diff --git a/.github/.OwlBot.lock.yaml b/.github/.OwlBot.lock.yaml index c701359..3815c98 100644 --- a/.github/.OwlBot.lock.yaml +++ b/.github/.OwlBot.lock.yaml @@ -13,5 +13,4 @@ # limitations under the License. docker: image: gcr.io/cloud-devrel-public-resources/owlbot-python:latest - digest: sha256:c6c965a4bf40c19011b11f87dbc801a66d3a23fbc6704102be064ef31c51f1c3 -# created: 2022-08-09T15:58:56.463048506Z + digest: sha256:7a40313731a7cb1454eef6b33d3446ebb121836738dc3ab3d2d3ded5268c35b6 diff --git a/.github/sync-repo-settings.yaml b/.github/sync-repo-settings.yaml new file mode 100644 index 0000000..201ee10 --- /dev/null +++ b/.github/sync-repo-settings.yaml @@ -0,0 +1,35 @@ +# https://github.com/googleapis/repo-automation-bots/tree/main/packages/sync-repo-settings +# Rules for main branch protection +branchProtectionRules: +# Identifies the protection rule pattern. Name of the branch to be protected. +# Defaults to `main` +- pattern: main + requiresCodeOwnerReviews: true + requiresStrictStatusChecks: true + requiredStatusCheckContexts: + - 'cla/google' + - 'OwlBot Post Processor' + - 'docs' + - 'docfx' + - 'lint' + - 'unit (3.7)' + - 'unit (3.8)' + - 'unit (3.9)' + - 'unit (3.10)' + - 'cover' + - 'Samples - Lint' + - 'Samples - Python 3.7' + - 'Samples - Python 3.8' + - 'Samples - Python 3.9' + - 'Samples - Python 3.10' +permissionRules: + - team: actools-python + permission: admin + - team: actools + permission: admin + - team: yoshi-python + permission: push + - team: python-samples-owners + permission: push + - team: python-samples-reviewers + permission: push diff --git a/.kokoro/publish-docs.sh b/.kokoro/publish-docs.sh index 8acb14e..1c4d623 100755 --- a/.kokoro/publish-docs.sh +++ b/.kokoro/publish-docs.sh @@ -21,14 +21,12 @@ export PYTHONUNBUFFERED=1 export PATH="${HOME}/.local/bin:${PATH}" # Install nox -python3 -m pip install --user --upgrade --quiet nox +python3 -m pip install --require-hashes -r .kokoro/requirements.txt python3 -m nox --version # build docs nox -s docs -python3 -m pip install --user gcp-docuploader - # create metadata python3 -m docuploader create-metadata \ --name=$(jq --raw-output '.name // empty' .repo-metadata.json) \ diff --git a/.kokoro/release.sh b/.kokoro/release.sh index 6930af4..28df152 100755 --- a/.kokoro/release.sh +++ b/.kokoro/release.sh @@ -16,12 +16,9 @@ set -eo pipefail # Start the releasetool reporter -python3 -m pip install gcp-releasetool +python3 -m pip install --require-hashes -r github/python-iam/.kokoro/requirements.txt python3 -m releasetool publish-reporter-script > /tmp/publisher-script; source /tmp/publisher-script -# Ensure that we have the latest versions of Twine, Wheel, and Setuptools. -python3 -m pip install --upgrade twine wheel setuptools - # Disable buffering, so that the logs stream through. export PYTHONUNBUFFERED=1 diff --git a/.kokoro/requirements.in b/.kokoro/requirements.in new file mode 100644 index 0000000..7718391 --- /dev/null +++ b/.kokoro/requirements.in @@ -0,0 +1,8 @@ +gcp-docuploader +gcp-releasetool +importlib-metadata +typing-extensions +twine +wheel +setuptools +nox \ No newline at end of file diff --git a/.kokoro/requirements.txt b/.kokoro/requirements.txt new file mode 100644 index 0000000..d15994b --- /dev/null +++ b/.kokoro/requirements.txt @@ -0,0 +1,471 @@ +# +# This file is autogenerated by pip-compile with python 3.10 +# To update, run: +# +# pip-compile --allow-unsafe --generate-hashes requirements.in +# +argcomplete==2.0.0 \ + --hash=sha256:6372ad78c89d662035101418ae253668445b391755cfe94ea52f1b9d22425b20 \ + --hash=sha256:cffa11ea77999bb0dd27bb25ff6dc142a6796142f68d45b1a26b11f58724561e + # via nox +attrs==22.1.0 \ + --hash=sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6 \ + --hash=sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c + # via gcp-releasetool +bleach==5.0.1 \ + --hash=sha256:085f7f33c15bd408dd9b17a4ad77c577db66d76203e5984b1bd59baeee948b2a \ + --hash=sha256:0d03255c47eb9bd2f26aa9bb7f2107732e7e8fe195ca2f64709fcf3b0a4a085c + # via readme-renderer +cachetools==5.2.0 \ + --hash=sha256:6a94c6402995a99c3970cc7e4884bb60b4a8639938157eeed436098bf9831757 \ + --hash=sha256:f9f17d2aec496a9aa6b76f53e3b614c965223c061982d434d160f930c698a9db + # via google-auth +certifi==2022.6.15 \ + --hash=sha256:84c85a9078b11105f04f3036a9482ae10e4621616db313fe045dd24743a0820d \ + --hash=sha256:fe86415d55e84719d75f8b69414f6438ac3547d2078ab91b67e779ef69378412 + # via requests +cffi==1.15.1 \ + --hash=sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5 \ + --hash=sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef \ + --hash=sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104 \ + --hash=sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426 \ + --hash=sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405 \ + --hash=sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375 \ + --hash=sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a \ + --hash=sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e \ + --hash=sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc \ + --hash=sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf \ + --hash=sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185 \ + --hash=sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497 \ + --hash=sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3 \ + --hash=sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35 \ + --hash=sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c \ + --hash=sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83 \ + --hash=sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21 \ + --hash=sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca \ + --hash=sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984 \ + --hash=sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac \ + --hash=sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd \ + --hash=sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee \ + --hash=sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a \ + --hash=sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2 \ + --hash=sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192 \ + --hash=sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7 \ + --hash=sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585 \ + --hash=sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f \ + --hash=sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e \ + --hash=sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27 \ + --hash=sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b \ + --hash=sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e \ + --hash=sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e \ + --hash=sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d \ + --hash=sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c \ + --hash=sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415 \ + --hash=sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82 \ + --hash=sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02 \ + --hash=sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314 \ + --hash=sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325 \ + --hash=sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c \ + --hash=sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3 \ + --hash=sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914 \ + --hash=sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045 \ + --hash=sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d \ + --hash=sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9 \ + --hash=sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5 \ + --hash=sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2 \ + --hash=sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c \ + --hash=sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3 \ + --hash=sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2 \ + --hash=sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8 \ + --hash=sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d \ + --hash=sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d \ + --hash=sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9 \ + --hash=sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162 \ + --hash=sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76 \ + --hash=sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4 \ + --hash=sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e \ + --hash=sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9 \ + --hash=sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6 \ + --hash=sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b \ + --hash=sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01 \ + --hash=sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0 + # via cryptography +charset-normalizer==2.1.1 \ + --hash=sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845 \ + --hash=sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f + # via requests +click==8.0.4 \ + --hash=sha256:6a7a62563bbfabfda3a38f3023a1db4a35978c0abd76f6c9605ecd6554d6d9b1 \ + --hash=sha256:8458d7b1287c5fb128c90e23381cf99dcde74beaf6c7ff6384ce84d6fe090adb + # via + # gcp-docuploader + # gcp-releasetool +colorlog==6.7.0 \ + --hash=sha256:0d33ca236784a1ba3ff9c532d4964126d8a2c44f1f0cb1d2b0728196f512f662 \ + --hash=sha256:bd94bd21c1e13fac7bd3153f4bc3a7dc0eb0974b8bc2fdf1a989e474f6e582e5 + # via + # gcp-docuploader + # nox +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 + # via + # gcp-releasetool + # secretstorage +distlib==0.3.6 \ + --hash=sha256:14bad2d9b04d3a36127ac97f30b12a19268f211063d8f8ee4f47108896e11b46 \ + --hash=sha256:f35c4b692542ca110de7ef0bea44d73981caeb34ca0b9b6b2e6d7790dda8f80e + # via virtualenv +docutils==0.19 \ + --hash=sha256:33995a6753c30b7f577febfc2c50411fec6aac7f7ffeb7c4cfe5991072dcf9e6 \ + --hash=sha256:5e1de4d849fee02c63b040a4a3fd567f4ab104defd8a5511fbbc24a8a017efbc + # via readme-renderer +filelock==3.8.0 \ + --hash=sha256:55447caa666f2198c5b6b13a26d2084d26fa5b115c00d065664b2124680c4edc \ + --hash=sha256:617eb4e5eedc82fc5f47b6d61e4d11cb837c56cb4544e39081099fa17ad109d4 + # via virtualenv +gcp-docuploader==0.6.3 \ + --hash=sha256:ba8c9d76b3bbac54b0311c503a373b00edc2dc02d6d54ea9507045adb8e870f7 \ + --hash=sha256:c0f5aaa82ce1854a386197e4e359b120ad6d4e57ae2c812fce42219a3288026b + # via -r requirements.in +gcp-releasetool==1.8.7 \ + --hash=sha256:3d2a67c9db39322194afb3b427e9cb0476ce8f2a04033695f0aeb63979fc2b37 \ + --hash=sha256:5e4d28f66e90780d77f3ecf1e9155852b0c3b13cbccb08ab07e66b2357c8da8d + # via -r requirements.in +google-api-core==2.8.2 \ + --hash=sha256:06f7244c640322b508b125903bb5701bebabce8832f85aba9335ec00b3d02edc \ + --hash=sha256:93c6a91ccac79079ac6bbf8b74ee75db970cc899278b97d53bc012f35908cf50 + # via + # google-cloud-core + # google-cloud-storage +google-auth==2.11.0 \ + --hash=sha256:be62acaae38d0049c21ca90f27a23847245c9f161ff54ede13af2cb6afecbac9 \ + --hash=sha256:ed65ecf9f681832298e29328e1ef0a3676e3732b2e56f41532d45f70a22de0fb + # via + # gcp-releasetool + # google-api-core + # google-cloud-core + # google-cloud-storage +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 + # 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 + # via google-resumable-media +google-resumable-media==2.3.3 \ + --hash=sha256:27c52620bd364d1c8116eaac4ea2afcbfb81ae9139fb3199652fcac1724bfb6c \ + --hash=sha256:5b52774ea7a829a8cdaa8bd2d4c3d4bc660c91b30857ab2668d0eb830f4ea8c5 + # via google-cloud-storage +googleapis-common-protos==1.56.4 \ + --hash=sha256:8eb2cbc91b69feaf23e32452a7ae60e791e09967d81d4fcc7fc388182d1bd394 \ + --hash=sha256:c25873c47279387cfdcbdafa36149887901d36202cb645a0e4f29686bf6e4417 + # via google-api-core +idna==3.3 \ + --hash=sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff \ + --hash=sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d + # via requests +importlib-metadata==4.12.0 \ + --hash=sha256:637245b8bab2b6502fcbc752cc4b7a6f6243bb02b31c5c26156ad103d3d45670 \ + --hash=sha256:7401a975809ea1fdc658c3aa4f78cc2195a0e019c5cbc4c06122884e9ae80c23 + # via + # -r requirements.in + # twine +jaraco-classes==3.2.2 \ + --hash=sha256:6745f113b0b588239ceb49532aa09c3ebb947433ce311ef2f8e3ad64ebb74594 \ + --hash=sha256:e6ef6fd3fcf4579a7a019d87d1e56a883f4e4c35cfe925f86731abc58804e647 + # via keyring +jeepney==0.8.0 \ + --hash=sha256:5efe48d255973902f6badc3ce55e2aa6c5c3b3bc642059ef3a91247bcfcc5806 \ + --hash=sha256:c0a454ad016ca575060802ee4d590dd912e35c122fa04e70306de3d076cce755 + # via + # keyring + # secretstorage +jinja2==3.1.2 \ + --hash=sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852 \ + --hash=sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61 + # via gcp-releasetool +keyring==23.9.0 \ + --hash=sha256:4c32a31174faaee48f43a7e2c7e9c3216ec5e95acf22a2bebfb4a1d05056ee44 \ + --hash=sha256:98f060ec95ada2ab910c195a2d4317be6ef87936a766b239c46aa3c7aac4f0db + # via + # gcp-releasetool + # twine +markupsafe==2.1.1 \ + --hash=sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003 \ + --hash=sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88 \ + --hash=sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5 \ + --hash=sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7 \ + --hash=sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a \ + --hash=sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603 \ + --hash=sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1 \ + --hash=sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135 \ + --hash=sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247 \ + --hash=sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6 \ + --hash=sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601 \ + --hash=sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77 \ + --hash=sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02 \ + --hash=sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e \ + --hash=sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63 \ + --hash=sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f \ + --hash=sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980 \ + --hash=sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b \ + --hash=sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812 \ + --hash=sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff \ + --hash=sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96 \ + --hash=sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1 \ + --hash=sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925 \ + --hash=sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a \ + --hash=sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6 \ + --hash=sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e \ + --hash=sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f \ + --hash=sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4 \ + --hash=sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f \ + --hash=sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3 \ + --hash=sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c \ + --hash=sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a \ + --hash=sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417 \ + --hash=sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a \ + --hash=sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a \ + --hash=sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37 \ + --hash=sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452 \ + --hash=sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933 \ + --hash=sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a \ + --hash=sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7 + # via jinja2 +more-itertools==8.14.0 \ + --hash=sha256:1bc4f91ee5b1b31ac7ceacc17c09befe6a40a503907baf9c839c229b5095cfd2 \ + --hash=sha256:c09443cd3d5438b8dafccd867a6bc1cb0894389e90cb53d227456b0b0bccb750 + # via jaraco-classes +nox==2022.8.7 \ + --hash=sha256:1b894940551dc5c389f9271d197ca5d655d40bdc6ccf93ed6880e4042760a34b \ + --hash=sha256:96cca88779e08282a699d672258ec01eb7c792d35bbbf538c723172bce23212c + # via -r requirements.in +packaging==21.3 \ + --hash=sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb \ + --hash=sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522 + # via + # gcp-releasetool + # nox +pkginfo==1.8.3 \ + --hash=sha256:848865108ec99d4901b2f7e84058b6e7660aae8ae10164e015a6dcf5b242a594 \ + --hash=sha256:a84da4318dd86f870a9447a8c98340aa06216bfc6f2b7bdc4b8766984ae1867c + # via twine +platformdirs==2.5.2 \ + --hash=sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788 \ + --hash=sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19 + # 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 + # via + # gcp-docuploader + # gcp-releasetool + # google-api-core +py==1.11.0 \ + --hash=sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719 \ + --hash=sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378 + # via nox +pyasn1==0.4.8 \ + --hash=sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d \ + --hash=sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba + # via + # pyasn1-modules + # rsa +pyasn1-modules==0.2.8 \ + --hash=sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e \ + --hash=sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74 + # via google-auth +pycparser==2.21 \ + --hash=sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9 \ + --hash=sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206 + # via cffi +pygments==2.13.0 \ + --hash=sha256:56a8508ae95f98e2b9bdf93a6be5ae3f7d8af858b43e02c5a2ff083726be40c1 \ + --hash=sha256:f643f331ab57ba3c9d89212ee4a2dabc6e94f117cf4eefde99a0574720d14c42 + # via + # readme-renderer + # rich +pyjwt==2.4.0 \ + --hash=sha256:72d1d253f32dbd4f5c88eaf1fdc62f3a19f676ccbadb9dbc5d07e951b2b26daf \ + --hash=sha256:d42908208c699b3b973cbeb01a969ba6a96c821eefb1c5bfe4c390c01d67abba + # via gcp-releasetool +pyparsing==3.0.9 \ + --hash=sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb \ + --hash=sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc + # via packaging +pyperclip==1.8.2 \ + --hash=sha256:105254a8b04934f0bc84e9c24eb360a591aaf6535c9def5f29d92af107a9bf57 + # via gcp-releasetool +python-dateutil==2.8.2 \ + --hash=sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86 \ + --hash=sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9 + # via gcp-releasetool +readme-renderer==37.0 \ + --hash=sha256:07b7ea234e03e58f77cc222e206e6abb8f4c0435becce5104794ee591f9301c5 \ + --hash=sha256:9fa416704703e509eeb900696751c908ddeb2011319d93700d8f18baff887a69 + # via twine +requests==2.28.1 \ + --hash=sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983 \ + --hash=sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349 + # via + # gcp-releasetool + # google-api-core + # google-cloud-storage + # requests-toolbelt + # twine +requests-toolbelt==0.9.1 \ + --hash=sha256:380606e1d10dc85c3bd47bf5a6095f815ec007be7a8b69c878507068df059e6f \ + --hash=sha256:968089d4584ad4ad7c171454f0a5c6dac23971e9472521ea3b6d49d610aa6fc0 + # via twine +rfc3986==2.0.0 \ + --hash=sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd \ + --hash=sha256:97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c + # via twine +rich==12.5.1 \ + --hash=sha256:2eb4e6894cde1e017976d2975ac210ef515d7548bc595ba20e195fb9628acdeb \ + --hash=sha256:63a5c5ce3673d3d5fbbf23cd87e11ab84b6b451436f1b7f19ec54b6bc36ed7ca + # via twine +rsa==4.9 \ + --hash=sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7 \ + --hash=sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21 + # via google-auth +secretstorage==3.3.3 \ + --hash=sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77 \ + --hash=sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99 + # via keyring +six==1.16.0 \ + --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ + --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 + # via + # bleach + # gcp-docuploader + # google-auth + # python-dateutil +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 + # via -r requirements.in +urllib3==1.26.12 \ + --hash=sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e \ + --hash=sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997 + # via + # requests + # twine +virtualenv==20.16.4 \ + --hash=sha256:014f766e4134d0008dcaa1f95bafa0fb0f575795d07cae50b1bee514185d6782 \ + --hash=sha256:035ed57acce4ac35c82c9d8802202b0e71adac011a511ff650cbcf9635006a22 + # via nox +webencodings==0.5.1 \ + --hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \ + --hash=sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923 + # via bleach +wheel==0.37.1 \ + --hash=sha256:4bdcd7d840138086126cd09254dc6195fb4fc6f01c050a1d7236f2630db1d22a \ + --hash=sha256:e9a504e793efbca1b8e0e9cb979a249cf4a0a7b5b8c9e8b65a5e39d49529c1c4 + # via -r requirements.in +zipp==3.8.1 \ + --hash=sha256:05b45f1ee8f807d0cc928485ca40a07cb491cf092ff587c0df9cb1fd154848d2 \ + --hash=sha256:47c40d7fe183a6f21403a199b3e4192cca5774656965b0a4988ad2f8feb5f009 + # 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 + # via -r requirements.in diff --git a/CHANGELOG.md b/CHANGELOG.md index 97428f8..e7539db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,19 @@ [1]: https://pypi.org/project/google-cloud-iam/#history +## [2.9.0](https://github.com/googleapis/python-iam/compare/v2.8.2...v2.9.0) (2022-10-24) + + +### Features + +* Add client for IAM Deny v2 API ([#230](https://github.com/googleapis/python-iam/issues/230)) ([07a2025](https://github.com/googleapis/python-iam/commit/07a20255498ec1ccb6cff501936546cc4814c969)) +* **v2beta:** Update the public IAM Deny v2beta API ([#226](https://github.com/googleapis/python-iam/issues/226)) ([bbe8e3d](https://github.com/googleapis/python-iam/commit/bbe8e3d3e1be719d4d617e3e7536d6a331f85f66)) + + +### Bug Fixes + +* **v2beta:** remove google.api.resource_reference annotations ([bbe8e3d](https://github.com/googleapis/python-iam/commit/bbe8e3d3e1be719d4d617e3e7536d6a331f85f66)) + ## [2.8.2](https://github.com/googleapis/python-iam/compare/v2.8.1...v2.8.2) (2022-08-11) diff --git a/docs/iam_v2/policies.rst b/docs/iam_v2/policies.rst new file mode 100644 index 0000000..4716ad1 --- /dev/null +++ b/docs/iam_v2/policies.rst @@ -0,0 +1,10 @@ +Policies +-------------------------- + +.. automodule:: google.cloud.iam_v2.services.policies + :members: + :inherited-members: + +.. automodule:: google.cloud.iam_v2.services.policies.pagers + :members: + :inherited-members: diff --git a/docs/iam_v2/services.rst b/docs/iam_v2/services.rst new file mode 100644 index 0000000..f70f98f --- /dev/null +++ b/docs/iam_v2/services.rst @@ -0,0 +1,6 @@ +Services for Google Cloud Iam v2 API +==================================== +.. toctree:: + :maxdepth: 2 + + policies diff --git a/docs/iam_v2/types.rst b/docs/iam_v2/types.rst new file mode 100644 index 0000000..00a7f65 --- /dev/null +++ b/docs/iam_v2/types.rst @@ -0,0 +1,7 @@ +Types for Google Cloud Iam v2 API +================================= + +.. automodule:: google.cloud.iam_v2.types + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/index.rst b/docs/index.rst index e718836..6a06598 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -2,9 +2,14 @@ .. include:: multiprocessing.rst -This package includes clients for multiple versions of Cloud Identity and Access Management. -By default, you will get version ``iam_credentials_v1``. +API Reference +------------- +.. toctree:: + :maxdepth: 2 + + iam_v2/services + iam_v2/types API Reference ------------- @@ -22,7 +27,6 @@ API Reference iam_v2beta/services iam_v2beta/types - Migration Guide --------------- diff --git a/google/cloud/iam_credentials_v1/services/iam_credentials/async_client.py b/google/cloud/iam_credentials_v1/services/iam_credentials/async_client.py index afcc9f8..e369c2a 100644 --- a/google/cloud/iam_credentials_v1/services/iam_credentials/async_client.py +++ b/google/cloud/iam_credentials_v1/services/iam_credentials/async_client.py @@ -234,6 +234,13 @@ async def generate_access_token( .. 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 iam_credentials_v1 async def sample_generate_access_token(): @@ -243,7 +250,7 @@ async def sample_generate_access_token(): # Initialize request argument(s) request = iam_credentials_v1.GenerateAccessTokenRequest( name="name_value", - scope=['scope_value_1', 'scope_value_2'], + scope=['scope_value1', 'scope_value2'], ) # Make the request @@ -391,6 +398,13 @@ async def generate_id_token( .. 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 iam_credentials_v1 async def sample_generate_id_token(): @@ -541,6 +555,13 @@ async def sign_blob( .. 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 iam_credentials_v1 async def sample_sign_blob(): @@ -678,6 +699,13 @@ async def sign_jwt( .. 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 iam_credentials_v1 async def sample_sign_jwt(): diff --git a/google/cloud/iam_credentials_v1/services/iam_credentials/client.py b/google/cloud/iam_credentials_v1/services/iam_credentials/client.py index 086a9a9..ecb432d 100644 --- a/google/cloud/iam_credentials_v1/services/iam_credentials/client.py +++ b/google/cloud/iam_credentials_v1/services/iam_credentials/client.py @@ -455,6 +455,13 @@ def generate_access_token( .. 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 iam_credentials_v1 def sample_generate_access_token(): @@ -464,7 +471,7 @@ def sample_generate_access_token(): # Initialize request argument(s) request = iam_credentials_v1.GenerateAccessTokenRequest( name="name_value", - scope=['scope_value_1', 'scope_value_2'], + scope=['scope_value1', 'scope_value2'], ) # Make the request @@ -602,6 +609,13 @@ def generate_id_token( .. 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 iam_credentials_v1 def sample_generate_id_token(): @@ -742,6 +756,13 @@ def sign_blob( .. 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 iam_credentials_v1 def sample_sign_blob(): @@ -869,6 +890,13 @@ def sign_jwt( .. 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 iam_credentials_v1 def sample_sign_jwt(): diff --git a/google/cloud/iam_v2/__init__.py b/google/cloud/iam_v2/__init__.py new file mode 100644 index 0000000..cc79688 --- /dev/null +++ b/google/cloud/iam_v2/__init__.py @@ -0,0 +1,44 @@ +# -*- 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 .services.policies import PoliciesAsyncClient, PoliciesClient +from .types.deny import DenyRule +from .types.policy import ( + CreatePolicyRequest, + DeletePolicyRequest, + GetPolicyRequest, + ListPoliciesRequest, + ListPoliciesResponse, + Policy, + PolicyOperationMetadata, + PolicyRule, + UpdatePolicyRequest, +) + +__all__ = ( + "PoliciesAsyncClient", + "CreatePolicyRequest", + "DeletePolicyRequest", + "DenyRule", + "GetPolicyRequest", + "ListPoliciesRequest", + "ListPoliciesResponse", + "PoliciesClient", + "Policy", + "PolicyOperationMetadata", + "PolicyRule", + "UpdatePolicyRequest", +) diff --git a/google/cloud/iam_v2/gapic_metadata.json b/google/cloud/iam_v2/gapic_metadata.json new file mode 100644 index 0000000..9179600 --- /dev/null +++ b/google/cloud/iam_v2/gapic_metadata.json @@ -0,0 +1,73 @@ + { + "comment": "This file maps proto services/RPCs to the corresponding library clients/methods", + "language": "python", + "libraryPackage": "google.cloud.iam_v2", + "protoPackage": "google.iam.v2", + "schema": "1.0", + "services": { + "Policies": { + "clients": { + "grpc": { + "libraryClient": "PoliciesClient", + "rpcs": { + "CreatePolicy": { + "methods": [ + "create_policy" + ] + }, + "DeletePolicy": { + "methods": [ + "delete_policy" + ] + }, + "GetPolicy": { + "methods": [ + "get_policy" + ] + }, + "ListPolicies": { + "methods": [ + "list_policies" + ] + }, + "UpdatePolicy": { + "methods": [ + "update_policy" + ] + } + } + }, + "grpc-async": { + "libraryClient": "PoliciesAsyncClient", + "rpcs": { + "CreatePolicy": { + "methods": [ + "create_policy" + ] + }, + "DeletePolicy": { + "methods": [ + "delete_policy" + ] + }, + "GetPolicy": { + "methods": [ + "get_policy" + ] + }, + "ListPolicies": { + "methods": [ + "list_policies" + ] + }, + "UpdatePolicy": { + "methods": [ + "update_policy" + ] + } + } + } + } + } + } +} diff --git a/google/cloud/iam_v2/py.typed b/google/cloud/iam_v2/py.typed new file mode 100644 index 0000000..a8a7868 --- /dev/null +++ b/google/cloud/iam_v2/py.typed @@ -0,0 +1,2 @@ +# Marker file for PEP 561. +# The google-cloud-iam package uses inline types. diff --git a/google/cloud/iam_v2/services/__init__.py b/google/cloud/iam_v2/services/__init__.py new file mode 100644 index 0000000..e8e1c38 --- /dev/null +++ b/google/cloud/iam_v2/services/__init__.py @@ -0,0 +1,15 @@ +# -*- 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. +# diff --git a/google/cloud/iam_v2/services/policies/__init__.py b/google/cloud/iam_v2/services/policies/__init__.py new file mode 100644 index 0000000..15a6ab9 --- /dev/null +++ b/google/cloud/iam_v2/services/policies/__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 PoliciesAsyncClient +from .client import PoliciesClient + +__all__ = ( + "PoliciesClient", + "PoliciesAsyncClient", +) diff --git a/google/cloud/iam_v2/services/policies/async_client.py b/google/cloud/iam_v2/services/policies/async_client.py new file mode 100644 index 0000000..d852af6 --- /dev/null +++ b/google/cloud/iam_v2/services/policies/async_client.py @@ -0,0 +1,939 @@ +# -*- 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, 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 +import pkg_resources + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + +from google.api_core import operation # type: ignore +from google.api_core import operation_async # type: ignore +from google.longrunning import operations_pb2 +from google.protobuf import timestamp_pb2 # type: ignore + +from google.cloud.iam_v2.services.policies import pagers +from google.cloud.iam_v2.types import policy +from google.cloud.iam_v2.types import policy as gi_policy + +from .client import PoliciesClient +from .transports.base import DEFAULT_CLIENT_INFO, PoliciesTransport +from .transports.grpc_asyncio import PoliciesGrpcAsyncIOTransport + + +class PoliciesAsyncClient: + """An interface for managing Identity and Access Management + (IAM) policies. + """ + + _client: PoliciesClient + + DEFAULT_ENDPOINT = PoliciesClient.DEFAULT_ENDPOINT + DEFAULT_MTLS_ENDPOINT = PoliciesClient.DEFAULT_MTLS_ENDPOINT + + common_billing_account_path = staticmethod( + PoliciesClient.common_billing_account_path + ) + parse_common_billing_account_path = staticmethod( + PoliciesClient.parse_common_billing_account_path + ) + common_folder_path = staticmethod(PoliciesClient.common_folder_path) + parse_common_folder_path = staticmethod(PoliciesClient.parse_common_folder_path) + common_organization_path = staticmethod(PoliciesClient.common_organization_path) + parse_common_organization_path = staticmethod( + PoliciesClient.parse_common_organization_path + ) + common_project_path = staticmethod(PoliciesClient.common_project_path) + parse_common_project_path = staticmethod(PoliciesClient.parse_common_project_path) + common_location_path = staticmethod(PoliciesClient.common_location_path) + parse_common_location_path = staticmethod(PoliciesClient.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: + PoliciesAsyncClient: The constructed client. + """ + return PoliciesClient.from_service_account_info.__func__(PoliciesAsyncClient, 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: + PoliciesAsyncClient: The constructed client. + """ + return PoliciesClient.from_service_account_file.__func__(PoliciesAsyncClient, 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 PoliciesClient.get_mtls_endpoint_and_cert_source(client_options) # type: ignore + + @property + def transport(self) -> PoliciesTransport: + """Returns the transport used by the client instance. + + Returns: + PoliciesTransport: The transport used by the client instance. + """ + return self._client.transport + + get_transport_class = functools.partial( + type(PoliciesClient).get_transport_class, type(PoliciesClient) + ) + + def __init__( + self, + *, + credentials: ga_credentials.Credentials = None, + transport: Union[str, PoliciesTransport] = "grpc_asyncio", + client_options: ClientOptions = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + ) -> None: + """Instantiates the policies 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, ~.PoliciesTransport]): 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 = PoliciesClient( + credentials=credentials, + transport=transport, + client_options=client_options, + client_info=client_info, + ) + + async def list_policies( + self, + request: Union[policy.ListPoliciesRequest, dict] = None, + *, + parent: str = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListPoliciesAsyncPager: + r"""Retrieves the policies of the specified kind that are + attached to a resource. + + The response lists only policy metadata. In particular, + policy rules are omitted. + + .. 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 iam_v2 + + async def sample_list_policies(): + # Create a client + client = iam_v2.PoliciesAsyncClient() + + # Initialize request argument(s) + request = iam_v2.ListPoliciesRequest( + parent="parent_value", + ) + + # Make the request + page_result = client.list_policies(request=request) + + # Handle the response + async for response in page_result: + print(response) + + Args: + request (Union[google.cloud.iam_v2.types.ListPoliciesRequest, dict]): + The request object. Request message for `ListPolicies`. + parent (:class:`str`): + Required. The resource that the policy is attached to, + along with the kind of policy to list. Format: + ``policies/{attachment_point}/denypolicies`` + + The attachment point is identified by its URL-encoded + full resource name, which means that the forward-slash + character, ``/``, must be written as ``%2F``. For + example, + ``policies/cloudresourcemanager.googleapis.com%2Fprojects%2Fmy-project/denypolicies``. + + For organizations and folders, use the numeric ID in the + full resource name. For projects, you can use the + alphanumeric or the numeric ID. + + 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.iam_v2.services.policies.pagers.ListPoliciesAsyncPager: + Response message for ListPolicies. + + 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 = policy.ListPoliciesRequest(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_policies, + default_retry=retries.Retry( + initial=1.0, + maximum=10.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.ServiceUnavailable, + ), + deadline=60.0, + ), + default_timeout=60.0, + 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.ListPoliciesAsyncPager( + method=rpc, + request=request, + response=response, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def get_policy( + self, + request: Union[policy.GetPolicyRequest, dict] = None, + *, + name: str = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> policy.Policy: + r"""Gets a 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 iam_v2 + + async def sample_get_policy(): + # Create a client + client = iam_v2.PoliciesAsyncClient() + + # Initialize request argument(s) + request = iam_v2.GetPolicyRequest( + name="name_value", + ) + + # Make the request + response = await client.get_policy(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.cloud.iam_v2.types.GetPolicyRequest, dict]): + The request object. Request message for `GetPolicy`. + name (:class:`str`): + Required. The resource name of the policy to retrieve. + Format: + ``policies/{attachment_point}/denypolicies/{policy_id}`` + + Use the URL-encoded full resource name, which means that + the forward-slash character, ``/``, must be written as + ``%2F``. For example, + ``policies/cloudresourcemanager.googleapis.com%2Fprojects%2Fmy-project/denypolicies/my-policy``. + + For organizations and folders, use the numeric ID in the + full resource name. For projects, you can use the + alphanumeric or the numeric ID. + + 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.iam_v2.types.Policy: + Data for an IAM policy. + """ + # 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 = policy.GetPolicyRequest(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_policy, + default_retry=retries.Retry( + initial=1.0, + maximum=10.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.ServiceUnavailable, + ), + deadline=60.0, + ), + default_timeout=60.0, + 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 create_policy( + self, + request: Union[gi_policy.CreatePolicyRequest, dict] = None, + *, + parent: str = None, + policy: gi_policy.Policy = None, + policy_id: str = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operation_async.AsyncOperation: + r"""Creates a 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 iam_v2 + + async def sample_create_policy(): + # Create a client + client = iam_v2.PoliciesAsyncClient() + + # Initialize request argument(s) + request = iam_v2.CreatePolicyRequest( + parent="parent_value", + ) + + # Make the request + operation = client.create_policy(request=request) + + print("Waiting for operation to complete...") + + response = await operation.result() + + # Handle the response + print(response) + + Args: + request (Union[google.cloud.iam_v2.types.CreatePolicyRequest, dict]): + The request object. Request message for `CreatePolicy`. + parent (:class:`str`): + Required. The resource that the policy is attached to, + along with the kind of policy to create. Format: + ``policies/{attachment_point}/denypolicies`` + + The attachment point is identified by its URL-encoded + full resource name, which means that the forward-slash + character, ``/``, must be written as ``%2F``. For + example, + ``policies/cloudresourcemanager.googleapis.com%2Fprojects%2Fmy-project/denypolicies``. + + For organizations and folders, use the numeric ID in the + full resource name. For projects, you can use the + alphanumeric or the numeric ID. + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + policy (:class:`google.cloud.iam_v2.types.Policy`): + Required. The policy to create. + This corresponds to the ``policy`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + policy_id (:class:`str`): + The ID to use for this policy, which will become the + final component of the policy's resource name. The ID + must contain 3 to 63 characters. It can contain + lowercase letters and numbers, as well as dashes (``-``) + and periods (``.``). The first character must be a + lowercase letter. + + This corresponds to the ``policy_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.iam_v2.types.Policy` Data for an + IAM policy. + + """ + # 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, policy, policy_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 = gi_policy.CreatePolicyRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if parent is not None: + request.parent = parent + if policy is not None: + request.policy = policy + if policy_id is not None: + request.policy_id = policy_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_policy, + default_retry=retries.Retry( + initial=1.0, + maximum=10.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.ServiceUnavailable, + ), + deadline=60.0, + ), + default_timeout=60.0, + 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, + gi_policy.Policy, + metadata_type=gi_policy.PolicyOperationMetadata, + ) + + # Done; return the response. + return response + + async def update_policy( + self, + request: Union[policy.UpdatePolicyRequest, dict] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operation_async.AsyncOperation: + r"""Updates the specified policy. + + You can update only the rules and the display name for the + policy. + + To update a policy, you should use a read-modify-write loop: + + 1. Use [GetPolicy][google.iam.v2.Policies.GetPolicy] to read the + current version of the policy. + 2. Modify the policy as needed. + 3. Use ``UpdatePolicy`` to write the updated policy. + + This pattern helps prevent conflicts between concurrent updates. + + .. 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 iam_v2 + + async def sample_update_policy(): + # Create a client + client = iam_v2.PoliciesAsyncClient() + + # Initialize request argument(s) + request = iam_v2.UpdatePolicyRequest( + ) + + # Make the request + operation = client.update_policy(request=request) + + print("Waiting for operation to complete...") + + response = await operation.result() + + # Handle the response + print(response) + + Args: + request (Union[google.cloud.iam_v2.types.UpdatePolicyRequest, dict]): + The request object. Request message for `UpdatePolicy`. + 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.iam_v2.types.Policy` Data for an + IAM policy. + + """ + # Create or coerce a protobuf request object. + request = policy.UpdatePolicyRequest(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.update_policy, + default_retry=retries.Retry( + initial=1.0, + maximum=10.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.ServiceUnavailable, + ), + deadline=60.0, + ), + default_timeout=60.0, + 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( + (("policy.name", request.policy.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, + policy.Policy, + metadata_type=policy.PolicyOperationMetadata, + ) + + # Done; return the response. + return response + + async def delete_policy( + self, + request: Union[policy.DeletePolicyRequest, dict] = None, + *, + name: str = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operation_async.AsyncOperation: + r"""Deletes a policy. This action is permanent. + + .. 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 iam_v2 + + async def sample_delete_policy(): + # Create a client + client = iam_v2.PoliciesAsyncClient() + + # Initialize request argument(s) + request = iam_v2.DeletePolicyRequest( + name="name_value", + ) + + # Make the request + operation = client.delete_policy(request=request) + + print("Waiting for operation to complete...") + + response = await operation.result() + + # Handle the response + print(response) + + Args: + request (Union[google.cloud.iam_v2.types.DeletePolicyRequest, dict]): + The request object. Request message for `DeletePolicy`. + name (:class:`str`): + Required. The resource name of the policy to delete. + Format: + ``policies/{attachment_point}/denypolicies/{policy_id}`` + + Use the URL-encoded full resource name, which means that + the forward-slash character, ``/``, must be written as + ``%2F``. For example, + ``policies/cloudresourcemanager.googleapis.com%2Fprojects%2Fmy-project/denypolicies/my-policy``. + + For organizations and folders, use the numeric ID in the + full resource name. For projects, you can use the + alphanumeric or the numeric ID. + + 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.iam_v2.types.Policy` Data for an + IAM policy. + + """ + # 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 = policy.DeletePolicyRequest(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_policy, + default_retry=retries.Retry( + initial=1.0, + maximum=10.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.ServiceUnavailable, + ), + deadline=60.0, + ), + default_timeout=60.0, + 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, + policy.Policy, + metadata_type=policy.PolicyOperationMetadata, + ) + + # Done; return the response. + return response + + async def get_operation( + self, + request: operations_pb2.GetOperationRequest = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + 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 __aenter__(self): + return self + + 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-iam", + ).version, + ) +except pkg_resources.DistributionNotFound: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() + + +__all__ = ("PoliciesAsyncClient",) diff --git a/google/cloud/iam_v2/services/policies/client.py b/google/cloud/iam_v2/services/policies/client.py new file mode 100644 index 0000000..d503855 --- /dev/null +++ b/google/cloud/iam_v2/services/policies/client.py @@ -0,0 +1,1113 @@ +# -*- 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, Optional, Sequence, Tuple, Type, Union + +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 +import pkg_resources + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + +from google.api_core import operation # type: ignore +from google.api_core import operation_async # type: ignore +from google.longrunning import operations_pb2 +from google.protobuf import timestamp_pb2 # type: ignore + +from google.cloud.iam_v2.services.policies import pagers +from google.cloud.iam_v2.types import policy +from google.cloud.iam_v2.types import policy as gi_policy + +from .transports.base import DEFAULT_CLIENT_INFO, PoliciesTransport +from .transports.grpc import PoliciesGrpcTransport +from .transports.grpc_asyncio import PoliciesGrpcAsyncIOTransport + + +class PoliciesClientMeta(type): + """Metaclass for the Policies 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[PoliciesTransport]] + _transport_registry["grpc"] = PoliciesGrpcTransport + _transport_registry["grpc_asyncio"] = PoliciesGrpcAsyncIOTransport + + def get_transport_class( + cls, + label: str = None, + ) -> Type[PoliciesTransport]: + """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 PoliciesClient(metaclass=PoliciesClientMeta): + """An interface for managing Identity and Access Management + (IAM) policies. + """ + + @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 = "iam.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: + PoliciesClient: 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: + PoliciesClient: 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) -> PoliciesTransport: + """Returns the transport used by the client instance. + + Returns: + PoliciesTransport: The transport used by the client + instance. + """ + return self._transport + + @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: Union[str, PoliciesTransport, None] = None, + client_options: Optional[client_options_lib.ClientOptions] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + ) -> None: + """Instantiates the policies 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, PoliciesTransport]): The + transport to use. If set to None, a transport is chosen + automatically. + client_options (google.api_core.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. + 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() + + 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, PoliciesTransport): + # transport is a PoliciesTransport 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 list_policies( + self, + request: Union[policy.ListPoliciesRequest, dict] = None, + *, + parent: str = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListPoliciesPager: + r"""Retrieves the policies of the specified kind that are + attached to a resource. + + The response lists only policy metadata. In particular, + policy rules are omitted. + + .. 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 iam_v2 + + def sample_list_policies(): + # Create a client + client = iam_v2.PoliciesClient() + + # Initialize request argument(s) + request = iam_v2.ListPoliciesRequest( + parent="parent_value", + ) + + # Make the request + page_result = client.list_policies(request=request) + + # Handle the response + for response in page_result: + print(response) + + Args: + request (Union[google.cloud.iam_v2.types.ListPoliciesRequest, dict]): + The request object. Request message for `ListPolicies`. + parent (str): + Required. The resource that the policy is attached to, + along with the kind of policy to list. Format: + ``policies/{attachment_point}/denypolicies`` + + The attachment point is identified by its URL-encoded + full resource name, which means that the forward-slash + character, ``/``, must be written as ``%2F``. For + example, + ``policies/cloudresourcemanager.googleapis.com%2Fprojects%2Fmy-project/denypolicies``. + + For organizations and folders, use the numeric ID in the + full resource name. For projects, you can use the + alphanumeric or the numeric ID. + + 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.iam_v2.services.policies.pagers.ListPoliciesPager: + Response message for ListPolicies. + + 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 policy.ListPoliciesRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, policy.ListPoliciesRequest): + request = policy.ListPoliciesRequest(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_policies] + + # 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.ListPoliciesPager( + method=rpc, + request=request, + response=response, + metadata=metadata, + ) + + # Done; return the response. + return response + + def get_policy( + self, + request: Union[policy.GetPolicyRequest, dict] = None, + *, + name: str = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> policy.Policy: + r"""Gets a 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 iam_v2 + + def sample_get_policy(): + # Create a client + client = iam_v2.PoliciesClient() + + # Initialize request argument(s) + request = iam_v2.GetPolicyRequest( + name="name_value", + ) + + # Make the request + response = client.get_policy(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.cloud.iam_v2.types.GetPolicyRequest, dict]): + The request object. Request message for `GetPolicy`. + name (str): + Required. The resource name of the policy to retrieve. + Format: + ``policies/{attachment_point}/denypolicies/{policy_id}`` + + Use the URL-encoded full resource name, which means that + the forward-slash character, ``/``, must be written as + ``%2F``. For example, + ``policies/cloudresourcemanager.googleapis.com%2Fprojects%2Fmy-project/denypolicies/my-policy``. + + For organizations and folders, use the numeric ID in the + full resource name. For projects, you can use the + alphanumeric or the numeric ID. + + 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.iam_v2.types.Policy: + Data for an IAM policy. + """ + # 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 policy.GetPolicyRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, policy.GetPolicyRequest): + request = policy.GetPolicyRequest(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_policy] + + # 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 create_policy( + self, + request: Union[gi_policy.CreatePolicyRequest, dict] = None, + *, + parent: str = None, + policy: gi_policy.Policy = None, + policy_id: str = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operation.Operation: + r"""Creates a 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 iam_v2 + + def sample_create_policy(): + # Create a client + client = iam_v2.PoliciesClient() + + # Initialize request argument(s) + request = iam_v2.CreatePolicyRequest( + parent="parent_value", + ) + + # Make the request + operation = client.create_policy(request=request) + + print("Waiting for operation to complete...") + + response = operation.result() + + # Handle the response + print(response) + + Args: + request (Union[google.cloud.iam_v2.types.CreatePolicyRequest, dict]): + The request object. Request message for `CreatePolicy`. + parent (str): + Required. The resource that the policy is attached to, + along with the kind of policy to create. Format: + ``policies/{attachment_point}/denypolicies`` + + The attachment point is identified by its URL-encoded + full resource name, which means that the forward-slash + character, ``/``, must be written as ``%2F``. For + example, + ``policies/cloudresourcemanager.googleapis.com%2Fprojects%2Fmy-project/denypolicies``. + + For organizations and folders, use the numeric ID in the + full resource name. For projects, you can use the + alphanumeric or the numeric ID. + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + policy (google.cloud.iam_v2.types.Policy): + Required. The policy to create. + This corresponds to the ``policy`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + policy_id (str): + The ID to use for this policy, which will become the + final component of the policy's resource name. The ID + must contain 3 to 63 characters. It can contain + lowercase letters and numbers, as well as dashes (``-``) + and periods (``.``). The first character must be a + lowercase letter. + + This corresponds to the ``policy_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.iam_v2.types.Policy` Data for an + IAM policy. + + """ + # 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, policy, policy_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 gi_policy.CreatePolicyRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, gi_policy.CreatePolicyRequest): + request = gi_policy.CreatePolicyRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if parent is not None: + request.parent = parent + if policy is not None: + request.policy = policy + if policy_id is not None: + request.policy_id = policy_id + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.create_policy] + + # 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, + gi_policy.Policy, + metadata_type=gi_policy.PolicyOperationMetadata, + ) + + # Done; return the response. + return response + + def update_policy( + self, + request: Union[policy.UpdatePolicyRequest, dict] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operation.Operation: + r"""Updates the specified policy. + + You can update only the rules and the display name for the + policy. + + To update a policy, you should use a read-modify-write loop: + + 1. Use [GetPolicy][google.iam.v2.Policies.GetPolicy] to read the + current version of the policy. + 2. Modify the policy as needed. + 3. Use ``UpdatePolicy`` to write the updated policy. + + This pattern helps prevent conflicts between concurrent updates. + + .. 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 iam_v2 + + def sample_update_policy(): + # Create a client + client = iam_v2.PoliciesClient() + + # Initialize request argument(s) + request = iam_v2.UpdatePolicyRequest( + ) + + # Make the request + operation = client.update_policy(request=request) + + print("Waiting for operation to complete...") + + response = operation.result() + + # Handle the response + print(response) + + Args: + request (Union[google.cloud.iam_v2.types.UpdatePolicyRequest, dict]): + The request object. Request message for `UpdatePolicy`. + 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.iam_v2.types.Policy` Data for an + IAM policy. + + """ + # Create or coerce a protobuf request object. + # Minor optimization to avoid making a copy if the user passes + # in a policy.UpdatePolicyRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, policy.UpdatePolicyRequest): + request = policy.UpdatePolicyRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.update_policy] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("policy.name", request.policy.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, + policy.Policy, + metadata_type=policy.PolicyOperationMetadata, + ) + + # Done; return the response. + return response + + def delete_policy( + self, + request: Union[policy.DeletePolicyRequest, dict] = None, + *, + name: str = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operation.Operation: + r"""Deletes a policy. This action is permanent. + + .. 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 iam_v2 + + def sample_delete_policy(): + # Create a client + client = iam_v2.PoliciesClient() + + # Initialize request argument(s) + request = iam_v2.DeletePolicyRequest( + name="name_value", + ) + + # Make the request + operation = client.delete_policy(request=request) + + print("Waiting for operation to complete...") + + response = operation.result() + + # Handle the response + print(response) + + Args: + request (Union[google.cloud.iam_v2.types.DeletePolicyRequest, dict]): + The request object. Request message for `DeletePolicy`. + name (str): + Required. The resource name of the policy to delete. + Format: + ``policies/{attachment_point}/denypolicies/{policy_id}`` + + Use the URL-encoded full resource name, which means that + the forward-slash character, ``/``, must be written as + ``%2F``. For example, + ``policies/cloudresourcemanager.googleapis.com%2Fprojects%2Fmy-project/denypolicies/my-policy``. + + For organizations and folders, use the numeric ID in the + full resource name. For projects, you can use the + alphanumeric or the numeric ID. + + 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.iam_v2.types.Policy` Data for an + IAM policy. + + """ + # 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 policy.DeletePolicyRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, policy.DeletePolicyRequest): + request = policy.DeletePolicyRequest(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_policy] + + # 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, + policy.Policy, + metadata_type=policy.PolicyOperationMetadata, + ) + + # 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 get_operation( + self, + request: operations_pb2.GetOperationRequest = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + 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 + + +try: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=pkg_resources.get_distribution( + "google-cloud-iam", + ).version, + ) +except pkg_resources.DistributionNotFound: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() + + +__all__ = ("PoliciesClient",) diff --git a/google/cloud/iam_v2/services/policies/pagers.py b/google/cloud/iam_v2/services/policies/pagers.py new file mode 100644 index 0000000..2129b65 --- /dev/null +++ b/google/cloud/iam_v2/services/policies/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.iam_v2.types import policy + + +class ListPoliciesPager: + """A pager for iterating through ``list_policies`` requests. + + This class thinly wraps an initial + :class:`google.cloud.iam_v2.types.ListPoliciesResponse` object, and + provides an ``__iter__`` method to iterate through its + ``policies`` field. + + If there are more pages, the ``__iter__`` method will make additional + ``ListPolicies`` requests and continue to iterate + through the ``policies`` field on the + corresponding responses. + + All the usual :class:`google.cloud.iam_v2.types.ListPoliciesResponse` + 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[..., policy.ListPoliciesResponse], + request: policy.ListPoliciesRequest, + response: policy.ListPoliciesResponse, + *, + 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.iam_v2.types.ListPoliciesRequest): + The initial request object. + response (google.cloud.iam_v2.types.ListPoliciesResponse): + 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 = policy.ListPoliciesRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + def pages(self) -> Iterator[policy.ListPoliciesResponse]: + 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[policy.Policy]: + for page in self.pages: + yield from page.policies + + def __repr__(self) -> str: + return "{0}<{1!r}>".format(self.__class__.__name__, self._response) + + +class ListPoliciesAsyncPager: + """A pager for iterating through ``list_policies`` requests. + + This class thinly wraps an initial + :class:`google.cloud.iam_v2.types.ListPoliciesResponse` object, and + provides an ``__aiter__`` method to iterate through its + ``policies`` field. + + If there are more pages, the ``__aiter__`` method will make additional + ``ListPolicies`` requests and continue to iterate + through the ``policies`` field on the + corresponding responses. + + All the usual :class:`google.cloud.iam_v2.types.ListPoliciesResponse` + 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[policy.ListPoliciesResponse]], + request: policy.ListPoliciesRequest, + response: policy.ListPoliciesResponse, + *, + 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.iam_v2.types.ListPoliciesRequest): + The initial request object. + response (google.cloud.iam_v2.types.ListPoliciesResponse): + 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 = policy.ListPoliciesRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + async def pages(self) -> AsyncIterator[policy.ListPoliciesResponse]: + 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[policy.Policy]: + async def async_generator(): + async for page in self.pages: + for response in page.policies: + yield response + + return async_generator() + + def __repr__(self) -> str: + return "{0}<{1!r}>".format(self.__class__.__name__, self._response) diff --git a/google/cloud/iam_v2/services/policies/transports/__init__.py b/google/cloud/iam_v2/services/policies/transports/__init__.py new file mode 100644 index 0000000..1b3a90a --- /dev/null +++ b/google/cloud/iam_v2/services/policies/transports/__init__.py @@ -0,0 +1,32 @@ +# -*- 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 PoliciesTransport +from .grpc import PoliciesGrpcTransport +from .grpc_asyncio import PoliciesGrpcAsyncIOTransport + +# Compile a registry of transports. +_transport_registry = OrderedDict() # type: Dict[str, Type[PoliciesTransport]] +_transport_registry["grpc"] = PoliciesGrpcTransport +_transport_registry["grpc_asyncio"] = PoliciesGrpcAsyncIOTransport + +__all__ = ( + "PoliciesTransport", + "PoliciesGrpcTransport", + "PoliciesGrpcAsyncIOTransport", +) diff --git a/google/cloud/iam_v2/services/policies/transports/base.py b/google/cloud/iam_v2/services/policies/transports/base.py new file mode 100644 index 0000000..f90a697 --- /dev/null +++ b/google/cloud/iam_v2/services/policies/transports/base.py @@ -0,0 +1,276 @@ +# -*- 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.longrunning import operations_pb2 # type: ignore +from google.oauth2 import service_account # type: ignore +import pkg_resources + +from google.cloud.iam_v2.types import policy +from google.cloud.iam_v2.types import policy as gi_policy + +try: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=pkg_resources.get_distribution( + "google-cloud-iam", + ).version, + ) +except pkg_resources.DistributionNotFound: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() + + +class PoliciesTransport(abc.ABC): + """Abstract transport class for Policies.""" + + AUTH_SCOPES = ("https://www.googleapis.com/auth/cloud-platform",) + + DEFAULT_HOST: str = "iam.googleapis.com" + + def __init__( + self, + *, + host: str = DEFAULT_HOST, + credentials: 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.list_policies: gapic_v1.method.wrap_method( + self.list_policies, + default_retry=retries.Retry( + initial=1.0, + maximum=10.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.ServiceUnavailable, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=client_info, + ), + self.get_policy: gapic_v1.method.wrap_method( + self.get_policy, + default_retry=retries.Retry( + initial=1.0, + maximum=10.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.ServiceUnavailable, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=client_info, + ), + self.create_policy: gapic_v1.method.wrap_method( + self.create_policy, + default_retry=retries.Retry( + initial=1.0, + maximum=10.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.ServiceUnavailable, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=client_info, + ), + self.update_policy: gapic_v1.method.wrap_method( + self.update_policy, + default_retry=retries.Retry( + initial=1.0, + maximum=10.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.ServiceUnavailable, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=client_info, + ), + self.delete_policy: gapic_v1.method.wrap_method( + self.delete_policy, + default_retry=retries.Retry( + initial=1.0, + maximum=10.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.ServiceUnavailable, + ), + deadline=60.0, + ), + default_timeout=60.0, + 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 list_policies( + self, + ) -> Callable[ + [policy.ListPoliciesRequest], + Union[policy.ListPoliciesResponse, Awaitable[policy.ListPoliciesResponse]], + ]: + raise NotImplementedError() + + @property + def get_policy( + self, + ) -> Callable[ + [policy.GetPolicyRequest], Union[policy.Policy, Awaitable[policy.Policy]] + ]: + raise NotImplementedError() + + @property + def create_policy( + self, + ) -> Callable[ + [gi_policy.CreatePolicyRequest], + Union[operations_pb2.Operation, Awaitable[operations_pb2.Operation]], + ]: + raise NotImplementedError() + + @property + def update_policy( + self, + ) -> Callable[ + [policy.UpdatePolicyRequest], + Union[operations_pb2.Operation, Awaitable[operations_pb2.Operation]], + ]: + raise NotImplementedError() + + @property + def delete_policy( + self, + ) -> Callable[ + [policy.DeletePolicyRequest], + Union[operations_pb2.Operation, Awaitable[operations_pb2.Operation]], + ]: + raise NotImplementedError() + + @property + def get_operation( + self, + ) -> Callable[ + [operations_pb2.GetOperationRequest], + Union[operations_pb2.Operation, Awaitable[operations_pb2.Operation]], + ]: + raise NotImplementedError() + + @property + def kind(self) -> str: + raise NotImplementedError() + + +__all__ = ("PoliciesTransport",) diff --git a/google/cloud/iam_v2/services/policies/transports/grpc.py b/google/cloud/iam_v2/services/policies/transports/grpc.py new file mode 100644 index 0000000..f09c345 --- /dev/null +++ b/google/cloud/iam_v2/services/policies/transports/grpc.py @@ -0,0 +1,418 @@ +# -*- 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.longrunning import operations_pb2 # type: ignore +import grpc # type: ignore + +from google.cloud.iam_v2.types import policy +from google.cloud.iam_v2.types import policy as gi_policy + +from .base import DEFAULT_CLIENT_INFO, PoliciesTransport + + +class PoliciesGrpcTransport(PoliciesTransport): + """gRPC backend transport for Policies. + + An interface for managing Identity and Access Management + (IAM) policies. + + 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 = "iam.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, + 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 = "iam.googleapis.com", + credentials: ga_credentials.Credentials = None, + credentials_file: 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 list_policies( + self, + ) -> Callable[[policy.ListPoliciesRequest], policy.ListPoliciesResponse]: + r"""Return a callable for the list policies method over gRPC. + + Retrieves the policies of the specified kind that are + attached to a resource. + + The response lists only policy metadata. In particular, + policy rules are omitted. + + Returns: + Callable[[~.ListPoliciesRequest], + ~.ListPoliciesResponse]: + 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_policies" not in self._stubs: + self._stubs["list_policies"] = self.grpc_channel.unary_unary( + "/google.iam.v2.Policies/ListPolicies", + request_serializer=policy.ListPoliciesRequest.serialize, + response_deserializer=policy.ListPoliciesResponse.deserialize, + ) + return self._stubs["list_policies"] + + @property + def get_policy(self) -> Callable[[policy.GetPolicyRequest], policy.Policy]: + r"""Return a callable for the get policy method over gRPC. + + Gets a policy. + + Returns: + Callable[[~.GetPolicyRequest], + ~.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_policy" not in self._stubs: + self._stubs["get_policy"] = self.grpc_channel.unary_unary( + "/google.iam.v2.Policies/GetPolicy", + request_serializer=policy.GetPolicyRequest.serialize, + response_deserializer=policy.Policy.deserialize, + ) + return self._stubs["get_policy"] + + @property + def create_policy( + self, + ) -> Callable[[gi_policy.CreatePolicyRequest], operations_pb2.Operation]: + r"""Return a callable for the create policy method over gRPC. + + Creates a policy. + + Returns: + Callable[[~.CreatePolicyRequest], + ~.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_policy" not in self._stubs: + self._stubs["create_policy"] = self.grpc_channel.unary_unary( + "/google.iam.v2.Policies/CreatePolicy", + request_serializer=gi_policy.CreatePolicyRequest.serialize, + response_deserializer=operations_pb2.Operation.FromString, + ) + return self._stubs["create_policy"] + + @property + def update_policy( + self, + ) -> Callable[[policy.UpdatePolicyRequest], operations_pb2.Operation]: + r"""Return a callable for the update policy method over gRPC. + + Updates the specified policy. + + You can update only the rules and the display name for the + policy. + + To update a policy, you should use a read-modify-write loop: + + 1. Use [GetPolicy][google.iam.v2.Policies.GetPolicy] to read the + current version of the policy. + 2. Modify the policy as needed. + 3. Use ``UpdatePolicy`` to write the updated policy. + + This pattern helps prevent conflicts between concurrent updates. + + Returns: + Callable[[~.UpdatePolicyRequest], + ~.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_policy" not in self._stubs: + self._stubs["update_policy"] = self.grpc_channel.unary_unary( + "/google.iam.v2.Policies/UpdatePolicy", + request_serializer=policy.UpdatePolicyRequest.serialize, + response_deserializer=operations_pb2.Operation.FromString, + ) + return self._stubs["update_policy"] + + @property + def delete_policy( + self, + ) -> Callable[[policy.DeletePolicyRequest], operations_pb2.Operation]: + r"""Return a callable for the delete policy method over gRPC. + + Deletes a policy. This action is permanent. + + Returns: + Callable[[~.DeletePolicyRequest], + ~.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_policy" not in self._stubs: + self._stubs["delete_policy"] = self.grpc_channel.unary_unary( + "/google.iam.v2.Policies/DeletePolicy", + request_serializer=policy.DeletePolicyRequest.serialize, + response_deserializer=operations_pb2.Operation.FromString, + ) + return self._stubs["delete_policy"] + + def close(self): + self.grpc_channel.close() + + @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 kind(self) -> str: + return "grpc" + + +__all__ = ("PoliciesGrpcTransport",) diff --git a/google/cloud/iam_v2/services/policies/transports/grpc_asyncio.py b/google/cloud/iam_v2/services/policies/transports/grpc_asyncio.py new file mode 100644 index 0000000..1261531 --- /dev/null +++ b/google/cloud/iam_v2/services/policies/transports/grpc_asyncio.py @@ -0,0 +1,421 @@ +# -*- 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.longrunning import operations_pb2 # type: ignore +import grpc # type: ignore +from grpc.experimental import aio # type: ignore + +from google.cloud.iam_v2.types import policy +from google.cloud.iam_v2.types import policy as gi_policy + +from .base import DEFAULT_CLIENT_INFO, PoliciesTransport +from .grpc import PoliciesGrpcTransport + + +class PoliciesGrpcAsyncIOTransport(PoliciesTransport): + """gRPC AsyncIO backend transport for Policies. + + An interface for managing Identity and Access Management + (IAM) policies. + + 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 = "iam.googleapis.com", + credentials: 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 = "iam.googleapis.com", + credentials: 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, + 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 list_policies( + self, + ) -> Callable[[policy.ListPoliciesRequest], Awaitable[policy.ListPoliciesResponse]]: + r"""Return a callable for the list policies method over gRPC. + + Retrieves the policies of the specified kind that are + attached to a resource. + + The response lists only policy metadata. In particular, + policy rules are omitted. + + Returns: + Callable[[~.ListPoliciesRequest], + Awaitable[~.ListPoliciesResponse]]: + 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_policies" not in self._stubs: + self._stubs["list_policies"] = self.grpc_channel.unary_unary( + "/google.iam.v2.Policies/ListPolicies", + request_serializer=policy.ListPoliciesRequest.serialize, + response_deserializer=policy.ListPoliciesResponse.deserialize, + ) + return self._stubs["list_policies"] + + @property + def get_policy( + self, + ) -> Callable[[policy.GetPolicyRequest], Awaitable[policy.Policy]]: + r"""Return a callable for the get policy method over gRPC. + + Gets a policy. + + Returns: + Callable[[~.GetPolicyRequest], + 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_policy" not in self._stubs: + self._stubs["get_policy"] = self.grpc_channel.unary_unary( + "/google.iam.v2.Policies/GetPolicy", + request_serializer=policy.GetPolicyRequest.serialize, + response_deserializer=policy.Policy.deserialize, + ) + return self._stubs["get_policy"] + + @property + def create_policy( + self, + ) -> Callable[[gi_policy.CreatePolicyRequest], Awaitable[operations_pb2.Operation]]: + r"""Return a callable for the create policy method over gRPC. + + Creates a policy. + + Returns: + Callable[[~.CreatePolicyRequest], + 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_policy" not in self._stubs: + self._stubs["create_policy"] = self.grpc_channel.unary_unary( + "/google.iam.v2.Policies/CreatePolicy", + request_serializer=gi_policy.CreatePolicyRequest.serialize, + response_deserializer=operations_pb2.Operation.FromString, + ) + return self._stubs["create_policy"] + + @property + def update_policy( + self, + ) -> Callable[[policy.UpdatePolicyRequest], Awaitable[operations_pb2.Operation]]: + r"""Return a callable for the update policy method over gRPC. + + Updates the specified policy. + + You can update only the rules and the display name for the + policy. + + To update a policy, you should use a read-modify-write loop: + + 1. Use [GetPolicy][google.iam.v2.Policies.GetPolicy] to read the + current version of the policy. + 2. Modify the policy as needed. + 3. Use ``UpdatePolicy`` to write the updated policy. + + This pattern helps prevent conflicts between concurrent updates. + + Returns: + Callable[[~.UpdatePolicyRequest], + 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_policy" not in self._stubs: + self._stubs["update_policy"] = self.grpc_channel.unary_unary( + "/google.iam.v2.Policies/UpdatePolicy", + request_serializer=policy.UpdatePolicyRequest.serialize, + response_deserializer=operations_pb2.Operation.FromString, + ) + return self._stubs["update_policy"] + + @property + def delete_policy( + self, + ) -> Callable[[policy.DeletePolicyRequest], Awaitable[operations_pb2.Operation]]: + r"""Return a callable for the delete policy method over gRPC. + + Deletes a policy. This action is permanent. + + Returns: + Callable[[~.DeletePolicyRequest], + 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_policy" not in self._stubs: + self._stubs["delete_policy"] = self.grpc_channel.unary_unary( + "/google.iam.v2.Policies/DeletePolicy", + request_serializer=policy.DeletePolicyRequest.serialize, + response_deserializer=operations_pb2.Operation.FromString, + ) + return self._stubs["delete_policy"] + + def close(self): + return self.grpc_channel.close() + + @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"] + + +__all__ = ("PoliciesGrpcAsyncIOTransport",) diff --git a/google/cloud/iam_v2/types/__init__.py b/google/cloud/iam_v2/types/__init__.py new file mode 100644 index 0000000..237009d --- /dev/null +++ b/google/cloud/iam_v2/types/__init__.py @@ -0,0 +1,40 @@ +# -*- 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 .deny import DenyRule +from .policy import ( + CreatePolicyRequest, + DeletePolicyRequest, + GetPolicyRequest, + ListPoliciesRequest, + ListPoliciesResponse, + Policy, + PolicyOperationMetadata, + PolicyRule, + UpdatePolicyRequest, +) + +__all__ = ( + "DenyRule", + "CreatePolicyRequest", + "DeletePolicyRequest", + "GetPolicyRequest", + "ListPoliciesRequest", + "ListPoliciesResponse", + "Policy", + "PolicyOperationMetadata", + "PolicyRule", + "UpdatePolicyRequest", +) diff --git a/google/cloud/iam_v2/types/deny.py b/google/cloud/iam_v2/types/deny.py new file mode 100644 index 0000000..a3dd76c --- /dev/null +++ b/google/cloud/iam_v2/types/deny.py @@ -0,0 +1,141 @@ +# -*- 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.type import expr_pb2 # type: ignore +import proto # type: ignore + +__protobuf__ = proto.module( + package="google.iam.v2", + manifest={ + "DenyRule", + }, +) + + +class DenyRule(proto.Message): + r"""A deny rule in an IAM deny policy. + + Attributes: + denied_principals (Sequence[str]): + The identities that are prevented from using one or more + permissions on Google Cloud resources. This field can + contain the following values: + + - ``principalSet://goog/public:all``: A special identifier + that represents any principal that is on the internet, + even if they do not have a Google Account or are not + logged in. + + - ``principal://goog/subject/{email_id}``: A specific + Google Account. Includes Gmail, Cloud Identity, and + Google Workspace user accounts. For example, + ``principal://goog/subject/alice@example.com``. + + - ``deleted:principal://goog/subject/{email_id}?uid={uid}``: + A specific Google Account that was deleted recently. For + example, + ``deleted:principal://goog/subject/alice@example.com?uid=1234567890``. + If the Google Account is recovered, this identifier + reverts to the standard identifier for a Google Account. + + - ``principalSet://goog/group/{group_id}``: A Google group. + For example, + ``principalSet://goog/group/admins@example.com``. + + - ``deleted:principalSet://goog/group/{group_id}?uid={uid}``: + A Google group that was deleted recently. For example, + ``deleted:principalSet://goog/group/admins@example.com?uid=1234567890``. + If the Google group is restored, this identifier reverts + to the standard identifier for a Google group. + + - ``principal://iam.googleapis.com/projects/-/serviceAccounts/{service_account_id}``: + A Google Cloud service account. For example, + ``principal://iam.googleapis.com/projects/-/serviceAccounts/my-service-account@iam.gserviceaccount.com``. + + - ``deleted:principal://iam.googleapis.com/projects/-/serviceAccounts/{service_account_id}?uid={uid}``: + A Google Cloud service account that was deleted recently. + For example, + ``deleted:principal://iam.googleapis.com/projects/-/serviceAccounts/my-service-account@iam.gserviceaccount.com?uid=1234567890``. + If the service account is undeleted, this identifier + reverts to the standard identifier for a service account. + + - ``principalSet://goog/cloudIdentityCustomerId/{customer_id}``: + All of the principals associated with the specified + Google Workspace or Cloud Identity customer ID. For + example, + ``principalSet://goog/cloudIdentityCustomerId/C01Abc35``. + exception_principals (Sequence[str]): + The identities that are excluded from the deny rule, even if + they are listed in the ``denied_principals``. For example, + you could add a Google group to the ``denied_principals``, + then exclude specific users who belong to that group. + + This field can contain the same values as the + ``denied_principals`` field, excluding + ``principalSet://goog/public:all``, which represents all + users on the internet. + denied_permissions (Sequence[str]): + The permissions that are explicitly denied by this rule. + Each permission uses the format + ``{service_fqdn}/{resource}.{verb}``, where + ``{service_fqdn}`` is the fully qualified domain name for + the service. For example, ``iam.googleapis.com/roles.list``. + exception_permissions (Sequence[str]): + Specifies the permissions that this rule excludes from the + set of denied permissions given by ``denied_permissions``. + If a permission appears in ``denied_permissions`` *and* in + ``exception_permissions`` then it will *not* be denied. + + The excluded permissions can be specified using the same + syntax as ``denied_permissions``. + denial_condition (google.type.expr_pb2.Expr): + The condition that determines whether this deny rule applies + to a request. If the condition expression evaluates to + ``true``, then the deny rule is applied; otherwise, the deny + rule is not applied. + + Each deny rule is evaluated independently. If this deny rule + does not apply to a request, other deny rules might still + apply. + + The condition can use CEL functions that evaluate `resource + tags `__. + Other functions and operators are not supported. + """ + + denied_principals = proto.RepeatedField( + proto.STRING, + number=1, + ) + exception_principals = proto.RepeatedField( + proto.STRING, + number=2, + ) + denied_permissions = proto.RepeatedField( + proto.STRING, + number=3, + ) + exception_permissions = proto.RepeatedField( + proto.STRING, + number=4, + ) + denial_condition = proto.Field( + proto.MESSAGE, + number=5, + message=expr_pb2.Expr, + ) + + +__all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/google/cloud/iam_v2/types/policy.py b/google/cloud/iam_v2/types/policy.py new file mode 100644 index 0000000..d2b8165 --- /dev/null +++ b/google/cloud/iam_v2/types/policy.py @@ -0,0 +1,379 @@ +# -*- 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.protobuf import timestamp_pb2 # type: ignore +import proto # type: ignore + +from google.cloud.iam_v2.types import deny + +__protobuf__ = proto.module( + package="google.iam.v2", + manifest={ + "Policy", + "PolicyRule", + "ListPoliciesRequest", + "ListPoliciesResponse", + "GetPolicyRequest", + "CreatePolicyRequest", + "UpdatePolicyRequest", + "DeletePolicyRequest", + "PolicyOperationMetadata", + }, +) + + +class Policy(proto.Message): + r"""Data for an IAM policy. + + Attributes: + name (str): + Immutable. The resource name of the ``Policy``, which must + be unique. Format: + ``policies/{attachment_point}/denypolicies/{policy_id}`` + + The attachment point is identified by its URL-encoded full + resource name, which means that the forward-slash character, + ``/``, must be written as ``%2F``. For example, + ``policies/cloudresourcemanager.googleapis.com%2Fprojects%2Fmy-project/denypolicies/my-deny-policy``. + + For organizations and folders, use the numeric ID in the + full resource name. For projects, requests can use the + alphanumeric or the numeric ID. Responses always contain the + numeric ID. + uid (str): + Immutable. The globally unique ID of the ``Policy``. + Assigned automatically when the ``Policy`` is created. + kind (str): + Output only. The kind of the ``Policy``. Always contains the + value ``DenyPolicy``. + display_name (str): + A user-specified description of the ``Policy``. This value + can be up to 63 characters. + annotations (Mapping[str, str]): + A key-value map to store arbitrary metadata for the + ``Policy``. Keys can be up to 63 characters. Values can be + up to 255 characters. + etag (str): + An opaque tag that identifies the current version of the + ``Policy``. IAM uses this value to help manage concurrent + updates, so they do not cause one update to be overwritten + by another. + + If this field is present in a [CreatePolicy][] request, the + value is ignored. + create_time (google.protobuf.timestamp_pb2.Timestamp): + Output only. The time when the ``Policy`` was created. + update_time (google.protobuf.timestamp_pb2.Timestamp): + Output only. The time when the ``Policy`` was last updated. + delete_time (google.protobuf.timestamp_pb2.Timestamp): + Output only. The time when the ``Policy`` was deleted. Empty + if the policy is not deleted. + rules (Sequence[google.cloud.iam_v2.types.PolicyRule]): + A list of rules that specify the behavior of the ``Policy``. + All of the rules should be of the ``kind`` specified in the + ``Policy``. + managing_authority (str): + Immutable. Specifies that this policy is + managed by an authority and can only be modified + by that authority. Usage is restricted. + """ + + name = proto.Field( + proto.STRING, + number=1, + ) + uid = proto.Field( + proto.STRING, + number=2, + ) + kind = proto.Field( + proto.STRING, + number=3, + ) + display_name = proto.Field( + proto.STRING, + number=4, + ) + annotations = proto.MapField( + proto.STRING, + proto.STRING, + number=5, + ) + etag = proto.Field( + proto.STRING, + number=6, + ) + create_time = proto.Field( + proto.MESSAGE, + number=7, + message=timestamp_pb2.Timestamp, + ) + update_time = proto.Field( + proto.MESSAGE, + number=8, + message=timestamp_pb2.Timestamp, + ) + delete_time = proto.Field( + proto.MESSAGE, + number=9, + message=timestamp_pb2.Timestamp, + ) + rules = proto.RepeatedField( + proto.MESSAGE, + number=10, + message="PolicyRule", + ) + managing_authority = proto.Field( + proto.STRING, + number=11, + ) + + +class PolicyRule(proto.Message): + r"""A single rule in a ``Policy``. + + .. _oneof: https://proto-plus-python.readthedocs.io/en/stable/fields.html#oneofs-mutually-exclusive-fields + + Attributes: + deny_rule (google.cloud.iam_v2.types.DenyRule): + A rule for a deny policy. + + This field is a member of `oneof`_ ``kind``. + description (str): + A user-specified description of the rule. + This value can be up to 256 characters. + """ + + deny_rule = proto.Field( + proto.MESSAGE, + number=2, + oneof="kind", + message=deny.DenyRule, + ) + description = proto.Field( + proto.STRING, + number=1, + ) + + +class ListPoliciesRequest(proto.Message): + r"""Request message for ``ListPolicies``. + + Attributes: + parent (str): + Required. The resource that the policy is attached to, along + with the kind of policy to list. Format: + ``policies/{attachment_point}/denypolicies`` + + The attachment point is identified by its URL-encoded full + resource name, which means that the forward-slash character, + ``/``, must be written as ``%2F``. For example, + ``policies/cloudresourcemanager.googleapis.com%2Fprojects%2Fmy-project/denypolicies``. + + For organizations and folders, use the numeric ID in the + full resource name. For projects, you can use the + alphanumeric or the numeric ID. + page_size (int): + The maximum number of policies to return. IAM + ignores this value and uses the value 1000. + page_token (str): + A page token received in a + [ListPoliciesResponse][google.iam.v2.ListPoliciesResponse]. + Provide this token to retrieve the next page. + """ + + parent = proto.Field( + proto.STRING, + number=1, + ) + page_size = proto.Field( + proto.INT32, + number=2, + ) + page_token = proto.Field( + proto.STRING, + number=3, + ) + + +class ListPoliciesResponse(proto.Message): + r"""Response message for ``ListPolicies``. + + Attributes: + policies (Sequence[google.cloud.iam_v2.types.Policy]): + Metadata for the policies that are attached + to the resource. + next_page_token (str): + A page token that you can use in a + [ListPoliciesRequest][google.iam.v2.ListPoliciesRequest] to + retrieve the next page. If this field is omitted, there are + no additional pages. + """ + + @property + def raw_page(self): + return self + + policies = proto.RepeatedField( + proto.MESSAGE, + number=1, + message="Policy", + ) + next_page_token = proto.Field( + proto.STRING, + number=2, + ) + + +class GetPolicyRequest(proto.Message): + r"""Request message for ``GetPolicy``. + + Attributes: + name (str): + Required. The resource name of the policy to retrieve. + Format: + ``policies/{attachment_point}/denypolicies/{policy_id}`` + + Use the URL-encoded full resource name, which means that the + forward-slash character, ``/``, must be written as ``%2F``. + For example, + ``policies/cloudresourcemanager.googleapis.com%2Fprojects%2Fmy-project/denypolicies/my-policy``. + + For organizations and folders, use the numeric ID in the + full resource name. For projects, you can use the + alphanumeric or the numeric ID. + """ + + name = proto.Field( + proto.STRING, + number=1, + ) + + +class CreatePolicyRequest(proto.Message): + r"""Request message for ``CreatePolicy``. + + Attributes: + parent (str): + Required. The resource that the policy is attached to, along + with the kind of policy to create. Format: + ``policies/{attachment_point}/denypolicies`` + + The attachment point is identified by its URL-encoded full + resource name, which means that the forward-slash character, + ``/``, must be written as ``%2F``. For example, + ``policies/cloudresourcemanager.googleapis.com%2Fprojects%2Fmy-project/denypolicies``. + + For organizations and folders, use the numeric ID in the + full resource name. For projects, you can use the + alphanumeric or the numeric ID. + policy (google.cloud.iam_v2.types.Policy): + Required. The policy to create. + policy_id (str): + The ID to use for this policy, which will become the final + component of the policy's resource name. The ID must contain + 3 to 63 characters. It can contain lowercase letters and + numbers, as well as dashes (``-``) and periods (``.``). The + first character must be a lowercase letter. + """ + + parent = proto.Field( + proto.STRING, + number=1, + ) + policy = proto.Field( + proto.MESSAGE, + number=2, + message="Policy", + ) + policy_id = proto.Field( + proto.STRING, + number=3, + ) + + +class UpdatePolicyRequest(proto.Message): + r"""Request message for ``UpdatePolicy``. + + Attributes: + policy (google.cloud.iam_v2.types.Policy): + Required. The policy to update. + + To prevent conflicting updates, the ``etag`` value must + match the value that is stored in IAM. If the ``etag`` + values do not match, the request fails with a ``409`` error + code and ``ABORTED`` status. + """ + + policy = proto.Field( + proto.MESSAGE, + number=1, + message="Policy", + ) + + +class DeletePolicyRequest(proto.Message): + r"""Request message for ``DeletePolicy``. + + Attributes: + name (str): + Required. The resource name of the policy to delete. Format: + ``policies/{attachment_point}/denypolicies/{policy_id}`` + + Use the URL-encoded full resource name, which means that the + forward-slash character, ``/``, must be written as ``%2F``. + For example, + ``policies/cloudresourcemanager.googleapis.com%2Fprojects%2Fmy-project/denypolicies/my-policy``. + + For organizations and folders, use the numeric ID in the + full resource name. For projects, you can use the + alphanumeric or the numeric ID. + etag (str): + Optional. The expected ``etag`` of the policy to delete. If + the value does not match the value that is stored in IAM, + the request fails with a ``409`` error code and ``ABORTED`` + status. + + If you omit this field, the policy is deleted regardless of + its current ``etag``. + """ + + name = proto.Field( + proto.STRING, + number=1, + ) + etag = proto.Field( + proto.STRING, + number=2, + ) + + +class PolicyOperationMetadata(proto.Message): + r"""Metadata for long-running ``Policy`` operations. + + Attributes: + create_time (google.protobuf.timestamp_pb2.Timestamp): + Timestamp when the ``google.longrunning.Operation`` was + created. + """ + + create_time = proto.Field( + proto.MESSAGE, + number=1, + message=timestamp_pb2.Timestamp, + ) + + +__all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/google/cloud/iam_v2beta/services/policies/async_client.py b/google/cloud/iam_v2beta/services/policies/async_client.py index 254635f..05237f9 100644 --- a/google/cloud/iam_v2beta/services/policies/async_client.py +++ b/google/cloud/iam_v2beta/services/policies/async_client.py @@ -33,6 +33,7 @@ from google.api_core import operation # type: ignore from google.api_core import operation_async # type: ignore +from google.longrunning import operations_pb2 from google.protobuf import timestamp_pb2 # type: ignore from google.cloud.iam_v2beta.services.policies import pagers @@ -54,8 +55,6 @@ class PoliciesAsyncClient: DEFAULT_ENDPOINT = PoliciesClient.DEFAULT_ENDPOINT DEFAULT_MTLS_ENDPOINT = PoliciesClient.DEFAULT_MTLS_ENDPOINT - policy_path = staticmethod(PoliciesClient.policy_path) - parse_policy_path = staticmethod(PoliciesClient.parse_policy_path) common_billing_account_path = staticmethod( PoliciesClient.common_billing_account_path ) @@ -219,6 +218,13 @@ async def list_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 iam_v2beta async def sample_list_policies(): @@ -345,6 +351,13 @@ async def get_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 iam_v2beta async def sample_get_policy(): @@ -458,6 +471,13 @@ async def create_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 iam_v2beta async def sample_create_policy(): @@ -618,6 +638,13 @@ async def update_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 iam_v2beta async def sample_update_policy(): @@ -716,6 +743,13 @@ async def delete_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 iam_v2beta async def sample_delete_policy(): @@ -831,6 +865,60 @@ async def sample_delete_policy(): # Done; return the response. return response + async def get_operation( + self, + request: operations_pb2.GetOperationRequest = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + 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 __aenter__(self): return self diff --git a/google/cloud/iam_v2beta/services/policies/client.py b/google/cloud/iam_v2beta/services/policies/client.py index d70c007..07f2d9d 100644 --- a/google/cloud/iam_v2beta/services/policies/client.py +++ b/google/cloud/iam_v2beta/services/policies/client.py @@ -36,6 +36,7 @@ from google.api_core import operation # type: ignore from google.api_core import operation_async # type: ignore +from google.longrunning import operations_pb2 from google.protobuf import timestamp_pb2 # type: ignore from google.cloud.iam_v2beta.services.policies import pagers @@ -168,21 +169,6 @@ def transport(self) -> PoliciesTransport: """ return self._transport - @staticmethod - def policy_path( - policy: str, - ) -> str: - """Returns a fully-qualified policy string.""" - return "policies/{policy}".format( - policy=policy, - ) - - @staticmethod - def parse_policy_path(path: str) -> Dict[str, str]: - """Parses a policy path into its component segments.""" - m = re.match(r"^policies/(?P.+?)$", path) - return m.groupdict() if m else {} - @staticmethod def common_billing_account_path( billing_account: str, @@ -443,6 +429,13 @@ def list_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 iam_v2beta def sample_list_policies(): @@ -560,6 +553,13 @@ def get_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 iam_v2beta def sample_get_policy(): @@ -664,6 +664,13 @@ def create_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 iam_v2beta def sample_create_policy(): @@ -815,6 +822,13 @@ def update_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 iam_v2beta def sample_update_policy(): @@ -905,6 +919,13 @@ def delete_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 iam_v2beta def sample_delete_policy(): @@ -1024,6 +1045,60 @@ def __exit__(self, type, value, traceback): """ self.transport.close() + def get_operation( + self, + request: operations_pb2.GetOperationRequest = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + 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 + try: DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/google/cloud/iam_v2beta/services/policies/transports/base.py b/google/cloud/iam_v2beta/services/policies/transports/base.py index 82e5648..c00cc4b 100644 --- a/google/cloud/iam_v2beta/services/policies/transports/base.py +++ b/google/cloud/iam_v2beta/services/policies/transports/base.py @@ -259,6 +259,15 @@ def delete_policy( ]: raise NotImplementedError() + @property + def get_operation( + self, + ) -> Callable[ + [operations_pb2.GetOperationRequest], + Union[operations_pb2.Operation, Awaitable[operations_pb2.Operation]], + ]: + raise NotImplementedError() + @property def kind(self) -> str: raise NotImplementedError() diff --git a/google/cloud/iam_v2beta/services/policies/transports/grpc.py b/google/cloud/iam_v2beta/services/policies/transports/grpc.py index e0f4471..3cd60a7 100644 --- a/google/cloud/iam_v2beta/services/policies/transports/grpc.py +++ b/google/cloud/iam_v2beta/services/policies/transports/grpc.py @@ -393,6 +393,23 @@ def delete_policy( def close(self): self.grpc_channel.close() + @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 kind(self) -> str: return "grpc" diff --git a/google/cloud/iam_v2beta/services/policies/transports/grpc_asyncio.py b/google/cloud/iam_v2beta/services/policies/transports/grpc_asyncio.py index 0e03360..85ebabb 100644 --- a/google/cloud/iam_v2beta/services/policies/transports/grpc_asyncio.py +++ b/google/cloud/iam_v2beta/services/policies/transports/grpc_asyncio.py @@ -400,5 +400,22 @@ def delete_policy( def close(self): return self.grpc_channel.close() + @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"] + __all__ = ("PoliciesGrpcAsyncIOTransport",) diff --git a/google/cloud/iam_v2beta/types/deny.py b/google/cloud/iam_v2beta/types/deny.py index 7438334..15f277d 100644 --- a/google/cloud/iam_v2beta/types/deny.py +++ b/google/cloud/iam_v2beta/types/deny.py @@ -34,8 +34,9 @@ class DenyRule(proto.Message): contain the following values: - ``principalSet://goog/public:all``: A special identifier - that represents any user who is on the internet, even if - they do not have a Google Account or are not logged in. + that represents any principal that is on the internet, + even if they do not have a Google Account or are not + logged in. - ``principal://goog/subject/{email_id}``: A specific Google Account. Includes Gmail, Cloud Identity, and diff --git a/mypy.ini b/mypy.ini index 4505b48..574c5ae 100644 --- a/mypy.ini +++ b/mypy.ini @@ -1,3 +1,3 @@ [mypy] -python_version = 3.6 +python_version = 3.7 namespace_packages = True diff --git a/noxfile.py b/noxfile.py index cc39f3b..ffe9f35 100644 --- a/noxfile.py +++ b/noxfile.py @@ -189,7 +189,9 @@ def unit(session): def install_systemtest_dependencies(session, *constraints): # Use pre-release gRPC for system tests. - session.install("--pre", "grpcio") + # Exclude version 1.49.0rc1 which has a known issue. + # See https://github.com/grpc/grpc/pull/30642 + session.install("--pre", "grpcio!=1.49.0rc1") session.install(*SYSTEM_TEST_STANDARD_DEPENDENCIES, *constraints) @@ -369,7 +371,8 @@ def prerelease_deps(session): # dependency of grpc "six", "googleapis-common-protos", - "grpcio", + # Exclude version 1.49.0rc1 which has a known issue. See https://github.com/grpc/grpc/pull/30642 + "grpcio!=1.49.0rc1", "grpcio-status", "google-api-core", "proto-plus", diff --git a/owlbot.py b/owlbot.py index cd317c4..cb9b5e9 100644 --- a/owlbot.py +++ b/owlbot.py @@ -62,9 +62,29 @@ def get_staging_dirs( # This library ships clients for two different APIs, # IAM and IAM credentials iam_credentials_default_version = "v1" -iam_default_version = "v2beta" +iam_default_version = "v2" for library in get_staging_dirs(iam_default_version, "iam"): + s.replace( + # workaround docstring formatting issues + library / "google/cloud/iam_v2/services/policies/*client.py", + """ + ``` + \{ + attachment_point: + 'cloudresourcemanager.googleapis.com%2Forganizations%2F212345678901' + filter: 'kind:denyPolicies' + \} + ```""", + """ + ``` + { + attachment_point: + 'cloudresourcemanager.googleapis.com%2Forganizations%2F212345678901' + filter: 'kind:denyPolicies' + } + ```""", + ) s.move([library], excludes=["setup.py", "README.rst", "docs/index.rst", "google/cloud/iam/**",]) for library in get_staging_dirs(iam_credentials_default_version, "iamcredentials"): @@ -74,7 +94,6 @@ def get_staging_dirs( templated_files = CommonTemplates().py_library( microgenerator=True, - versions=detect_versions(path="./google", default_first=True), ) s.move( [templated_files], excludes=[".coveragerc"] diff --git a/renovate.json b/renovate.json index c21036d..39b2a0e 100644 --- a/renovate.json +++ b/renovate.json @@ -5,7 +5,7 @@ ":preserveSemverRanges", ":disableDependencyDashboard" ], - "ignorePaths": [".pre-commit-config.yaml"], + "ignorePaths": [".pre-commit-config.yaml", ".kokoro/requirements.txt", "setup.py"], "pip_requirements": { "fileMatch": ["requirements-test.txt", "samples/[\\S/]*constraints.txt", "samples/[\\S/]*constraints-test.txt"] } diff --git a/samples/__init__.py b/samples/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/samples/generated_samples/iam_v2_generated_policies_create_policy_async.py b/samples/generated_samples/iam_v2_generated_policies_create_policy_async.py new file mode 100644 index 0000000..8e9107e --- /dev/null +++ b/samples/generated_samples/iam_v2_generated_policies_create_policy_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 CreatePolicy +# 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-iam + + +# [START iam_v2_generated_Policies_CreatePolicy_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 iam_v2 + + +async def sample_create_policy(): + # Create a client + client = iam_v2.PoliciesAsyncClient() + + # Initialize request argument(s) + request = iam_v2.CreatePolicyRequest( + parent="parent_value", + ) + + # Make the request + operation = client.create_policy(request=request) + + print("Waiting for operation to complete...") + + response = await operation.result() + + # Handle the response + print(response) + +# [END iam_v2_generated_Policies_CreatePolicy_async] diff --git a/samples/generated_samples/iam_v2_generated_policies_create_policy_sync.py b/samples/generated_samples/iam_v2_generated_policies_create_policy_sync.py new file mode 100644 index 0000000..0afd014 --- /dev/null +++ b/samples/generated_samples/iam_v2_generated_policies_create_policy_sync.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 CreatePolicy +# 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-iam + + +# [START iam_v2_generated_Policies_CreatePolicy_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 iam_v2 + + +def sample_create_policy(): + # Create a client + client = iam_v2.PoliciesClient() + + # Initialize request argument(s) + request = iam_v2.CreatePolicyRequest( + parent="parent_value", + ) + + # Make the request + operation = client.create_policy(request=request) + + print("Waiting for operation to complete...") + + response = operation.result() + + # Handle the response + print(response) + +# [END iam_v2_generated_Policies_CreatePolicy_sync] diff --git a/samples/generated_samples/iam_v2_generated_policies_delete_policy_async.py b/samples/generated_samples/iam_v2_generated_policies_delete_policy_async.py new file mode 100644 index 0000000..8169cd0 --- /dev/null +++ b/samples/generated_samples/iam_v2_generated_policies_delete_policy_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 DeletePolicy +# 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-iam + + +# [START iam_v2_generated_Policies_DeletePolicy_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 iam_v2 + + +async def sample_delete_policy(): + # Create a client + client = iam_v2.PoliciesAsyncClient() + + # Initialize request argument(s) + request = iam_v2.DeletePolicyRequest( + name="name_value", + ) + + # Make the request + operation = client.delete_policy(request=request) + + print("Waiting for operation to complete...") + + response = await operation.result() + + # Handle the response + print(response) + +# [END iam_v2_generated_Policies_DeletePolicy_async] diff --git a/samples/generated_samples/iam_v2_generated_policies_delete_policy_sync.py b/samples/generated_samples/iam_v2_generated_policies_delete_policy_sync.py new file mode 100644 index 0000000..dd7f7b1 --- /dev/null +++ b/samples/generated_samples/iam_v2_generated_policies_delete_policy_sync.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 DeletePolicy +# 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-iam + + +# [START iam_v2_generated_Policies_DeletePolicy_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 iam_v2 + + +def sample_delete_policy(): + # Create a client + client = iam_v2.PoliciesClient() + + # Initialize request argument(s) + request = iam_v2.DeletePolicyRequest( + name="name_value", + ) + + # Make the request + operation = client.delete_policy(request=request) + + print("Waiting for operation to complete...") + + response = operation.result() + + # Handle the response + print(response) + +# [END iam_v2_generated_Policies_DeletePolicy_sync] diff --git a/samples/generated_samples/iam_v2_generated_policies_get_policy_async.py b/samples/generated_samples/iam_v2_generated_policies_get_policy_async.py new file mode 100644 index 0000000..5e26a38 --- /dev/null +++ b/samples/generated_samples/iam_v2_generated_policies_get_policy_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 GetPolicy +# 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-iam + + +# [START iam_v2_generated_Policies_GetPolicy_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 iam_v2 + + +async def sample_get_policy(): + # Create a client + client = iam_v2.PoliciesAsyncClient() + + # Initialize request argument(s) + request = iam_v2.GetPolicyRequest( + name="name_value", + ) + + # Make the request + response = await client.get_policy(request=request) + + # Handle the response + print(response) + +# [END iam_v2_generated_Policies_GetPolicy_async] diff --git a/samples/generated_samples/iam_v2_generated_policies_get_policy_sync.py b/samples/generated_samples/iam_v2_generated_policies_get_policy_sync.py new file mode 100644 index 0000000..70a3b1f --- /dev/null +++ b/samples/generated_samples/iam_v2_generated_policies_get_policy_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 GetPolicy +# 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-iam + + +# [START iam_v2_generated_Policies_GetPolicy_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 iam_v2 + + +def sample_get_policy(): + # Create a client + client = iam_v2.PoliciesClient() + + # Initialize request argument(s) + request = iam_v2.GetPolicyRequest( + name="name_value", + ) + + # Make the request + response = client.get_policy(request=request) + + # Handle the response + print(response) + +# [END iam_v2_generated_Policies_GetPolicy_sync] diff --git a/samples/generated_samples/iam_v2_generated_policies_list_applicable_policies_async.py b/samples/generated_samples/iam_v2_generated_policies_list_applicable_policies_async.py new file mode 100644 index 0000000..86e23a3 --- /dev/null +++ b/samples/generated_samples/iam_v2_generated_policies_list_applicable_policies_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 ListApplicablePolicies +# 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-iam + + +# [START iam_v2_generated_Policies_ListApplicablePolicies_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 iam_v2 + + +async def sample_list_applicable_policies(): + # Create a client + client = iam_v2.PoliciesAsyncClient() + + # Initialize request argument(s) + request = iam_v2.ListApplicablePoliciesRequest( + attachment_point="attachment_point_value", + ) + + # Make the request + page_result = client.list_applicable_policies(request=request) + + # Handle the response + async for response in page_result: + print(response) + +# [END iam_v2_generated_Policies_ListApplicablePolicies_async] diff --git a/samples/generated_samples/iam_v2_generated_policies_list_applicable_policies_sync.py b/samples/generated_samples/iam_v2_generated_policies_list_applicable_policies_sync.py new file mode 100644 index 0000000..655f240 --- /dev/null +++ b/samples/generated_samples/iam_v2_generated_policies_list_applicable_policies_sync.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 ListApplicablePolicies +# 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-iam + + +# [START iam_v2_generated_Policies_ListApplicablePolicies_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 iam_v2 + + +def sample_list_applicable_policies(): + # Create a client + client = iam_v2.PoliciesClient() + + # Initialize request argument(s) + request = iam_v2.ListApplicablePoliciesRequest( + attachment_point="attachment_point_value", + ) + + # Make the request + page_result = client.list_applicable_policies(request=request) + + # Handle the response + for response in page_result: + print(response) + +# [END iam_v2_generated_Policies_ListApplicablePolicies_sync] diff --git a/samples/generated_samples/iam_v2_generated_policies_list_policies_async.py b/samples/generated_samples/iam_v2_generated_policies_list_policies_async.py new file mode 100644 index 0000000..3651a33 --- /dev/null +++ b/samples/generated_samples/iam_v2_generated_policies_list_policies_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 ListPolicies +# 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-iam + + +# [START iam_v2_generated_Policies_ListPolicies_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 iam_v2 + + +async def sample_list_policies(): + # Create a client + client = iam_v2.PoliciesAsyncClient() + + # Initialize request argument(s) + request = iam_v2.ListPoliciesRequest( + parent="parent_value", + ) + + # Make the request + page_result = client.list_policies(request=request) + + # Handle the response + async for response in page_result: + print(response) + +# [END iam_v2_generated_Policies_ListPolicies_async] diff --git a/samples/generated_samples/iam_v2_generated_policies_list_policies_sync.py b/samples/generated_samples/iam_v2_generated_policies_list_policies_sync.py new file mode 100644 index 0000000..3bb0f66 --- /dev/null +++ b/samples/generated_samples/iam_v2_generated_policies_list_policies_sync.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 ListPolicies +# 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-iam + + +# [START iam_v2_generated_Policies_ListPolicies_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 iam_v2 + + +def sample_list_policies(): + # Create a client + client = iam_v2.PoliciesClient() + + # Initialize request argument(s) + request = iam_v2.ListPoliciesRequest( + parent="parent_value", + ) + + # Make the request + page_result = client.list_policies(request=request) + + # Handle the response + for response in page_result: + print(response) + +# [END iam_v2_generated_Policies_ListPolicies_sync] diff --git a/samples/generated_samples/iam_v2_generated_policies_update_policy_async.py b/samples/generated_samples/iam_v2_generated_policies_update_policy_async.py new file mode 100644 index 0000000..9f0c19f --- /dev/null +++ b/samples/generated_samples/iam_v2_generated_policies_update_policy_async.py @@ -0,0 +1,55 @@ +# -*- 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 UpdatePolicy +# 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-iam + + +# [START iam_v2_generated_Policies_UpdatePolicy_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 iam_v2 + + +async def sample_update_policy(): + # Create a client + client = iam_v2.PoliciesAsyncClient() + + # Initialize request argument(s) + request = iam_v2.UpdatePolicyRequest( + ) + + # Make the request + operation = client.update_policy(request=request) + + print("Waiting for operation to complete...") + + response = await operation.result() + + # Handle the response + print(response) + +# [END iam_v2_generated_Policies_UpdatePolicy_async] diff --git a/samples/generated_samples/iam_v2_generated_policies_update_policy_sync.py b/samples/generated_samples/iam_v2_generated_policies_update_policy_sync.py new file mode 100644 index 0000000..d5797d3 --- /dev/null +++ b/samples/generated_samples/iam_v2_generated_policies_update_policy_sync.py @@ -0,0 +1,55 @@ +# -*- 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 UpdatePolicy +# 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-iam + + +# [START iam_v2_generated_Policies_UpdatePolicy_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 iam_v2 + + +def sample_update_policy(): + # Create a client + client = iam_v2.PoliciesClient() + + # Initialize request argument(s) + request = iam_v2.UpdatePolicyRequest( + ) + + # Make the request + operation = client.update_policy(request=request) + + print("Waiting for operation to complete...") + + response = operation.result() + + # Handle the response + print(response) + +# [END iam_v2_generated_Policies_UpdatePolicy_sync] diff --git a/samples/generated_samples/iam_v2beta_generated_policies_create_policy_async.py b/samples/generated_samples/iam_v2beta_generated_policies_create_policy_async.py index 97095a7..e056ff6 100644 --- a/samples/generated_samples/iam_v2beta_generated_policies_create_policy_async.py +++ b/samples/generated_samples/iam_v2beta_generated_policies_create_policy_async.py @@ -24,6 +24,13 @@ # [START iam_v2beta_generated_Policies_CreatePolicy_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 iam_v2beta diff --git a/samples/generated_samples/iam_v2beta_generated_policies_create_policy_sync.py b/samples/generated_samples/iam_v2beta_generated_policies_create_policy_sync.py index 6ffde1e..9da27d9 100644 --- a/samples/generated_samples/iam_v2beta_generated_policies_create_policy_sync.py +++ b/samples/generated_samples/iam_v2beta_generated_policies_create_policy_sync.py @@ -24,6 +24,13 @@ # [START iam_v2beta_generated_Policies_CreatePolicy_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 iam_v2beta diff --git a/samples/generated_samples/iam_v2beta_generated_policies_delete_policy_async.py b/samples/generated_samples/iam_v2beta_generated_policies_delete_policy_async.py index 9a342db..76a05fa 100644 --- a/samples/generated_samples/iam_v2beta_generated_policies_delete_policy_async.py +++ b/samples/generated_samples/iam_v2beta_generated_policies_delete_policy_async.py @@ -24,6 +24,13 @@ # [START iam_v2beta_generated_Policies_DeletePolicy_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 iam_v2beta diff --git a/samples/generated_samples/iam_v2beta_generated_policies_delete_policy_sync.py b/samples/generated_samples/iam_v2beta_generated_policies_delete_policy_sync.py index d2754c4..2654ce7 100644 --- a/samples/generated_samples/iam_v2beta_generated_policies_delete_policy_sync.py +++ b/samples/generated_samples/iam_v2beta_generated_policies_delete_policy_sync.py @@ -24,6 +24,13 @@ # [START iam_v2beta_generated_Policies_DeletePolicy_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 iam_v2beta diff --git a/samples/generated_samples/iam_v2beta_generated_policies_get_policy_async.py b/samples/generated_samples/iam_v2beta_generated_policies_get_policy_async.py index d3c6a35..08bf54b 100644 --- a/samples/generated_samples/iam_v2beta_generated_policies_get_policy_async.py +++ b/samples/generated_samples/iam_v2beta_generated_policies_get_policy_async.py @@ -24,6 +24,13 @@ # [START iam_v2beta_generated_Policies_GetPolicy_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 iam_v2beta diff --git a/samples/generated_samples/iam_v2beta_generated_policies_get_policy_sync.py b/samples/generated_samples/iam_v2beta_generated_policies_get_policy_sync.py index d6e7f86..91e7467 100644 --- a/samples/generated_samples/iam_v2beta_generated_policies_get_policy_sync.py +++ b/samples/generated_samples/iam_v2beta_generated_policies_get_policy_sync.py @@ -24,6 +24,13 @@ # [START iam_v2beta_generated_Policies_GetPolicy_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 iam_v2beta diff --git a/samples/generated_samples/iam_v2beta_generated_policies_list_policies_async.py b/samples/generated_samples/iam_v2beta_generated_policies_list_policies_async.py index 54142db..1d35774 100644 --- a/samples/generated_samples/iam_v2beta_generated_policies_list_policies_async.py +++ b/samples/generated_samples/iam_v2beta_generated_policies_list_policies_async.py @@ -24,6 +24,13 @@ # [START iam_v2beta_generated_Policies_ListPolicies_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 iam_v2beta diff --git a/samples/generated_samples/iam_v2beta_generated_policies_list_policies_sync.py b/samples/generated_samples/iam_v2beta_generated_policies_list_policies_sync.py index d26198c..b9f37f9 100644 --- a/samples/generated_samples/iam_v2beta_generated_policies_list_policies_sync.py +++ b/samples/generated_samples/iam_v2beta_generated_policies_list_policies_sync.py @@ -24,6 +24,13 @@ # [START iam_v2beta_generated_Policies_ListPolicies_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 iam_v2beta diff --git a/samples/generated_samples/iam_v2beta_generated_policies_update_policy_async.py b/samples/generated_samples/iam_v2beta_generated_policies_update_policy_async.py index 532b731..4e47477 100644 --- a/samples/generated_samples/iam_v2beta_generated_policies_update_policy_async.py +++ b/samples/generated_samples/iam_v2beta_generated_policies_update_policy_async.py @@ -24,6 +24,13 @@ # [START iam_v2beta_generated_Policies_UpdatePolicy_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 iam_v2beta diff --git a/samples/generated_samples/iam_v2beta_generated_policies_update_policy_sync.py b/samples/generated_samples/iam_v2beta_generated_policies_update_policy_sync.py index bd45786..9fa4f9c 100644 --- a/samples/generated_samples/iam_v2beta_generated_policies_update_policy_sync.py +++ b/samples/generated_samples/iam_v2beta_generated_policies_update_policy_sync.py @@ -24,6 +24,13 @@ # [START iam_v2beta_generated_Policies_UpdatePolicy_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 iam_v2beta diff --git a/samples/generated_samples/iamcredentials_v1_generated_iam_credentials_generate_access_token_async.py b/samples/generated_samples/iamcredentials_v1_generated_iam_credentials_generate_access_token_async.py index c684949..f3fe8e1 100644 --- a/samples/generated_samples/iamcredentials_v1_generated_iam_credentials_generate_access_token_async.py +++ b/samples/generated_samples/iamcredentials_v1_generated_iam_credentials_generate_access_token_async.py @@ -24,6 +24,13 @@ # [START iamcredentials_v1_generated_IAMCredentials_GenerateAccessToken_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 iam_credentials_v1 @@ -34,7 +41,7 @@ async def sample_generate_access_token(): # Initialize request argument(s) request = iam_credentials_v1.GenerateAccessTokenRequest( name="name_value", - scope=['scope_value_1', 'scope_value_2'], + scope=['scope_value1', 'scope_value2'], ) # Make the request diff --git a/samples/generated_samples/iamcredentials_v1_generated_iam_credentials_generate_access_token_sync.py b/samples/generated_samples/iamcredentials_v1_generated_iam_credentials_generate_access_token_sync.py index f50c4c2..93734d7 100644 --- a/samples/generated_samples/iamcredentials_v1_generated_iam_credentials_generate_access_token_sync.py +++ b/samples/generated_samples/iamcredentials_v1_generated_iam_credentials_generate_access_token_sync.py @@ -24,6 +24,13 @@ # [START iamcredentials_v1_generated_IAMCredentials_GenerateAccessToken_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 iam_credentials_v1 @@ -34,7 +41,7 @@ def sample_generate_access_token(): # Initialize request argument(s) request = iam_credentials_v1.GenerateAccessTokenRequest( name="name_value", - scope=['scope_value_1', 'scope_value_2'], + scope=['scope_value1', 'scope_value2'], ) # Make the request diff --git a/samples/generated_samples/iamcredentials_v1_generated_iam_credentials_generate_id_token_async.py b/samples/generated_samples/iamcredentials_v1_generated_iam_credentials_generate_id_token_async.py index e397afa..d2c90a2 100644 --- a/samples/generated_samples/iamcredentials_v1_generated_iam_credentials_generate_id_token_async.py +++ b/samples/generated_samples/iamcredentials_v1_generated_iam_credentials_generate_id_token_async.py @@ -24,6 +24,13 @@ # [START iamcredentials_v1_generated_IAMCredentials_GenerateIdToken_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 iam_credentials_v1 diff --git a/samples/generated_samples/iamcredentials_v1_generated_iam_credentials_generate_id_token_sync.py b/samples/generated_samples/iamcredentials_v1_generated_iam_credentials_generate_id_token_sync.py index 2b57c7b..4e4781a 100644 --- a/samples/generated_samples/iamcredentials_v1_generated_iam_credentials_generate_id_token_sync.py +++ b/samples/generated_samples/iamcredentials_v1_generated_iam_credentials_generate_id_token_sync.py @@ -24,6 +24,13 @@ # [START iamcredentials_v1_generated_IAMCredentials_GenerateIdToken_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 iam_credentials_v1 diff --git a/samples/generated_samples/iamcredentials_v1_generated_iam_credentials_sign_blob_async.py b/samples/generated_samples/iamcredentials_v1_generated_iam_credentials_sign_blob_async.py index 630be24..dc9c951 100644 --- a/samples/generated_samples/iamcredentials_v1_generated_iam_credentials_sign_blob_async.py +++ b/samples/generated_samples/iamcredentials_v1_generated_iam_credentials_sign_blob_async.py @@ -24,6 +24,13 @@ # [START iamcredentials_v1_generated_IAMCredentials_SignBlob_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 iam_credentials_v1 diff --git a/samples/generated_samples/iamcredentials_v1_generated_iam_credentials_sign_blob_sync.py b/samples/generated_samples/iamcredentials_v1_generated_iam_credentials_sign_blob_sync.py index bb648cc..568b02d 100644 --- a/samples/generated_samples/iamcredentials_v1_generated_iam_credentials_sign_blob_sync.py +++ b/samples/generated_samples/iamcredentials_v1_generated_iam_credentials_sign_blob_sync.py @@ -24,6 +24,13 @@ # [START iamcredentials_v1_generated_IAMCredentials_SignBlob_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 iam_credentials_v1 diff --git a/samples/generated_samples/iamcredentials_v1_generated_iam_credentials_sign_jwt_async.py b/samples/generated_samples/iamcredentials_v1_generated_iam_credentials_sign_jwt_async.py index bf2bf75..7fc15ec 100644 --- a/samples/generated_samples/iamcredentials_v1_generated_iam_credentials_sign_jwt_async.py +++ b/samples/generated_samples/iamcredentials_v1_generated_iam_credentials_sign_jwt_async.py @@ -24,6 +24,13 @@ # [START iamcredentials_v1_generated_IAMCredentials_SignJwt_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 iam_credentials_v1 diff --git a/samples/generated_samples/iamcredentials_v1_generated_iam_credentials_sign_jwt_sync.py b/samples/generated_samples/iamcredentials_v1_generated_iam_credentials_sign_jwt_sync.py index b222e94..181fc05 100644 --- a/samples/generated_samples/iamcredentials_v1_generated_iam_credentials_sign_jwt_sync.py +++ b/samples/generated_samples/iamcredentials_v1_generated_iam_credentials_sign_jwt_sync.py @@ -24,6 +24,13 @@ # [START iamcredentials_v1_generated_IAMCredentials_SignJwt_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 iam_credentials_v1 diff --git a/samples/generated_samples/snippet_metadata_iam credentials_v1.json b/samples/generated_samples/snippet_metadata_iam credentials_v1.json index 83952f7..2f4e976 100644 --- a/samples/generated_samples/snippet_metadata_iam credentials_v1.json +++ b/samples/generated_samples/snippet_metadata_iam credentials_v1.json @@ -71,33 +71,33 @@ "regionTag": "iamcredentials_v1_generated_IAMCredentials_GenerateAccessToken_async", "segments": [ { - "end": 45, + "end": 52, "start": 27, "type": "FULL" }, { - "end": 45, + "end": 52, "start": 27, "type": "SHORT" }, { - "end": 33, - "start": 31, + "end": 40, + "start": 38, "type": "CLIENT_INITIALIZATION" }, { - "end": 39, - "start": 34, + "end": 46, + "start": 41, "type": "REQUEST_INITIALIZATION" }, { - "end": 42, - "start": 40, + "end": 49, + "start": 47, "type": "REQUEST_EXECUTION" }, { - "end": 46, - "start": 43, + "end": 53, + "start": 50, "type": "RESPONSE_HANDLING" } ], @@ -163,33 +163,33 @@ "regionTag": "iamcredentials_v1_generated_IAMCredentials_GenerateAccessToken_sync", "segments": [ { - "end": 45, + "end": 52, "start": 27, "type": "FULL" }, { - "end": 45, + "end": 52, "start": 27, "type": "SHORT" }, { - "end": 33, - "start": 31, + "end": 40, + "start": 38, "type": "CLIENT_INITIALIZATION" }, { - "end": 39, - "start": 34, + "end": 46, + "start": 41, "type": "REQUEST_INITIALIZATION" }, { - "end": 42, - "start": 40, + "end": 49, + "start": 47, "type": "REQUEST_EXECUTION" }, { - "end": 46, - "start": 43, + "end": 53, + "start": 50, "type": "RESPONSE_HANDLING" } ], @@ -256,33 +256,33 @@ "regionTag": "iamcredentials_v1_generated_IAMCredentials_GenerateIdToken_async", "segments": [ { - "end": 45, + "end": 52, "start": 27, "type": "FULL" }, { - "end": 45, + "end": 52, "start": 27, "type": "SHORT" }, { - "end": 33, - "start": 31, + "end": 40, + "start": 38, "type": "CLIENT_INITIALIZATION" }, { - "end": 39, - "start": 34, + "end": 46, + "start": 41, "type": "REQUEST_INITIALIZATION" }, { - "end": 42, - "start": 40, + "end": 49, + "start": 47, "type": "REQUEST_EXECUTION" }, { - "end": 46, - "start": 43, + "end": 53, + "start": 50, "type": "RESPONSE_HANDLING" } ], @@ -348,33 +348,33 @@ "regionTag": "iamcredentials_v1_generated_IAMCredentials_GenerateIdToken_sync", "segments": [ { - "end": 45, + "end": 52, "start": 27, "type": "FULL" }, { - "end": 45, + "end": 52, "start": 27, "type": "SHORT" }, { - "end": 33, - "start": 31, + "end": 40, + "start": 38, "type": "CLIENT_INITIALIZATION" }, { - "end": 39, - "start": 34, + "end": 46, + "start": 41, "type": "REQUEST_INITIALIZATION" }, { - "end": 42, - "start": 40, + "end": 49, + "start": 47, "type": "REQUEST_EXECUTION" }, { - "end": 46, - "start": 43, + "end": 53, + "start": 50, "type": "RESPONSE_HANDLING" } ], @@ -437,33 +437,33 @@ "regionTag": "iamcredentials_v1_generated_IAMCredentials_SignBlob_async", "segments": [ { - "end": 45, + "end": 52, "start": 27, "type": "FULL" }, { - "end": 45, + "end": 52, "start": 27, "type": "SHORT" }, { - "end": 33, - "start": 31, + "end": 40, + "start": 38, "type": "CLIENT_INITIALIZATION" }, { - "end": 39, - "start": 34, + "end": 46, + "start": 41, "type": "REQUEST_INITIALIZATION" }, { - "end": 42, - "start": 40, + "end": 49, + "start": 47, "type": "REQUEST_EXECUTION" }, { - "end": 46, - "start": 43, + "end": 53, + "start": 50, "type": "RESPONSE_HANDLING" } ], @@ -525,33 +525,33 @@ "regionTag": "iamcredentials_v1_generated_IAMCredentials_SignBlob_sync", "segments": [ { - "end": 45, + "end": 52, "start": 27, "type": "FULL" }, { - "end": 45, + "end": 52, "start": 27, "type": "SHORT" }, { - "end": 33, - "start": 31, + "end": 40, + "start": 38, "type": "CLIENT_INITIALIZATION" }, { - "end": 39, - "start": 34, + "end": 46, + "start": 41, "type": "REQUEST_INITIALIZATION" }, { - "end": 42, - "start": 40, + "end": 49, + "start": 47, "type": "REQUEST_EXECUTION" }, { - "end": 46, - "start": 43, + "end": 53, + "start": 50, "type": "RESPONSE_HANDLING" } ], @@ -614,33 +614,33 @@ "regionTag": "iamcredentials_v1_generated_IAMCredentials_SignJwt_async", "segments": [ { - "end": 45, + "end": 52, "start": 27, "type": "FULL" }, { - "end": 45, + "end": 52, "start": 27, "type": "SHORT" }, { - "end": 33, - "start": 31, + "end": 40, + "start": 38, "type": "CLIENT_INITIALIZATION" }, { - "end": 39, - "start": 34, + "end": 46, + "start": 41, "type": "REQUEST_INITIALIZATION" }, { - "end": 42, - "start": 40, + "end": 49, + "start": 47, "type": "REQUEST_EXECUTION" }, { - "end": 46, - "start": 43, + "end": 53, + "start": 50, "type": "RESPONSE_HANDLING" } ], @@ -702,33 +702,33 @@ "regionTag": "iamcredentials_v1_generated_IAMCredentials_SignJwt_sync", "segments": [ { - "end": 45, + "end": 52, "start": 27, "type": "FULL" }, { - "end": 45, + "end": 52, "start": 27, "type": "SHORT" }, { - "end": 33, - "start": 31, + "end": 40, + "start": 38, "type": "CLIENT_INITIALIZATION" }, { - "end": 39, - "start": 34, + "end": 46, + "start": 41, "type": "REQUEST_INITIALIZATION" }, { - "end": 42, - "start": 40, + "end": 49, + "start": 47, "type": "REQUEST_EXECUTION" }, { - "end": 46, - "start": 43, + "end": 53, + "start": 50, "type": "RESPONSE_HANDLING" } ], diff --git a/samples/generated_samples/snippet_metadata_iam_v2.json b/samples/generated_samples/snippet_metadata_iam_v2.json new file mode 100644 index 0000000..9cd8be2 --- /dev/null +++ b/samples/generated_samples/snippet_metadata_iam_v2.json @@ -0,0 +1,827 @@ +{ + "clientLibrary": { + "apis": [ + { + "id": "google.iam.v2", + "version": "v2" + } + ], + "language": "PYTHON", + "name": "google-cloud-iam" + }, + "snippets": [ + { + "canonical": true, + "clientMethod": { + "async": true, + "client": { + "fullName": "google.cloud.iam_v2.PoliciesAsyncClient", + "shortName": "PoliciesAsyncClient" + }, + "fullName": "google.cloud.iam_v2.PoliciesAsyncClient.create_policy", + "method": { + "fullName": "google.iam.v2.Policies.CreatePolicy", + "service": { + "fullName": "google.iam.v2.Policies", + "shortName": "Policies" + }, + "shortName": "CreatePolicy" + }, + "parameters": [ + { + "name": "request", + "type": "google.cloud.iam_v2.types.CreatePolicyRequest" + }, + { + "name": "parent", + "type": "str" + }, + { + "name": "policy", + "type": "google.cloud.iam_v2.types.Policy" + }, + { + "name": "policy_id", + "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": "create_policy" + }, + "description": "Sample for CreatePolicy", + "file": "iam_v2_generated_policies_create_policy_async.py", + "language": "PYTHON", + "origin": "API_DEFINITION", + "regionTag": "iam_v2_generated_Policies_CreatePolicy_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": "iam_v2_generated_policies_create_policy_async.py" + }, + { + "canonical": true, + "clientMethod": { + "client": { + "fullName": "google.cloud.iam_v2.PoliciesClient", + "shortName": "PoliciesClient" + }, + "fullName": "google.cloud.iam_v2.PoliciesClient.create_policy", + "method": { + "fullName": "google.iam.v2.Policies.CreatePolicy", + "service": { + "fullName": "google.iam.v2.Policies", + "shortName": "Policies" + }, + "shortName": "CreatePolicy" + }, + "parameters": [ + { + "name": "request", + "type": "google.cloud.iam_v2.types.CreatePolicyRequest" + }, + { + "name": "parent", + "type": "str" + }, + { + "name": "policy", + "type": "google.cloud.iam_v2.types.Policy" + }, + { + "name": "policy_id", + "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": "create_policy" + }, + "description": "Sample for CreatePolicy", + "file": "iam_v2_generated_policies_create_policy_sync.py", + "language": "PYTHON", + "origin": "API_DEFINITION", + "regionTag": "iam_v2_generated_Policies_CreatePolicy_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": "iam_v2_generated_policies_create_policy_sync.py" + }, + { + "canonical": true, + "clientMethod": { + "async": true, + "client": { + "fullName": "google.cloud.iam_v2.PoliciesAsyncClient", + "shortName": "PoliciesAsyncClient" + }, + "fullName": "google.cloud.iam_v2.PoliciesAsyncClient.delete_policy", + "method": { + "fullName": "google.iam.v2.Policies.DeletePolicy", + "service": { + "fullName": "google.iam.v2.Policies", + "shortName": "Policies" + }, + "shortName": "DeletePolicy" + }, + "parameters": [ + { + "name": "request", + "type": "google.cloud.iam_v2.types.DeletePolicyRequest" + }, + { + "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_policy" + }, + "description": "Sample for DeletePolicy", + "file": "iam_v2_generated_policies_delete_policy_async.py", + "language": "PYTHON", + "origin": "API_DEFINITION", + "regionTag": "iam_v2_generated_Policies_DeletePolicy_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": "iam_v2_generated_policies_delete_policy_async.py" + }, + { + "canonical": true, + "clientMethod": { + "client": { + "fullName": "google.cloud.iam_v2.PoliciesClient", + "shortName": "PoliciesClient" + }, + "fullName": "google.cloud.iam_v2.PoliciesClient.delete_policy", + "method": { + "fullName": "google.iam.v2.Policies.DeletePolicy", + "service": { + "fullName": "google.iam.v2.Policies", + "shortName": "Policies" + }, + "shortName": "DeletePolicy" + }, + "parameters": [ + { + "name": "request", + "type": "google.cloud.iam_v2.types.DeletePolicyRequest" + }, + { + "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_policy" + }, + "description": "Sample for DeletePolicy", + "file": "iam_v2_generated_policies_delete_policy_sync.py", + "language": "PYTHON", + "origin": "API_DEFINITION", + "regionTag": "iam_v2_generated_Policies_DeletePolicy_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": "iam_v2_generated_policies_delete_policy_sync.py" + }, + { + "canonical": true, + "clientMethod": { + "async": true, + "client": { + "fullName": "google.cloud.iam_v2.PoliciesAsyncClient", + "shortName": "PoliciesAsyncClient" + }, + "fullName": "google.cloud.iam_v2.PoliciesAsyncClient.get_policy", + "method": { + "fullName": "google.iam.v2.Policies.GetPolicy", + "service": { + "fullName": "google.iam.v2.Policies", + "shortName": "Policies" + }, + "shortName": "GetPolicy" + }, + "parameters": [ + { + "name": "request", + "type": "google.cloud.iam_v2.types.GetPolicyRequest" + }, + { + "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.iam_v2.types.Policy", + "shortName": "get_policy" + }, + "description": "Sample for GetPolicy", + "file": "iam_v2_generated_policies_get_policy_async.py", + "language": "PYTHON", + "origin": "API_DEFINITION", + "regionTag": "iam_v2_generated_Policies_GetPolicy_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": "iam_v2_generated_policies_get_policy_async.py" + }, + { + "canonical": true, + "clientMethod": { + "client": { + "fullName": "google.cloud.iam_v2.PoliciesClient", + "shortName": "PoliciesClient" + }, + "fullName": "google.cloud.iam_v2.PoliciesClient.get_policy", + "method": { + "fullName": "google.iam.v2.Policies.GetPolicy", + "service": { + "fullName": "google.iam.v2.Policies", + "shortName": "Policies" + }, + "shortName": "GetPolicy" + }, + "parameters": [ + { + "name": "request", + "type": "google.cloud.iam_v2.types.GetPolicyRequest" + }, + { + "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.iam_v2.types.Policy", + "shortName": "get_policy" + }, + "description": "Sample for GetPolicy", + "file": "iam_v2_generated_policies_get_policy_sync.py", + "language": "PYTHON", + "origin": "API_DEFINITION", + "regionTag": "iam_v2_generated_Policies_GetPolicy_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": "iam_v2_generated_policies_get_policy_sync.py" + }, + { + "canonical": true, + "clientMethod": { + "async": true, + "client": { + "fullName": "google.cloud.iam_v2.PoliciesAsyncClient", + "shortName": "PoliciesAsyncClient" + }, + "fullName": "google.cloud.iam_v2.PoliciesAsyncClient.list_policies", + "method": { + "fullName": "google.iam.v2.Policies.ListPolicies", + "service": { + "fullName": "google.iam.v2.Policies", + "shortName": "Policies" + }, + "shortName": "ListPolicies" + }, + "parameters": [ + { + "name": "request", + "type": "google.cloud.iam_v2.types.ListPoliciesRequest" + }, + { + "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.iam_v2.services.policies.pagers.ListPoliciesAsyncPager", + "shortName": "list_policies" + }, + "description": "Sample for ListPolicies", + "file": "iam_v2_generated_policies_list_policies_async.py", + "language": "PYTHON", + "origin": "API_DEFINITION", + "regionTag": "iam_v2_generated_Policies_ListPolicies_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": "iam_v2_generated_policies_list_policies_async.py" + }, + { + "canonical": true, + "clientMethod": { + "client": { + "fullName": "google.cloud.iam_v2.PoliciesClient", + "shortName": "PoliciesClient" + }, + "fullName": "google.cloud.iam_v2.PoliciesClient.list_policies", + "method": { + "fullName": "google.iam.v2.Policies.ListPolicies", + "service": { + "fullName": "google.iam.v2.Policies", + "shortName": "Policies" + }, + "shortName": "ListPolicies" + }, + "parameters": [ + { + "name": "request", + "type": "google.cloud.iam_v2.types.ListPoliciesRequest" + }, + { + "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.iam_v2.services.policies.pagers.ListPoliciesPager", + "shortName": "list_policies" + }, + "description": "Sample for ListPolicies", + "file": "iam_v2_generated_policies_list_policies_sync.py", + "language": "PYTHON", + "origin": "API_DEFINITION", + "regionTag": "iam_v2_generated_Policies_ListPolicies_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": "iam_v2_generated_policies_list_policies_sync.py" + }, + { + "canonical": true, + "clientMethod": { + "async": true, + "client": { + "fullName": "google.cloud.iam_v2.PoliciesAsyncClient", + "shortName": "PoliciesAsyncClient" + }, + "fullName": "google.cloud.iam_v2.PoliciesAsyncClient.update_policy", + "method": { + "fullName": "google.iam.v2.Policies.UpdatePolicy", + "service": { + "fullName": "google.iam.v2.Policies", + "shortName": "Policies" + }, + "shortName": "UpdatePolicy" + }, + "parameters": [ + { + "name": "request", + "type": "google.cloud.iam_v2.types.UpdatePolicyRequest" + }, + { + "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_policy" + }, + "description": "Sample for UpdatePolicy", + "file": "iam_v2_generated_policies_update_policy_async.py", + "language": "PYTHON", + "origin": "API_DEFINITION", + "regionTag": "iam_v2_generated_Policies_UpdatePolicy_async", + "segments": [ + { + "end": 54, + "start": 27, + "type": "FULL" + }, + { + "end": 54, + "start": 27, + "type": "SHORT" + }, + { + "end": 40, + "start": 38, + "type": "CLIENT_INITIALIZATION" + }, + { + "end": 44, + "start": 41, + "type": "REQUEST_INITIALIZATION" + }, + { + "end": 51, + "start": 45, + "type": "REQUEST_EXECUTION" + }, + { + "end": 55, + "start": 52, + "type": "RESPONSE_HANDLING" + } + ], + "title": "iam_v2_generated_policies_update_policy_async.py" + }, + { + "canonical": true, + "clientMethod": { + "client": { + "fullName": "google.cloud.iam_v2.PoliciesClient", + "shortName": "PoliciesClient" + }, + "fullName": "google.cloud.iam_v2.PoliciesClient.update_policy", + "method": { + "fullName": "google.iam.v2.Policies.UpdatePolicy", + "service": { + "fullName": "google.iam.v2.Policies", + "shortName": "Policies" + }, + "shortName": "UpdatePolicy" + }, + "parameters": [ + { + "name": "request", + "type": "google.cloud.iam_v2.types.UpdatePolicyRequest" + }, + { + "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_policy" + }, + "description": "Sample for UpdatePolicy", + "file": "iam_v2_generated_policies_update_policy_sync.py", + "language": "PYTHON", + "origin": "API_DEFINITION", + "regionTag": "iam_v2_generated_Policies_UpdatePolicy_sync", + "segments": [ + { + "end": 54, + "start": 27, + "type": "FULL" + }, + { + "end": 54, + "start": 27, + "type": "SHORT" + }, + { + "end": 40, + "start": 38, + "type": "CLIENT_INITIALIZATION" + }, + { + "end": 44, + "start": 41, + "type": "REQUEST_INITIALIZATION" + }, + { + "end": 51, + "start": 45, + "type": "REQUEST_EXECUTION" + }, + { + "end": 55, + "start": 52, + "type": "RESPONSE_HANDLING" + } + ], + "title": "iam_v2_generated_policies_update_policy_sync.py" + } + ] +} diff --git a/samples/generated_samples/snippet_metadata_iam_v2beta.json b/samples/generated_samples/snippet_metadata_iam_v2beta.json index 7e2e68f..bb12148 100644 --- a/samples/generated_samples/snippet_metadata_iam_v2beta.json +++ b/samples/generated_samples/snippet_metadata_iam_v2beta.json @@ -67,33 +67,33 @@ "regionTag": "iam_v2beta_generated_Policies_CreatePolicy_async", "segments": [ { - "end": 48, + "end": 55, "start": 27, "type": "FULL" }, { - "end": 48, + "end": 55, "start": 27, "type": "SHORT" }, { - "end": 33, - "start": 31, + "end": 40, + "start": 38, "type": "CLIENT_INITIALIZATION" }, { - "end": 38, - "start": 34, + "end": 45, + "start": 41, "type": "REQUEST_INITIALIZATION" }, { - "end": 45, - "start": 39, + "end": 52, + "start": 46, "type": "REQUEST_EXECUTION" }, { - "end": 49, - "start": 46, + "end": 56, + "start": 53, "type": "RESPONSE_HANDLING" } ], @@ -155,33 +155,33 @@ "regionTag": "iam_v2beta_generated_Policies_CreatePolicy_sync", "segments": [ { - "end": 48, + "end": 55, "start": 27, "type": "FULL" }, { - "end": 48, + "end": 55, "start": 27, "type": "SHORT" }, { - "end": 33, - "start": 31, + "end": 40, + "start": 38, "type": "CLIENT_INITIALIZATION" }, { - "end": 38, - "start": 34, + "end": 45, + "start": 41, "type": "REQUEST_INITIALIZATION" }, { - "end": 45, - "start": 39, + "end": 52, + "start": 46, "type": "REQUEST_EXECUTION" }, { - "end": 49, - "start": 46, + "end": 56, + "start": 53, "type": "RESPONSE_HANDLING" } ], @@ -236,33 +236,33 @@ "regionTag": "iam_v2beta_generated_Policies_DeletePolicy_async", "segments": [ { - "end": 48, + "end": 55, "start": 27, "type": "FULL" }, { - "end": 48, + "end": 55, "start": 27, "type": "SHORT" }, { - "end": 33, - "start": 31, + "end": 40, + "start": 38, "type": "CLIENT_INITIALIZATION" }, { - "end": 38, - "start": 34, + "end": 45, + "start": 41, "type": "REQUEST_INITIALIZATION" }, { - "end": 45, - "start": 39, + "end": 52, + "start": 46, "type": "REQUEST_EXECUTION" }, { - "end": 49, - "start": 46, + "end": 56, + "start": 53, "type": "RESPONSE_HANDLING" } ], @@ -316,33 +316,33 @@ "regionTag": "iam_v2beta_generated_Policies_DeletePolicy_sync", "segments": [ { - "end": 48, + "end": 55, "start": 27, "type": "FULL" }, { - "end": 48, + "end": 55, "start": 27, "type": "SHORT" }, { - "end": 33, - "start": 31, + "end": 40, + "start": 38, "type": "CLIENT_INITIALIZATION" }, { - "end": 38, - "start": 34, + "end": 45, + "start": 41, "type": "REQUEST_INITIALIZATION" }, { - "end": 45, - "start": 39, + "end": 52, + "start": 46, "type": "REQUEST_EXECUTION" }, { - "end": 49, - "start": 46, + "end": 56, + "start": 53, "type": "RESPONSE_HANDLING" } ], @@ -397,33 +397,33 @@ "regionTag": "iam_v2beta_generated_Policies_GetPolicy_async", "segments": [ { - "end": 44, + "end": 51, "start": 27, "type": "FULL" }, { - "end": 44, + "end": 51, "start": 27, "type": "SHORT" }, { - "end": 33, - "start": 31, + "end": 40, + "start": 38, "type": "CLIENT_INITIALIZATION" }, { - "end": 38, - "start": 34, + "end": 45, + "start": 41, "type": "REQUEST_INITIALIZATION" }, { - "end": 41, - "start": 39, + "end": 48, + "start": 46, "type": "REQUEST_EXECUTION" }, { - "end": 45, - "start": 42, + "end": 52, + "start": 49, "type": "RESPONSE_HANDLING" } ], @@ -477,33 +477,33 @@ "regionTag": "iam_v2beta_generated_Policies_GetPolicy_sync", "segments": [ { - "end": 44, + "end": 51, "start": 27, "type": "FULL" }, { - "end": 44, + "end": 51, "start": 27, "type": "SHORT" }, { - "end": 33, - "start": 31, + "end": 40, + "start": 38, "type": "CLIENT_INITIALIZATION" }, { - "end": 38, - "start": 34, + "end": 45, + "start": 41, "type": "REQUEST_INITIALIZATION" }, { - "end": 41, - "start": 39, + "end": 48, + "start": 46, "type": "REQUEST_EXECUTION" }, { - "end": 45, - "start": 42, + "end": 52, + "start": 49, "type": "RESPONSE_HANDLING" } ], @@ -558,33 +558,33 @@ "regionTag": "iam_v2beta_generated_Policies_ListPolicies_async", "segments": [ { - "end": 45, + "end": 52, "start": 27, "type": "FULL" }, { - "end": 45, + "end": 52, "start": 27, "type": "SHORT" }, { - "end": 33, - "start": 31, + "end": 40, + "start": 38, "type": "CLIENT_INITIALIZATION" }, { - "end": 38, - "start": 34, + "end": 45, + "start": 41, "type": "REQUEST_INITIALIZATION" }, { - "end": 41, - "start": 39, + "end": 48, + "start": 46, "type": "REQUEST_EXECUTION" }, { - "end": 46, - "start": 42, + "end": 53, + "start": 49, "type": "RESPONSE_HANDLING" } ], @@ -638,33 +638,33 @@ "regionTag": "iam_v2beta_generated_Policies_ListPolicies_sync", "segments": [ { - "end": 45, + "end": 52, "start": 27, "type": "FULL" }, { - "end": 45, + "end": 52, "start": 27, "type": "SHORT" }, { - "end": 33, - "start": 31, + "end": 40, + "start": 38, "type": "CLIENT_INITIALIZATION" }, { - "end": 38, - "start": 34, + "end": 45, + "start": 41, "type": "REQUEST_INITIALIZATION" }, { - "end": 41, - "start": 39, + "end": 48, + "start": 46, "type": "REQUEST_EXECUTION" }, { - "end": 46, - "start": 42, + "end": 53, + "start": 49, "type": "RESPONSE_HANDLING" } ], @@ -715,33 +715,33 @@ "regionTag": "iam_v2beta_generated_Policies_UpdatePolicy_async", "segments": [ { - "end": 47, + "end": 54, "start": 27, "type": "FULL" }, { - "end": 47, + "end": 54, "start": 27, "type": "SHORT" }, { - "end": 33, - "start": 31, + "end": 40, + "start": 38, "type": "CLIENT_INITIALIZATION" }, { - "end": 37, - "start": 34, + "end": 44, + "start": 41, "type": "REQUEST_INITIALIZATION" }, { - "end": 44, - "start": 38, + "end": 51, + "start": 45, "type": "REQUEST_EXECUTION" }, { - "end": 48, - "start": 45, + "end": 55, + "start": 52, "type": "RESPONSE_HANDLING" } ], @@ -791,33 +791,33 @@ "regionTag": "iam_v2beta_generated_Policies_UpdatePolicy_sync", "segments": [ { - "end": 47, + "end": 54, "start": 27, "type": "FULL" }, { - "end": 47, + "end": 54, "start": 27, "type": "SHORT" }, { - "end": 33, - "start": 31, + "end": 40, + "start": 38, "type": "CLIENT_INITIALIZATION" }, { - "end": 37, - "start": 34, + "end": 44, + "start": 41, "type": "REQUEST_INITIALIZATION" }, { - "end": 44, - "start": 38, + "end": 51, + "start": 45, "type": "REQUEST_EXECUTION" }, { - "end": 48, - "start": 45, + "end": 55, + "start": 52, "type": "RESPONSE_HANDLING" } ], diff --git a/samples/snippets/conftest.py b/samples/snippets/conftest.py index 8dd0625..4fa0dea 100644 --- a/samples/snippets/conftest.py +++ b/samples/snippets/conftest.py @@ -16,19 +16,22 @@ import re import uuid -from _pytest.capture import CaptureFixture +from google.cloud import iam_v2 +from google.cloud.iam_v2 import types import pytest - -from create_deny_policy import create_deny_policy -from delete_deny_policy import delete_deny_policy +from samples.snippets.create_deny_policy import create_deny_policy +from samples.snippets.delete_deny_policy import delete_deny_policy PROJECT_ID = os.environ["GOOGLE_CLOUD_PROJECT"] GOOGLE_APPLICATION_CREDENTIALS = os.environ["GOOGLE_APPLICATION_CREDENTIALS"] @pytest.fixture -def deny_policy(capsys: CaptureFixture) -> None: - policy_id = f"limit-project-deletion-{uuid.uuid4()}" +def deny_policy(capsys: "pytest.CaptureFixture[str]") -> None: + policy_id = f"test-deny-policy-{uuid.uuid4()}" + + # Delete any existing policies. Otherwise it might throw quota issue. + delete_existing_deny_policies(PROJECT_ID, "test-deny-policy") # Create the Deny policy. create_deny_policy(PROJECT_ID, policy_id) @@ -39,3 +42,15 @@ def deny_policy(capsys: CaptureFixture) -> None: delete_deny_policy(PROJECT_ID, policy_id) out, _ = capsys.readouterr() assert re.search(f"Deleted the deny policy: {policy_id}", out) + + +def delete_existing_deny_policies(project_id: str, delete_name_prefix: str) -> None: + policies_client = iam_v2.PoliciesClient() + + attachment_point = f"cloudresourcemanager.googleapis.com%2Fprojects%2F{project_id}" + + request = types.ListPoliciesRequest() + request.parent = f"policies/{attachment_point}/denypolicies" + for policy in policies_client.list_policies(request=request): + if delete_name_prefix in policy.name: + delete_deny_policy(PROJECT_ID, str(policy.name).rsplit("/", 1)[-1]) diff --git a/samples/snippets/create_deny_policy.py b/samples/snippets/create_deny_policy.py index 1cc5e5b..569e55e 100644 --- a/samples/snippets/create_deny_policy.py +++ b/samples/snippets/create_deny_policy.py @@ -18,9 +18,8 @@ def create_deny_policy(project_id: str, policy_id: str) -> None: - from google.cloud import iam_v2beta - from google.cloud.iam_v2beta import types - from google.type import expr_pb2 + from google.cloud import iam_v2 + from google.cloud.iam_v2 import types """ Create a deny policy. @@ -36,7 +35,7 @@ def create_deny_policy(project_id: str, policy_id: str) -> None: project_id: ID or number of the Google Cloud project you want to use. policy_id: Specify the ID of the deny policy you want to create. """ - policies_client = iam_v2beta.PoliciesClient() + policies_client = iam_v2.PoliciesClient() # Each deny policy is attached to an organization, folder, or project. # To work with deny policies, specify the attachment point. @@ -100,9 +99,9 @@ def create_deny_policy(project_id: str, policy_id: str) -> None: request.policy = policy request.policy_id = policy_id - # Build the create policy request. - policies_client.create_policy(request=request) - print(f"Created the deny policy: {policy_id}") + # Build the create policy request and wait for the operation to complete. + result = policies_client.create_policy(request=request).result() + print(f"Created the deny policy: {result.name.rsplit('/')[-1]}") if __name__ == "__main__": diff --git a/samples/snippets/delete_deny_policy.py b/samples/snippets/delete_deny_policy.py index 769d8d2..e7128dc 100644 --- a/samples/snippets/delete_deny_policy.py +++ b/samples/snippets/delete_deny_policy.py @@ -16,8 +16,8 @@ # [START iam_delete_deny_policy] def delete_deny_policy(project_id: str, policy_id: str) -> None: - from google.cloud import iam_v2beta - from google.cloud.iam_v2beta import types + from google.cloud import iam_v2 + from google.cloud.iam_v2 import types """ Delete the policy if you no longer want to enforce the rules in a deny policy. @@ -25,7 +25,7 @@ def delete_deny_policy(project_id: str, policy_id: str) -> None: project_id: ID or number of the Google Cloud project you want to use. policy_id: The ID of the deny policy you want to retrieve. """ - policies_client = iam_v2beta.PoliciesClient() + policies_client = iam_v2.PoliciesClient() # Each deny policy is attached to an organization, folder, or project. # To work with deny policies, specify the attachment point. @@ -45,8 +45,8 @@ def delete_deny_policy(project_id: str, policy_id: str) -> None: request.name = f"policies/{attachment_point}/denypolicies/{policy_id}" # Create the DeletePolicy request. - policies_client.delete_policy(request=request) - print(f"Deleted the deny policy: {policy_id}") + result = policies_client.delete_policy(request=request).result() + print(f"Deleted the deny policy: {result.name.rsplit('/')[-1]}") if __name__ == "__main__": diff --git a/samples/snippets/get_deny_policy.py b/samples/snippets/get_deny_policy.py index 05183cf..9f451fb 100644 --- a/samples/snippets/get_deny_policy.py +++ b/samples/snippets/get_deny_policy.py @@ -15,17 +15,18 @@ # This file contains code samples that demonstrate how to get IAM deny policies. # [START iam_get_deny_policy] -def get_deny_policy(project_id: str, policy_id: str): - from google.cloud import iam_v2beta - from google.cloud.iam_v2beta import Policy, types +from google.cloud import iam_v2 +from google.cloud.iam_v2 import Policy, types + +def get_deny_policy(project_id: str, policy_id: str) -> Policy: """ Retrieve the deny policy given the project ID and policy ID. project_id: ID or number of the Google Cloud project you want to use. policy_id: The ID of the deny policy you want to retrieve. """ - policies_client = iam_v2beta.PoliciesClient() + policies_client = iam_v2.PoliciesClient() # Each deny policy is attached to an organization, folder, or project. # To work with deny policies, specify the attachment point. diff --git a/samples/snippets/list_deny_policies.py b/samples/snippets/list_deny_policies.py index c83eac9..106794f 100644 --- a/samples/snippets/list_deny_policies.py +++ b/samples/snippets/list_deny_policies.py @@ -16,8 +16,8 @@ # [START iam_list_deny_policy] def list_deny_policy(project_id: str) -> None: - from google.cloud import iam_v2beta - from google.cloud.iam_v2beta import types + from google.cloud import iam_v2 + from google.cloud.iam_v2 import types """ List all the deny policies that are attached to a resource. @@ -25,7 +25,7 @@ def list_deny_policy(project_id: str) -> None: project_id: ID or number of the Google Cloud project you want to use. """ - policies_client = iam_v2beta.PoliciesClient() + policies_client = iam_v2.PoliciesClient() # Each deny policy is attached to an organization, folder, or project. # To work with deny policies, specify the attachment point. diff --git a/samples/snippets/noxfile.py b/samples/snippets/noxfile.py index e9eb1cb..c171513 100644 --- a/samples/snippets/noxfile.py +++ b/samples/snippets/noxfile.py @@ -207,8 +207,10 @@ def _session_tests( session: nox.sessions.Session, post_install: Callable = None ) -> None: # check for presence of tests - test_list = glob.glob("*_test.py") + glob.glob("test_*.py") - test_list.extend(glob.glob("tests")) + test_list = glob.glob("**/*_test.py", recursive=True) + glob.glob( + "**/test_*.py", recursive=True + ) + test_list.extend(glob.glob("**/tests", recursive=True)) if len(test_list) == 0: print("No tests found, skipping directory.") diff --git a/samples/snippets/noxfile_config.py b/samples/snippets/noxfile_config.py index 4fdb52d..e892b33 100644 --- a/samples/snippets/noxfile_config.py +++ b/samples/snippets/noxfile_config.py @@ -31,7 +31,7 @@ # build specific Cloud project. You can also use your own string # to use your own Cloud project. # "gcloud_project_env": "GOOGLE_CLOUD_PROJECT", - "gcloud_project_env": "BUILD_SPECIFIC_GCLOUD_PROJECT", + "gcloud_project_env": "GOOGLE_CLOUD_PROJECT", # A dictionary you want to inject into your test. Don't put any # secrets here. These values will override predefined values. "envs": {}, diff --git a/samples/snippets/requirements-test.txt b/samples/snippets/requirements-test.txt new file mode 100644 index 0000000..d00689e --- /dev/null +++ b/samples/snippets/requirements-test.txt @@ -0,0 +1 @@ +pytest==7.1.2 diff --git a/samples/snippets/requirements.txt b/samples/snippets/requirements.txt index a52b935..bf3945c 100644 --- a/samples/snippets/requirements.txt +++ b/samples/snippets/requirements.txt @@ -1 +1 @@ -google-cloud-iam==2.8.1 \ No newline at end of file +google-cloud-iam==2.8.2 \ No newline at end of file diff --git a/samples/snippets/test_deny_policies.py b/samples/snippets/test_deny_policies.py index 3a5bb57..f6f50cb 100644 --- a/samples/snippets/test_deny_policies.py +++ b/samples/snippets/test_deny_policies.py @@ -15,23 +15,25 @@ import os import re -from _pytest.capture import CaptureFixture +import pytest from samples.snippets.get_deny_policy import get_deny_policy from samples.snippets.list_deny_policies import list_deny_policy from samples.snippets.update_deny_policy import update_deny_policy -PROJECT_ID = os.environ["PROJECT_ID"] +PROJECT_ID = os.environ["GOOGLE_CLOUD_PROJECT"] GOOGLE_APPLICATION_CREDENTIALS = os.environ["GOOGLE_APPLICATION_CREDENTIALS"] -def test_retrieve_policy(capsys: CaptureFixture, deny_policy) -> None: +def test_retrieve_policy( + capsys: "pytest.CaptureFixture[str]", deny_policy: str +) -> None: # Test policy retrieval, given the policy id. get_deny_policy(PROJECT_ID, deny_policy) out, _ = capsys.readouterr() assert re.search(f"Retrieved the deny policy: {deny_policy}", out) -def test_list_policies(capsys: CaptureFixture, deny_policy) -> None: +def test_list_policies(capsys: "pytest.CaptureFixture[str]", deny_policy: str) -> None: # Check if the created policy is listed. list_deny_policy(PROJECT_ID) out, _ = capsys.readouterr() @@ -39,7 +41,9 @@ def test_list_policies(capsys: CaptureFixture, deny_policy) -> None: assert re.search("Listed all deny policies", out) -def test_update_deny_policy(capsys: CaptureFixture, deny_policy) -> None: +def test_update_deny_policy( + capsys: "pytest.CaptureFixture[str]", deny_policy: str +) -> None: # Check if the policy rule is updated. policy = get_deny_policy(PROJECT_ID, deny_policy) update_deny_policy(PROJECT_ID, deny_policy, policy.etag) diff --git a/samples/snippets/update_deny_policy.py b/samples/snippets/update_deny_policy.py index d3b8477..3756c0b 100644 --- a/samples/snippets/update_deny_policy.py +++ b/samples/snippets/update_deny_policy.py @@ -16,9 +16,8 @@ # [START iam_update_deny_policy] def update_deny_policy(project_id: str, policy_id: str, etag: str) -> None: - from google.cloud import iam_v2beta - from google.cloud.iam_v2beta import types - from google.type import expr_pb2 + from google.cloud import iam_v2 + from google.cloud.iam_v2 import types """ Update the deny rules and/ or its display name after policy creation. @@ -30,7 +29,7 @@ def update_deny_policy(project_id: str, policy_id: str, etag: str) -> None: etag: Etag field that identifies the policy version. The etag changes each time you update the policy. Get the etag of an existing policy by performing a GetPolicy request. """ - policies_client = iam_v2beta.PoliciesClient() + policies_client = iam_v2.PoliciesClient() # Each deny policy is attached to an organization, folder, or project. # To work with deny policies, specify the attachment point. @@ -94,8 +93,8 @@ def update_deny_policy(project_id: str, policy_id: str, etag: str) -> None: request = types.UpdatePolicyRequest() request.policy = policy - policies_client.update_policy(request=request) - print(f"Updated the deny policy: {policy_id}") + result = policies_client.update_policy(request=request).result() + print(f"Updated the deny policy: {result.name.rsplit('/')[-1]}") if __name__ == "__main__": diff --git a/scripts/fixup_iam_v2_keywords.py b/scripts/fixup_iam_v2_keywords.py new file mode 100644 index 0000000..23d3d6d --- /dev/null +++ b/scripts/fixup_iam_v2_keywords.py @@ -0,0 +1,180 @@ +#! /usr/bin/env python3 +# -*- 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 argparse +import os +import libcst as cst +import pathlib +import sys +from typing import (Any, Callable, Dict, List, Sequence, Tuple) + + +def partition( + predicate: Callable[[Any], bool], + iterator: Sequence[Any] +) -> Tuple[List[Any], List[Any]]: + """A stable, out-of-place partition.""" + results = ([], []) + + for i in iterator: + results[int(predicate(i))].append(i) + + # Returns trueList, falseList + return results[1], results[0] + + +class iamCallTransformer(cst.CSTTransformer): + CTRL_PARAMS: Tuple[str] = ('retry', 'timeout', 'metadata') + METHOD_TO_PARAMS: Dict[str, Tuple[str]] = { + 'create_policy': ('parent', 'policy', 'policy_id', ), + 'delete_policy': ('name', 'etag', ), + 'get_policy': ('name', ), + 'list_policies': ('parent', 'page_size', 'page_token', ), + 'update_policy': ('policy', ), + } + + def leave_Call(self, original: cst.Call, updated: cst.Call) -> cst.CSTNode: + try: + key = original.func.attr.value + kword_params = self.METHOD_TO_PARAMS[key] + except (AttributeError, KeyError): + # Either not a method from the API or too convoluted to be sure. + return updated + + # If the existing code is valid, keyword args come after positional args. + # Therefore, all positional args must map to the first parameters. + args, kwargs = partition(lambda a: not bool(a.keyword), updated.args) + if any(k.keyword.value == "request" for k in kwargs): + # We've already fixed this file, don't fix it again. + return updated + + kwargs, ctrl_kwargs = partition( + lambda a: a.keyword.value not in self.CTRL_PARAMS, + kwargs + ) + + args, ctrl_args = args[:len(kword_params)], args[len(kword_params):] + ctrl_kwargs.extend(cst.Arg(value=a.value, keyword=cst.Name(value=ctrl)) + for a, ctrl in zip(ctrl_args, self.CTRL_PARAMS)) + + request_arg = cst.Arg( + value=cst.Dict([ + cst.DictElement( + cst.SimpleString("'{}'".format(name)), +cst.Element(value=arg.value) + ) + # Note: the args + kwargs looks silly, but keep in mind that + # the control parameters had to be stripped out, and that + # those could have been passed positionally or by keyword. + for name, arg in zip(kword_params, args + kwargs)]), + keyword=cst.Name("request") + ) + + return updated.with_changes( + args=[request_arg] + ctrl_kwargs + ) + + +def fix_files( + in_dir: pathlib.Path, + out_dir: pathlib.Path, + *, + transformer=iamCallTransformer(), +): + """Duplicate the input dir to the output dir, fixing file method calls. + + Preconditions: + * in_dir is a real directory + * out_dir is a real, empty directory + """ + pyfile_gen = ( + pathlib.Path(os.path.join(root, f)) + for root, _, files in os.walk(in_dir) + for f in files if os.path.splitext(f)[1] == ".py" + ) + + for fpath in pyfile_gen: + with open(fpath, 'r') as f: + src = f.read() + + # Parse the code and insert method call fixes. + tree = cst.parse_module(src) + updated = tree.visit(transformer) + + # Create the path and directory structure for the new file. + updated_path = out_dir.joinpath(fpath.relative_to(in_dir)) + updated_path.parent.mkdir(parents=True, exist_ok=True) + + # Generate the updated source file at the corresponding path. + with open(updated_path, 'w') as f: + f.write(updated.code) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser( + description="""Fix up source that uses the iam client library. + +The existing sources are NOT overwritten but are copied to output_dir with changes made. + +Note: This tool operates at a best-effort level at converting positional + parameters in client method calls to keyword based parameters. + Cases where it WILL FAIL include + A) * or ** expansion in a method call. + B) Calls via function or method alias (includes free function calls) + C) Indirect or dispatched calls (e.g. the method is looked up dynamically) + + These all constitute false negatives. The tool will also detect false + positives when an API method shares a name with another method. +""") + parser.add_argument( + '-d', + '--input-directory', + required=True, + dest='input_dir', + help='the input directory to walk for python files to fix up', + ) + parser.add_argument( + '-o', + '--output-directory', + required=True, + dest='output_dir', + help='the directory to output files fixed via un-flattening', + ) + args = parser.parse_args() + input_dir = pathlib.Path(args.input_dir) + output_dir = pathlib.Path(args.output_dir) + if not input_dir.is_dir(): + print( + f"input directory '{input_dir}' does not exist or is not a directory", + file=sys.stderr, + ) + sys.exit(-1) + + if not output_dir.is_dir(): + print( + f"output directory '{output_dir}' does not exist or is not a directory", + file=sys.stderr, + ) + sys.exit(-1) + + if os.listdir(output_dir): + print( + f"output directory '{output_dir}' is not empty", + file=sys.stderr, + ) + sys.exit(-1) + + fix_files(input_dir, output_dir) diff --git a/setup.py b/setup.py index 088f1fd..befda59 100644 --- a/setup.py +++ b/setup.py @@ -21,7 +21,7 @@ name = "google-cloud-iam" description = "IAM Service Account Credentials API client library" -version = "2.8.2" +version = "2.9.0" # Should be one of: # 'Development Status :: 3 - Alpha' # 'Development Status :: 4 - Beta' @@ -30,7 +30,7 @@ dependencies = [ "google-api-core[grpc] >= 1.32.0, <3.0.0dev,!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*", "proto-plus >= 1.22.0, <2.0.0dev", - "protobuf >= 3.19.0, <5.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", ] package_root = os.path.abspath(os.path.dirname(__file__)) diff --git a/testing/constraints-3.7.txt b/testing/constraints-3.7.txt index 51901fb..5dcaa6f 100644 --- a/testing/constraints-3.7.txt +++ b/testing/constraints-3.7.txt @@ -7,4 +7,4 @@ # Then this file should have foo==1.14.0 google-api-core==1.32.0 proto-plus==1.22.0 -protobuf==3.19.0 +protobuf==3.19.5 diff --git a/tests/unit/gapic/iam_credentials_v1/test_iam_credentials.py b/tests/unit/gapic/iam_credentials_v1/test_iam_credentials.py index 0bc68a1..1bb7d75 100644 --- a/tests/unit/gapic/iam_credentials_v1/test_iam_credentials.py +++ b/tests/unit/gapic/iam_credentials_v1/test_iam_credentials.py @@ -18,8 +18,8 @@ # try/except added for compatibility with python < 3.8 try: from unittest import mock - from unittest.mock import AsyncMock -except ImportError: + from unittest.mock import AsyncMock # pragma: NO COVER +except ImportError: # pragma: NO COVER import mock import math @@ -35,6 +35,7 @@ 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 diff --git a/tests/unit/gapic/iam_v2/__init__.py b/tests/unit/gapic/iam_v2/__init__.py new file mode 100644 index 0000000..e8e1c38 --- /dev/null +++ b/tests/unit/gapic/iam_v2/__init__.py @@ -0,0 +1,15 @@ +# -*- 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. +# diff --git a/tests/unit/gapic/iam_v2/test_policies.py b/tests/unit/gapic/iam_v2/test_policies.py new file mode 100644 index 0000000..f053031 --- /dev/null +++ b/tests/unit/gapic/iam_v2/test_policies.py @@ -0,0 +1,2806 @@ +# -*- 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 + +import math + +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.longrunning import operations_pb2 +from google.oauth2 import service_account +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 google.cloud.iam_v2.services.policies import ( + PoliciesAsyncClient, + PoliciesClient, + pagers, + transports, +) +from google.cloud.iam_v2.types import deny +from google.cloud.iam_v2.types import policy +from google.cloud.iam_v2.types import policy as gi_policy + + +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 PoliciesClient._get_default_mtls_endpoint(None) is None + assert PoliciesClient._get_default_mtls_endpoint(api_endpoint) == api_mtls_endpoint + assert ( + PoliciesClient._get_default_mtls_endpoint(api_mtls_endpoint) + == api_mtls_endpoint + ) + assert ( + PoliciesClient._get_default_mtls_endpoint(sandbox_endpoint) + == sandbox_mtls_endpoint + ) + assert ( + PoliciesClient._get_default_mtls_endpoint(sandbox_mtls_endpoint) + == sandbox_mtls_endpoint + ) + assert PoliciesClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi + + +@pytest.mark.parametrize( + "client_class,transport_name", + [ + (PoliciesClient, "grpc"), + (PoliciesAsyncClient, "grpc_asyncio"), + ], +) +def test_policies_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 == ("iam.googleapis.com:443") + + +@pytest.mark.parametrize( + "transport_class,transport_name", + [ + (transports.PoliciesGrpcTransport, "grpc"), + (transports.PoliciesGrpcAsyncIOTransport, "grpc_asyncio"), + ], +) +def test_policies_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", + [ + (PoliciesClient, "grpc"), + (PoliciesAsyncClient, "grpc_asyncio"), + ], +) +def test_policies_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 == ("iam.googleapis.com:443") + + +def test_policies_client_get_transport_class(): + transport = PoliciesClient.get_transport_class() + available_transports = [ + transports.PoliciesGrpcTransport, + ] + assert transport in available_transports + + transport = PoliciesClient.get_transport_class("grpc") + assert transport == transports.PoliciesGrpcTransport + + +@pytest.mark.parametrize( + "client_class,transport_class,transport_name", + [ + (PoliciesClient, transports.PoliciesGrpcTransport, "grpc"), + (PoliciesAsyncClient, transports.PoliciesGrpcAsyncIOTransport, "grpc_asyncio"), + ], +) +@mock.patch.object( + PoliciesClient, "DEFAULT_ENDPOINT", modify_default_endpoint(PoliciesClient) +) +@mock.patch.object( + PoliciesAsyncClient, + "DEFAULT_ENDPOINT", + modify_default_endpoint(PoliciesAsyncClient), +) +def test_policies_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(PoliciesClient, "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(PoliciesClient, "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", + [ + (PoliciesClient, transports.PoliciesGrpcTransport, "grpc", "true"), + ( + PoliciesAsyncClient, + transports.PoliciesGrpcAsyncIOTransport, + "grpc_asyncio", + "true", + ), + (PoliciesClient, transports.PoliciesGrpcTransport, "grpc", "false"), + ( + PoliciesAsyncClient, + transports.PoliciesGrpcAsyncIOTransport, + "grpc_asyncio", + "false", + ), + ], +) +@mock.patch.object( + PoliciesClient, "DEFAULT_ENDPOINT", modify_default_endpoint(PoliciesClient) +) +@mock.patch.object( + PoliciesAsyncClient, + "DEFAULT_ENDPOINT", + modify_default_endpoint(PoliciesAsyncClient), +) +@mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "auto"}) +def test_policies_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", [PoliciesClient, PoliciesAsyncClient]) +@mock.patch.object( + PoliciesClient, "DEFAULT_ENDPOINT", modify_default_endpoint(PoliciesClient) +) +@mock.patch.object( + PoliciesAsyncClient, + "DEFAULT_ENDPOINT", + modify_default_endpoint(PoliciesAsyncClient), +) +def test_policies_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", + [ + (PoliciesClient, transports.PoliciesGrpcTransport, "grpc"), + (PoliciesAsyncClient, transports.PoliciesGrpcAsyncIOTransport, "grpc_asyncio"), + ], +) +def test_policies_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", + [ + (PoliciesClient, transports.PoliciesGrpcTransport, "grpc", grpc_helpers), + ( + PoliciesAsyncClient, + transports.PoliciesGrpcAsyncIOTransport, + "grpc_asyncio", + grpc_helpers_async, + ), + ], +) +def test_policies_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_policies_client_client_options_from_dict(): + with mock.patch( + "google.cloud.iam_v2.services.policies.transports.PoliciesGrpcTransport.__init__" + ) as grpc_transport: + grpc_transport.return_value = None + client = PoliciesClient(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", + [ + (PoliciesClient, transports.PoliciesGrpcTransport, "grpc", grpc_helpers), + ( + PoliciesAsyncClient, + transports.PoliciesGrpcAsyncIOTransport, + "grpc_asyncio", + grpc_helpers_async, + ), + ], +) +def test_policies_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( + "iam.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="iam.googleapis.com", + ssl_credentials=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + +@pytest.mark.parametrize( + "request_type", + [ + policy.ListPoliciesRequest, + dict, + ], +) +def test_list_policies(request_type, transport: str = "grpc"): + client = PoliciesClient( + 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_policies), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = policy.ListPoliciesResponse( + next_page_token="next_page_token_value", + ) + response = client.list_policies(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == policy.ListPoliciesRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListPoliciesPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_policies_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 = PoliciesClient( + 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_policies), "__call__") as call: + client.list_policies() + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == policy.ListPoliciesRequest() + + +@pytest.mark.asyncio +async def test_list_policies_async( + transport: str = "grpc_asyncio", request_type=policy.ListPoliciesRequest +): + client = PoliciesAsyncClient( + 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_policies), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + policy.ListPoliciesResponse( + next_page_token="next_page_token_value", + ) + ) + response = await client.list_policies(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == policy.ListPoliciesRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListPoliciesAsyncPager) + assert response.next_page_token == "next_page_token_value" + + +@pytest.mark.asyncio +async def test_list_policies_async_from_dict(): + await test_list_policies_async(request_type=dict) + + +def test_list_policies_field_headers(): + client = PoliciesClient( + 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 = policy.ListPoliciesRequest() + + request.parent = "parent_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_policies), "__call__") as call: + call.return_value = policy.ListPoliciesResponse() + client.list_policies(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_policies_field_headers_async(): + client = PoliciesAsyncClient( + 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 = policy.ListPoliciesRequest() + + request.parent = "parent_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_policies), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + policy.ListPoliciesResponse() + ) + await client.list_policies(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_policies_flattened(): + client = PoliciesClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_policies), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = policy.ListPoliciesResponse() + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.list_policies( + 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_policies_flattened_error(): + client = PoliciesClient( + 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_policies( + policy.ListPoliciesRequest(), + parent="parent_value", + ) + + +@pytest.mark.asyncio +async def test_list_policies_flattened_async(): + client = PoliciesAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_policies), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = policy.ListPoliciesResponse() + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + policy.ListPoliciesResponse() + ) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.list_policies( + 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_policies_flattened_error_async(): + client = PoliciesAsyncClient( + 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_policies( + policy.ListPoliciesRequest(), + parent="parent_value", + ) + + +def test_list_policies_pager(transport_name: str = "grpc"): + client = PoliciesClient( + 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_policies), "__call__") as call: + # Set the response to a series of pages. + call.side_effect = ( + policy.ListPoliciesResponse( + policies=[ + policy.Policy(), + policy.Policy(), + policy.Policy(), + ], + next_page_token="abc", + ), + policy.ListPoliciesResponse( + policies=[], + next_page_token="def", + ), + policy.ListPoliciesResponse( + policies=[ + policy.Policy(), + ], + next_page_token="ghi", + ), + policy.ListPoliciesResponse( + policies=[ + policy.Policy(), + policy.Policy(), + ], + ), + RuntimeError, + ) + + metadata = () + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", ""),)), + ) + pager = client.list_policies(request={}) + + assert pager._metadata == metadata + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, policy.Policy) for i in results) + + +def test_list_policies_pages(transport_name: str = "grpc"): + client = PoliciesClient( + 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_policies), "__call__") as call: + # Set the response to a series of pages. + call.side_effect = ( + policy.ListPoliciesResponse( + policies=[ + policy.Policy(), + policy.Policy(), + policy.Policy(), + ], + next_page_token="abc", + ), + policy.ListPoliciesResponse( + policies=[], + next_page_token="def", + ), + policy.ListPoliciesResponse( + policies=[ + policy.Policy(), + ], + next_page_token="ghi", + ), + policy.ListPoliciesResponse( + policies=[ + policy.Policy(), + policy.Policy(), + ], + ), + RuntimeError, + ) + pages = list(client.list_policies(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_policies_async_pager(): + client = PoliciesAsyncClient( + credentials=ga_credentials.AnonymousCredentials, + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_policies), "__call__", new_callable=mock.AsyncMock + ) as call: + # Set the response to a series of pages. + call.side_effect = ( + policy.ListPoliciesResponse( + policies=[ + policy.Policy(), + policy.Policy(), + policy.Policy(), + ], + next_page_token="abc", + ), + policy.ListPoliciesResponse( + policies=[], + next_page_token="def", + ), + policy.ListPoliciesResponse( + policies=[ + policy.Policy(), + ], + next_page_token="ghi", + ), + policy.ListPoliciesResponse( + policies=[ + policy.Policy(), + policy.Policy(), + ], + ), + RuntimeError, + ) + async_pager = await client.list_policies( + 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, policy.Policy) for i in responses) + + +@pytest.mark.asyncio +async def test_list_policies_async_pages(): + client = PoliciesAsyncClient( + credentials=ga_credentials.AnonymousCredentials, + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_policies), "__call__", new_callable=mock.AsyncMock + ) as call: + # Set the response to a series of pages. + call.side_effect = ( + policy.ListPoliciesResponse( + policies=[ + policy.Policy(), + policy.Policy(), + policy.Policy(), + ], + next_page_token="abc", + ), + policy.ListPoliciesResponse( + policies=[], + next_page_token="def", + ), + policy.ListPoliciesResponse( + policies=[ + policy.Policy(), + ], + next_page_token="ghi", + ), + policy.ListPoliciesResponse( + policies=[ + policy.Policy(), + policy.Policy(), + ], + ), + RuntimeError, + ) + pages = [] + async for page_ in ( + await client.list_policies(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", + [ + policy.GetPolicyRequest, + dict, + ], +) +def test_get_policy(request_type, transport: str = "grpc"): + client = PoliciesClient( + 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_policy), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = policy.Policy( + name="name_value", + uid="uid_value", + kind="kind_value", + display_name="display_name_value", + etag="etag_value", + managing_authority="managing_authority_value", + ) + response = client.get_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] == policy.GetPolicyRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, policy.Policy) + assert response.name == "name_value" + assert response.uid == "uid_value" + assert response.kind == "kind_value" + assert response.display_name == "display_name_value" + assert response.etag == "etag_value" + assert response.managing_authority == "managing_authority_value" + + +def test_get_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 = PoliciesClient( + 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_policy), "__call__") as call: + client.get_policy() + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == policy.GetPolicyRequest() + + +@pytest.mark.asyncio +async def test_get_policy_async( + transport: str = "grpc_asyncio", request_type=policy.GetPolicyRequest +): + client = PoliciesAsyncClient( + 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_policy), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + policy.Policy( + name="name_value", + uid="uid_value", + kind="kind_value", + display_name="display_name_value", + etag="etag_value", + managing_authority="managing_authority_value", + ) + ) + response = await client.get_policy(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == policy.GetPolicyRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, policy.Policy) + assert response.name == "name_value" + assert response.uid == "uid_value" + assert response.kind == "kind_value" + assert response.display_name == "display_name_value" + assert response.etag == "etag_value" + assert response.managing_authority == "managing_authority_value" + + +@pytest.mark.asyncio +async def test_get_policy_async_from_dict(): + await test_get_policy_async(request_type=dict) + + +def test_get_policy_field_headers(): + client = PoliciesClient( + 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 = policy.GetPolicyRequest() + + request.name = "name_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_policy), "__call__") as call: + call.return_value = policy.Policy() + client.get_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", + "name=name_value", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_get_policy_field_headers_async(): + client = PoliciesAsyncClient( + 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 = policy.GetPolicyRequest() + + request.name = "name_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_policy), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(policy.Policy()) + await client.get_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", + "name=name_value", + ) in kw["metadata"] + + +def test_get_policy_flattened(): + client = PoliciesClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_policy), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = policy.Policy() + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.get_policy( + 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_policy_flattened_error(): + client = PoliciesClient( + 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_policy( + policy.GetPolicyRequest(), + name="name_value", + ) + + +@pytest.mark.asyncio +async def test_get_policy_flattened_async(): + client = PoliciesAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_policy), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = policy.Policy() + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(policy.Policy()) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.get_policy( + 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_policy_flattened_error_async(): + client = PoliciesAsyncClient( + 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_policy( + policy.GetPolicyRequest(), + name="name_value", + ) + + +@pytest.mark.parametrize( + "request_type", + [ + gi_policy.CreatePolicyRequest, + dict, + ], +) +def test_create_policy(request_type, transport: str = "grpc"): + client = PoliciesClient( + 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_policy), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation(name="operations/spam") + response = client.create_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] == gi_policy.CreatePolicyRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, future.Future) + + +def test_create_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 = PoliciesClient( + 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_policy), "__call__") as call: + client.create_policy() + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == gi_policy.CreatePolicyRequest() + + +@pytest.mark.asyncio +async def test_create_policy_async( + transport: str = "grpc_asyncio", request_type=gi_policy.CreatePolicyRequest +): + client = PoliciesAsyncClient( + 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_policy), "__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_policy(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == gi_policy.CreatePolicyRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, future.Future) + + +@pytest.mark.asyncio +async def test_create_policy_async_from_dict(): + await test_create_policy_async(request_type=dict) + + +def test_create_policy_field_headers(): + client = PoliciesClient( + 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 = gi_policy.CreatePolicyRequest() + + request.parent = "parent_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.create_policy), "__call__") as call: + call.return_value = operations_pb2.Operation(name="operations/op") + client.create_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", + "parent=parent_value", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_create_policy_field_headers_async(): + client = PoliciesAsyncClient( + 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 = gi_policy.CreatePolicyRequest() + + request.parent = "parent_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.create_policy), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation(name="operations/op") + ) + await client.create_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", + "parent=parent_value", + ) in kw["metadata"] + + +def test_create_policy_flattened(): + client = PoliciesClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.create_policy), "__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_policy( + parent="parent_value", + policy=gi_policy.Policy(name="name_value"), + policy_id="policy_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].policy + mock_val = gi_policy.Policy(name="name_value") + assert arg == mock_val + arg = args[0].policy_id + mock_val = "policy_id_value" + assert arg == mock_val + + +def test_create_policy_flattened_error(): + client = PoliciesClient( + 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_policy( + gi_policy.CreatePolicyRequest(), + parent="parent_value", + policy=gi_policy.Policy(name="name_value"), + policy_id="policy_id_value", + ) + + +@pytest.mark.asyncio +async def test_create_policy_flattened_async(): + client = PoliciesAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.create_policy), "__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_policy( + parent="parent_value", + policy=gi_policy.Policy(name="name_value"), + policy_id="policy_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].policy + mock_val = gi_policy.Policy(name="name_value") + assert arg == mock_val + arg = args[0].policy_id + mock_val = "policy_id_value" + assert arg == mock_val + + +@pytest.mark.asyncio +async def test_create_policy_flattened_error_async(): + client = PoliciesAsyncClient( + 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_policy( + gi_policy.CreatePolicyRequest(), + parent="parent_value", + policy=gi_policy.Policy(name="name_value"), + policy_id="policy_id_value", + ) + + +@pytest.mark.parametrize( + "request_type", + [ + policy.UpdatePolicyRequest, + dict, + ], +) +def test_update_policy(request_type, transport: str = "grpc"): + client = PoliciesClient( + 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_policy), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation(name="operations/spam") + response = client.update_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] == policy.UpdatePolicyRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, future.Future) + + +def test_update_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 = PoliciesClient( + 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_policy), "__call__") as call: + client.update_policy() + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == policy.UpdatePolicyRequest() + + +@pytest.mark.asyncio +async def test_update_policy_async( + transport: str = "grpc_asyncio", request_type=policy.UpdatePolicyRequest +): + client = PoliciesAsyncClient( + 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_policy), "__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_policy(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == policy.UpdatePolicyRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, future.Future) + + +@pytest.mark.asyncio +async def test_update_policy_async_from_dict(): + await test_update_policy_async(request_type=dict) + + +def test_update_policy_field_headers(): + client = PoliciesClient( + 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 = policy.UpdatePolicyRequest() + + request.policy.name = "name_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.update_policy), "__call__") as call: + call.return_value = operations_pb2.Operation(name="operations/op") + client.update_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", + "policy.name=name_value", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_update_policy_field_headers_async(): + client = PoliciesAsyncClient( + 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 = policy.UpdatePolicyRequest() + + request.policy.name = "name_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.update_policy), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation(name="operations/op") + ) + await client.update_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", + "policy.name=name_value", + ) in kw["metadata"] + + +@pytest.mark.parametrize( + "request_type", + [ + policy.DeletePolicyRequest, + dict, + ], +) +def test_delete_policy(request_type, transport: str = "grpc"): + client = PoliciesClient( + 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_policy), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation(name="operations/spam") + response = client.delete_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] == policy.DeletePolicyRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, future.Future) + + +def test_delete_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 = PoliciesClient( + 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_policy), "__call__") as call: + client.delete_policy() + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == policy.DeletePolicyRequest() + + +@pytest.mark.asyncio +async def test_delete_policy_async( + transport: str = "grpc_asyncio", request_type=policy.DeletePolicyRequest +): + client = PoliciesAsyncClient( + 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_policy), "__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_policy(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == policy.DeletePolicyRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, future.Future) + + +@pytest.mark.asyncio +async def test_delete_policy_async_from_dict(): + await test_delete_policy_async(request_type=dict) + + +def test_delete_policy_field_headers(): + client = PoliciesClient( + 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 = policy.DeletePolicyRequest() + + request.name = "name_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_policy), "__call__") as call: + call.return_value = operations_pb2.Operation(name="operations/op") + client.delete_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", + "name=name_value", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_delete_policy_field_headers_async(): + client = PoliciesAsyncClient( + 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 = policy.DeletePolicyRequest() + + request.name = "name_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_policy), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation(name="operations/op") + ) + await client.delete_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", + "name=name_value", + ) in kw["metadata"] + + +def test_delete_policy_flattened(): + client = PoliciesClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_policy), "__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_policy( + 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_policy_flattened_error(): + client = PoliciesClient( + 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_policy( + policy.DeletePolicyRequest(), + name="name_value", + ) + + +@pytest.mark.asyncio +async def test_delete_policy_flattened_async(): + client = PoliciesAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_policy), "__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_policy( + 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_policy_flattened_error_async(): + client = PoliciesAsyncClient( + 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_policy( + policy.DeletePolicyRequest(), + name="name_value", + ) + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.PoliciesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = PoliciesClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.PoliciesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = PoliciesClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide an api_key and a transport instance. + transport = transports.PoliciesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + options = client_options.ClientOptions() + options.api_key = "api_key" + with pytest.raises(ValueError): + client = PoliciesClient( + 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 = PoliciesClient( + client_options=options, credentials=ga_credentials.AnonymousCredentials() + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.PoliciesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = PoliciesClient( + client_options={"scopes": ["1", "2"]}, + transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.PoliciesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + client = PoliciesClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.PoliciesGrpcTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.PoliciesGrpcAsyncIOTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.PoliciesGrpcTransport, + transports.PoliciesGrpcAsyncIOTransport, + ], +) +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", + ], +) +def test_transport_kind(transport_name): + transport = PoliciesClient.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 = PoliciesClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + assert isinstance( + client.transport, + transports.PoliciesGrpcTransport, + ) + + +def test_policies_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(core_exceptions.DuplicateCredentialArgs): + transport = transports.PoliciesTransport( + credentials=ga_credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_policies_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.iam_v2.services.policies.transports.PoliciesTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.PoliciesTransport( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + "list_policies", + "get_policy", + "create_policy", + "update_policy", + "delete_policy", + "get_operation", + ) + 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_policies_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.iam_v2.services.policies.transports.PoliciesTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.PoliciesTransport( + 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_policies_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.iam_v2.services.policies.transports.PoliciesTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.PoliciesTransport() + adc.assert_called_once() + + +def test_policies_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) + PoliciesClient() + 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.PoliciesGrpcTransport, + transports.PoliciesGrpcAsyncIOTransport, + ], +) +def test_policies_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.PoliciesGrpcTransport, + transports.PoliciesGrpcAsyncIOTransport, + ], +) +def test_policies_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.PoliciesGrpcTransport, grpc_helpers), + (transports.PoliciesGrpcAsyncIOTransport, grpc_helpers_async), + ], +) +def test_policies_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( + "iam.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="iam.googleapis.com", + ssl_credentials=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + +@pytest.mark.parametrize( + "transport_class", + [transports.PoliciesGrpcTransport, transports.PoliciesGrpcAsyncIOTransport], +) +def test_policies_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 + ) + + +@pytest.mark.parametrize( + "transport_name", + [ + "grpc", + "grpc_asyncio", + ], +) +def test_policies_host_no_port(transport_name): + client = PoliciesClient( + credentials=ga_credentials.AnonymousCredentials(), + client_options=client_options.ClientOptions(api_endpoint="iam.googleapis.com"), + transport=transport_name, + ) + assert client.transport._host == ("iam.googleapis.com:443") + + +@pytest.mark.parametrize( + "transport_name", + [ + "grpc", + "grpc_asyncio", + ], +) +def test_policies_host_with_port(transport_name): + client = PoliciesClient( + credentials=ga_credentials.AnonymousCredentials(), + client_options=client_options.ClientOptions( + api_endpoint="iam.googleapis.com:8000" + ), + transport=transport_name, + ) + assert client.transport._host == ("iam.googleapis.com:8000") + + +def test_policies_grpc_transport_channel(): + channel = grpc.secure_channel("http://localhost/", grpc.local_channel_credentials()) + + # Check that channel is used if provided. + transport = transports.PoliciesGrpcTransport( + 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_policies_grpc_asyncio_transport_channel(): + channel = aio.secure_channel("http://localhost/", grpc.local_channel_credentials()) + + # Check that channel is used if provided. + transport = transports.PoliciesGrpcAsyncIOTransport( + 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.PoliciesGrpcTransport, transports.PoliciesGrpcAsyncIOTransport], +) +def test_policies_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.PoliciesGrpcTransport, transports.PoliciesGrpcAsyncIOTransport], +) +def test_policies_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_policies_grpc_lro_client(): + client = PoliciesClient( + 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_policies_grpc_lro_async_client(): + client = PoliciesAsyncClient( + 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_common_billing_account_path(): + billing_account = "squid" + expected = "billingAccounts/{billing_account}".format( + billing_account=billing_account, + ) + actual = PoliciesClient.common_billing_account_path(billing_account) + assert expected == actual + + +def test_parse_common_billing_account_path(): + expected = { + "billing_account": "clam", + } + path = PoliciesClient.common_billing_account_path(**expected) + + # Check that the path construction is reversible. + actual = PoliciesClient.parse_common_billing_account_path(path) + assert expected == actual + + +def test_common_folder_path(): + folder = "whelk" + expected = "folders/{folder}".format( + folder=folder, + ) + actual = PoliciesClient.common_folder_path(folder) + assert expected == actual + + +def test_parse_common_folder_path(): + expected = { + "folder": "octopus", + } + path = PoliciesClient.common_folder_path(**expected) + + # Check that the path construction is reversible. + actual = PoliciesClient.parse_common_folder_path(path) + assert expected == actual + + +def test_common_organization_path(): + organization = "oyster" + expected = "organizations/{organization}".format( + organization=organization, + ) + actual = PoliciesClient.common_organization_path(organization) + assert expected == actual + + +def test_parse_common_organization_path(): + expected = { + "organization": "nudibranch", + } + path = PoliciesClient.common_organization_path(**expected) + + # Check that the path construction is reversible. + actual = PoliciesClient.parse_common_organization_path(path) + assert expected == actual + + +def test_common_project_path(): + project = "cuttlefish" + expected = "projects/{project}".format( + project=project, + ) + actual = PoliciesClient.common_project_path(project) + assert expected == actual + + +def test_parse_common_project_path(): + expected = { + "project": "mussel", + } + path = PoliciesClient.common_project_path(**expected) + + # Check that the path construction is reversible. + actual = PoliciesClient.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 = PoliciesClient.common_location_path(project, location) + assert expected == actual + + +def test_parse_common_location_path(): + expected = { + "project": "scallop", + "location": "abalone", + } + path = PoliciesClient.common_location_path(**expected) + + # Check that the path construction is reversible. + actual = PoliciesClient.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.PoliciesTransport, "_prep_wrapped_messages" + ) as prep: + client = PoliciesClient( + credentials=ga_credentials.AnonymousCredentials(), + client_info=client_info, + ) + prep.assert_called_once_with(client_info) + + with mock.patch.object( + transports.PoliciesTransport, "_prep_wrapped_messages" + ) as prep: + transport_class = PoliciesClient.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 = PoliciesAsyncClient( + 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_get_operation(transport: str = "grpc"): + client = PoliciesClient( + 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 = PoliciesAsyncClient( + 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 = PoliciesClient( + 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 = PoliciesAsyncClient( + 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 = PoliciesClient( + 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 = PoliciesAsyncClient( + 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_transport_close(): + transports = { + "grpc": "_grpc_channel", + } + + for transport, close_name in transports.items(): + client = PoliciesClient( + 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 = [ + "grpc", + ] + for transport in transports: + client = PoliciesClient( + 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", + [ + (PoliciesClient, transports.PoliciesGrpcTransport), + (PoliciesAsyncClient, transports.PoliciesGrpcAsyncIOTransport), + ], +) +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/iam_v2beta/test_policies.py b/tests/unit/gapic/iam_v2beta/test_policies.py index 6c1aa76..520646d 100644 --- a/tests/unit/gapic/iam_v2beta/test_policies.py +++ b/tests/unit/gapic/iam_v2beta/test_policies.py @@ -18,8 +18,8 @@ # try/except added for compatibility with python < 3.8 try: from unittest import mock - from unittest.mock import AsyncMock -except ImportError: + from unittest.mock import AsyncMock # pragma: NO COVER +except ImportError: # pragma: NO COVER import mock import math @@ -45,6 +45,7 @@ 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 @@ -2080,6 +2081,7 @@ def test_policies_base_transport(): "create_policy", "update_policy", "delete_policy", + "get_operation", ) for method in methods: with pytest.raises(NotImplementedError): @@ -2451,28 +2453,8 @@ def test_policies_grpc_lro_async_client(): assert transport.operations_client is transport.operations_client -def test_policy_path(): - policy = "squid" - expected = "policies/{policy}".format( - policy=policy, - ) - actual = PoliciesClient.policy_path(policy) - assert expected == actual - - -def test_parse_policy_path(): - expected = { - "policy": "clam", - } - path = PoliciesClient.policy_path(**expected) - - # Check that the path construction is reversible. - actual = PoliciesClient.parse_policy_path(path) - assert expected == actual - - def test_common_billing_account_path(): - billing_account = "whelk" + billing_account = "squid" expected = "billingAccounts/{billing_account}".format( billing_account=billing_account, ) @@ -2482,7 +2464,7 @@ def test_common_billing_account_path(): def test_parse_common_billing_account_path(): expected = { - "billing_account": "octopus", + "billing_account": "clam", } path = PoliciesClient.common_billing_account_path(**expected) @@ -2492,7 +2474,7 @@ def test_parse_common_billing_account_path(): def test_common_folder_path(): - folder = "oyster" + folder = "whelk" expected = "folders/{folder}".format( folder=folder, ) @@ -2502,7 +2484,7 @@ def test_common_folder_path(): def test_parse_common_folder_path(): expected = { - "folder": "nudibranch", + "folder": "octopus", } path = PoliciesClient.common_folder_path(**expected) @@ -2512,7 +2494,7 @@ def test_parse_common_folder_path(): def test_common_organization_path(): - organization = "cuttlefish" + organization = "oyster" expected = "organizations/{organization}".format( organization=organization, ) @@ -2522,7 +2504,7 @@ def test_common_organization_path(): def test_parse_common_organization_path(): expected = { - "organization": "mussel", + "organization": "nudibranch", } path = PoliciesClient.common_organization_path(**expected) @@ -2532,7 +2514,7 @@ def test_parse_common_organization_path(): def test_common_project_path(): - project = "winkle" + project = "cuttlefish" expected = "projects/{project}".format( project=project, ) @@ -2542,7 +2524,7 @@ def test_common_project_path(): def test_parse_common_project_path(): expected = { - "project": "nautilus", + "project": "mussel", } path = PoliciesClient.common_project_path(**expected) @@ -2552,8 +2534,8 @@ def test_parse_common_project_path(): def test_common_location_path(): - project = "scallop" - location = "abalone" + project = "winkle" + location = "nautilus" expected = "projects/{project}/locations/{location}".format( project=project, location=location, @@ -2564,8 +2546,8 @@ def test_common_location_path(): def test_parse_common_location_path(): expected = { - "project": "squid", - "location": "clam", + "project": "scallop", + "location": "abalone", } path = PoliciesClient.common_location_path(**expected) @@ -2611,6 +2593,151 @@ async def test_transport_close_async(): close.assert_called_once() +def test_get_operation(transport: str = "grpc"): + client = PoliciesClient( + 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 = PoliciesAsyncClient( + 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 = PoliciesClient( + 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 = PoliciesAsyncClient( + 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 = PoliciesClient( + 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 = PoliciesAsyncClient( + 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_transport_close(): transports = { "grpc": "_grpc_channel",