From 34278bf526384296e95196f755ab983c4efeca62 Mon Sep 17 00:00:00 2001 From: Yoshi Automation Bot Date: Fri, 2 Apr 2021 13:16:58 -0700 Subject: [PATCH] fix: use correct retry deadlines (#164) feat: add `from_service_account_info` --- .coveragerc | 20 +- .github/header-checker-lint.yml | 15 + .gitignore | 4 +- .kokoro/build.sh | 26 +- .kokoro/docs/docs-presubmit.cfg | 11 + .kokoro/samples/python3.6/periodic-head.cfg | 11 + .kokoro/samples/python3.7/periodic-head.cfg | 11 + .kokoro/samples/python3.8/periodic-head.cfg | 11 + .kokoro/test-samples-against-head.sh | 28 ++ .kokoro/test-samples-impl.sh | 102 +++++ .kokoro/test-samples.sh | 96 +---- .pre-commit-config.yaml | 2 +- .trampolinerc | 1 + CONTRIBUTING.rst | 22 +- MANIFEST.in | 4 +- UPGRADING.md | 4 +- docs/asset_v1/asset_service.rst | 11 + docs/asset_v1/services.rst | 6 +- docs/asset_v1/types.rst | 1 + docs/asset_v1p1beta1/asset_service.rst | 11 + docs/asset_v1p1beta1/services.rst | 6 +- docs/asset_v1p1beta1/types.rst | 1 + docs/asset_v1p2beta1/asset_service.rst | 6 + docs/asset_v1p2beta1/services.rst | 6 +- docs/asset_v1p2beta1/types.rst | 1 + docs/asset_v1p4beta1/asset_service.rst | 6 + docs/asset_v1p4beta1/services.rst | 6 +- docs/asset_v1p4beta1/types.rst | 1 + docs/asset_v1p5beta1/asset_service.rst | 11 + docs/asset_v1p5beta1/services.rst | 6 +- docs/asset_v1p5beta1/types.rst | 1 + .../services/asset_service/async_client.py | 106 +++-- .../asset_v1/services/asset_service/client.py | 131 +++--- .../asset_v1/services/asset_service/pagers.py | 43 +- .../services/asset_service/transports/base.py | 25 +- .../services/asset_service/transports/grpc.py | 114 +++-- .../asset_service/transports/grpc_asyncio.py | 122 +++--- google/cloud/asset_v1/types/__init__.py | 104 ++--- google/cloud/asset_v1/types/asset_service.py | 80 ++-- google/cloud/asset_v1/types/assets.py | 64 +-- .../services/asset_service/async_client.py | 47 +- .../services/asset_service/client.py | 69 +-- .../services/asset_service/pagers.py | 43 +- .../services/asset_service/transports/base.py | 20 +- .../services/asset_service/transports/grpc.py | 112 +++-- .../asset_service/transports/grpc_asyncio.py | 120 +++--- .../cloud/asset_v1p1beta1/types/__init__.py | 24 +- .../asset_v1p1beta1/types/asset_service.py | 4 +- google/cloud/asset_v1p1beta1/types/assets.py | 8 +- .../services/asset_service/async_client.py | 59 ++- .../services/asset_service/client.py | 73 ++-- .../services/asset_service/transports/base.py | 21 +- .../services/asset_service/transports/grpc.py | 112 +++-- .../asset_service/transports/grpc_asyncio.py | 120 +++--- .../cloud/asset_v1p2beta1/types/__init__.py | 40 +- .../asset_v1p2beta1/types/asset_service.py | 16 +- google/cloud/asset_v1p2beta1/types/assets.py | 14 +- .../services/asset_service/async_client.py | 51 ++- .../services/asset_service/client.py | 59 +-- .../services/asset_service/transports/base.py | 19 +- .../services/asset_service/transports/grpc.py | 114 +++-- .../asset_service/transports/grpc_asyncio.py | 122 +++--- .../cloud/asset_v1p4beta1/types/__init__.py | 12 +- .../asset_v1p4beta1/types/asset_service.py | 32 +- google/cloud/asset_v1p4beta1/types/assets.py | 24 +- .../services/asset_service/async_client.py | 36 +- .../services/asset_service/client.py | 44 +- .../services/asset_service/pagers.py | 27 +- .../services/asset_service/transports/base.py | 19 +- .../services/asset_service/transports/grpc.py | 112 +++-- .../asset_service/transports/grpc_asyncio.py | 120 +++--- .../cloud/asset_v1p5beta1/types/__init__.py | 12 +- .../asset_v1p5beta1/types/asset_service.py | 8 +- google/cloud/asset_v1p5beta1/types/assets.py | 14 +- noxfile.py | 63 ++- renovate.json | 3 +- samples/snippets/noxfile.py | 2 +- setup.py | 8 +- synth.metadata | 177 +------- synth.py | 2 +- testing/constraints-3.6.txt | 6 +- tests/unit/gapic/asset_v1/__init__.py | 15 + .../unit/gapic/asset_v1/test_asset_service.py | 402 ++++++++++++++---- tests/unit/gapic/asset_v1p1beta1/__init__.py | 15 + .../asset_v1p1beta1/test_asset_service.py | 252 +++++++---- tests/unit/gapic/asset_v1p2beta1/__init__.py | 15 + .../asset_v1p2beta1/test_asset_service.py | 296 +++++++++---- tests/unit/gapic/asset_v1p4beta1/__init__.py | 15 + .../asset_v1p4beta1/test_asset_service.py | 252 +++++++---- tests/unit/gapic/asset_v1p5beta1/__init__.py | 15 + .../asset_v1p5beta1/test_asset_service.py | 232 ++++++---- 91 files changed, 2806 insertions(+), 1928 deletions(-) create mode 100644 .github/header-checker-lint.yml create mode 100644 .kokoro/samples/python3.6/periodic-head.cfg create mode 100644 .kokoro/samples/python3.7/periodic-head.cfg create mode 100644 .kokoro/samples/python3.8/periodic-head.cfg create mode 100755 .kokoro/test-samples-against-head.sh create mode 100755 .kokoro/test-samples-impl.sh create mode 100644 docs/asset_v1/asset_service.rst create mode 100644 docs/asset_v1p1beta1/asset_service.rst create mode 100644 docs/asset_v1p2beta1/asset_service.rst create mode 100644 docs/asset_v1p4beta1/asset_service.rst create mode 100644 docs/asset_v1p5beta1/asset_service.rst diff --git a/.coveragerc b/.coveragerc index f899817a..86c446a3 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1,27 +1,11 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2020 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Generated by synthtool. DO NOT EDIT! [run] branch = True [report] fail_under = 100 show_missing = True -omit = google/cloud/asset/__init__.py +omit = + google/cloud/asset/__init__.py exclude_lines = # Re-enable the standard pragma pragma: NO COVER diff --git a/.github/header-checker-lint.yml b/.github/header-checker-lint.yml new file mode 100644 index 00000000..fc281c05 --- /dev/null +++ b/.github/header-checker-lint.yml @@ -0,0 +1,15 @@ +{"allowedCopyrightHolders": ["Google LLC"], + "allowedLicenses": ["Apache-2.0", "MIT", "BSD-3"], + "ignoreFiles": ["**/requirements.txt", "**/requirements-test.txt"], + "sourceFileExtensions": [ + "ts", + "js", + "java", + "sh", + "Dockerfile", + "yaml", + "py", + "html", + "txt" + ] +} \ No newline at end of file diff --git a/.gitignore b/.gitignore index b9daa52f..b4243ced 100644 --- a/.gitignore +++ b/.gitignore @@ -50,8 +50,10 @@ docs.metadata # Virtual environment env/ + +# Test logs coverage.xml -sponge_log.xml +*sponge_log.xml # System test environment variables. system_tests/local_test_setup diff --git a/.kokoro/build.sh b/.kokoro/build.sh index ab94c0f1..f11a5c7f 100755 --- a/.kokoro/build.sh +++ b/.kokoro/build.sh @@ -15,7 +15,11 @@ set -eo pipefail -cd github/python-asset +if [[ -z "${PROJECT_ROOT:-}" ]]; then + PROJECT_ROOT="github/python-asset" +fi + +cd "${PROJECT_ROOT}" # Disable buffering, so that the logs stream through. export PYTHONUNBUFFERED=1 @@ -30,16 +34,26 @@ export GOOGLE_APPLICATION_CREDENTIALS=${KOKORO_GFILE_DIR}/service-account.json export PROJECT_ID=$(cat "${KOKORO_GFILE_DIR}/project-id.json") # Remove old nox -python3.6 -m pip uninstall --yes --quiet nox-automation +python3 -m pip uninstall --yes --quiet nox-automation # Install nox -python3.6 -m pip install --upgrade --quiet nox -python3.6 -m nox --version +python3 -m pip install --upgrade --quiet nox +python3 -m nox --version + +# If this is a continuous build, send the test log to the FlakyBot. +# See https://github.com/googleapis/repo-automation-bots/tree/master/packages/flakybot. +if [[ $KOKORO_BUILD_ARTIFACTS_SUBDIR = *"continuous"* ]]; then + cleanup() { + chmod +x $KOKORO_GFILE_DIR/linux_amd64/flakybot + $KOKORO_GFILE_DIR/linux_amd64/flakybot + } + trap cleanup EXIT HUP +fi # If NOX_SESSION is set, it only runs the specified session, # otherwise run all the sessions. if [[ -n "${NOX_SESSION:-}" ]]; then - python3.6 -m nox -s "${NOX_SESSION:-}" + python3 -m nox -s ${NOX_SESSION:-} else - python3.6 -m nox + python3 -m nox fi diff --git a/.kokoro/docs/docs-presubmit.cfg b/.kokoro/docs/docs-presubmit.cfg index 11181078..f50f3fbc 100644 --- a/.kokoro/docs/docs-presubmit.cfg +++ b/.kokoro/docs/docs-presubmit.cfg @@ -15,3 +15,14 @@ env_vars: { key: "TRAMPOLINE_IMAGE_UPLOAD" value: "false" } + +env_vars: { + key: "TRAMPOLINE_BUILD_FILE" + value: "github/python-asset/.kokoro/build.sh" +} + +# Only run this nox session. +env_vars: { + key: "NOX_SESSION" + value: "docs docfx" +} diff --git a/.kokoro/samples/python3.6/periodic-head.cfg b/.kokoro/samples/python3.6/periodic-head.cfg new file mode 100644 index 00000000..f9cfcd33 --- /dev/null +++ b/.kokoro/samples/python3.6/periodic-head.cfg @@ -0,0 +1,11 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +env_vars: { + key: "INSTALL_LIBRARY_FROM_SOURCE" + value: "True" +} + +env_vars: { + key: "TRAMPOLINE_BUILD_FILE" + value: "github/python-pubsub/.kokoro/test-samples-against-head.sh" +} diff --git a/.kokoro/samples/python3.7/periodic-head.cfg b/.kokoro/samples/python3.7/periodic-head.cfg new file mode 100644 index 00000000..f9cfcd33 --- /dev/null +++ b/.kokoro/samples/python3.7/periodic-head.cfg @@ -0,0 +1,11 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +env_vars: { + key: "INSTALL_LIBRARY_FROM_SOURCE" + value: "True" +} + +env_vars: { + key: "TRAMPOLINE_BUILD_FILE" + value: "github/python-pubsub/.kokoro/test-samples-against-head.sh" +} diff --git a/.kokoro/samples/python3.8/periodic-head.cfg b/.kokoro/samples/python3.8/periodic-head.cfg new file mode 100644 index 00000000..f9cfcd33 --- /dev/null +++ b/.kokoro/samples/python3.8/periodic-head.cfg @@ -0,0 +1,11 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +env_vars: { + key: "INSTALL_LIBRARY_FROM_SOURCE" + value: "True" +} + +env_vars: { + key: "TRAMPOLINE_BUILD_FILE" + value: "github/python-pubsub/.kokoro/test-samples-against-head.sh" +} diff --git a/.kokoro/test-samples-against-head.sh b/.kokoro/test-samples-against-head.sh new file mode 100755 index 00000000..1a00532b --- /dev/null +++ b/.kokoro/test-samples-against-head.sh @@ -0,0 +1,28 @@ +#!/bin/bash +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# A customized test runner for samples. +# +# For periodic builds, you can specify this file for testing against head. + +# `-e` enables the script to automatically fail when a command fails +# `-o pipefail` sets the exit code to the rightmost comment to exit with a non-zero +set -eo pipefail +# Enables `**` to include files nested inside sub-folders +shopt -s globstar + +cd github/python-asset + +exec .kokoro/test-samples-impl.sh diff --git a/.kokoro/test-samples-impl.sh b/.kokoro/test-samples-impl.sh new file mode 100755 index 00000000..cf5de74c --- /dev/null +++ b/.kokoro/test-samples-impl.sh @@ -0,0 +1,102 @@ +#!/bin/bash +# Copyright 2021 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +# `-e` enables the script to automatically fail when a command fails +# `-o pipefail` sets the exit code to the rightmost comment to exit with a non-zero +set -eo pipefail +# Enables `**` to include files nested inside sub-folders +shopt -s globstar + +# Exit early if samples directory doesn't exist +if [ ! -d "./samples" ]; then + echo "No tests run. `./samples` not found" + exit 0 +fi + +# Disable buffering, so that the logs stream through. +export PYTHONUNBUFFERED=1 + +# Debug: show build environment +env | grep KOKORO + +# Install nox +python3.6 -m pip install --upgrade --quiet nox + +# Use secrets acessor service account to get secrets +if [[ -f "${KOKORO_GFILE_DIR}/secrets_viewer_service_account.json" ]]; then + gcloud auth activate-service-account \ + --key-file="${KOKORO_GFILE_DIR}/secrets_viewer_service_account.json" \ + --project="cloud-devrel-kokoro-resources" +fi + +# This script will create 3 files: +# - testing/test-env.sh +# - testing/service-account.json +# - testing/client-secrets.json +./scripts/decrypt-secrets.sh + +source ./testing/test-env.sh +export GOOGLE_APPLICATION_CREDENTIALS=$(pwd)/testing/service-account.json + +# For cloud-run session, we activate the service account for gcloud sdk. +gcloud auth activate-service-account \ + --key-file "${GOOGLE_APPLICATION_CREDENTIALS}" + +export GOOGLE_CLIENT_SECRETS=$(pwd)/testing/client-secrets.json + +echo -e "\n******************** TESTING PROJECTS ********************" + +# Switch to 'fail at end' to allow all tests to complete before exiting. +set +e +# Use RTN to return a non-zero value if the test fails. +RTN=0 +ROOT=$(pwd) +# Find all requirements.txt in the samples directory (may break on whitespace). +for file in samples/**/requirements.txt; do + cd "$ROOT" + # Navigate to the project folder. + file=$(dirname "$file") + cd "$file" + + echo "------------------------------------------------------------" + echo "- testing $file" + echo "------------------------------------------------------------" + + # Use nox to execute the tests for the project. + python3.6 -m nox -s "$RUN_TESTS_SESSION" + EXIT=$? + + # If this is a periodic build, send the test log to the FlakyBot. + # See https://github.com/googleapis/repo-automation-bots/tree/master/packages/flakybot. + if [[ $KOKORO_BUILD_ARTIFACTS_SUBDIR = *"periodic"* ]]; then + chmod +x $KOKORO_GFILE_DIR/linux_amd64/flakybot + $KOKORO_GFILE_DIR/linux_amd64/flakybot + fi + + if [[ $EXIT -ne 0 ]]; then + RTN=1 + echo -e "\n Testing failed: Nox returned a non-zero exit code. \n" + else + echo -e "\n Testing completed.\n" + fi + +done +cd "$ROOT" + +# Workaround for Kokoro permissions issue: delete secrets +rm testing/{test-env.sh,client-secrets.json,service-account.json} + +exit "$RTN" diff --git a/.kokoro/test-samples.sh b/.kokoro/test-samples.sh index a6781eac..adec5700 100755 --- a/.kokoro/test-samples.sh +++ b/.kokoro/test-samples.sh @@ -13,6 +13,10 @@ # See the License for the specific language governing permissions and # limitations under the License. +# The default test runner for samples. +# +# For periodic builds, we rewinds the repo to the latest release, and +# run test-samples-impl.sh. # `-e` enables the script to automatically fail when a command fails # `-o pipefail` sets the exit code to the rightmost comment to exit with a non-zero @@ -24,87 +28,19 @@ cd github/python-asset # Run periodic samples tests at latest release if [[ $KOKORO_BUILD_ARTIFACTS_SUBDIR = *"periodic"* ]]; then + # preserving the test runner implementation. + cp .kokoro/test-samples-impl.sh "${TMPDIR}/test-samples-impl.sh" + echo "--- IMPORTANT IMPORTANT IMPORTANT ---" + echo "Now we rewind the repo back to the latest release..." LATEST_RELEASE=$(git describe --abbrev=0 --tags) git checkout $LATEST_RELEASE -fi - -# Exit early if samples directory doesn't exist -if [ ! -d "./samples" ]; then - echo "No tests run. `./samples` not found" - exit 0 -fi - -# Disable buffering, so that the logs stream through. -export PYTHONUNBUFFERED=1 - -# Debug: show build environment -env | grep KOKORO - -# Install nox -python3.6 -m pip install --upgrade --quiet nox - -# Use secrets acessor service account to get secrets -if [[ -f "${KOKORO_GFILE_DIR}/secrets_viewer_service_account.json" ]]; then - gcloud auth activate-service-account \ - --key-file="${KOKORO_GFILE_DIR}/secrets_viewer_service_account.json" \ - --project="cloud-devrel-kokoro-resources" -fi - -# This script will create 3 files: -# - testing/test-env.sh -# - testing/service-account.json -# - testing/client-secrets.json -./scripts/decrypt-secrets.sh - -source ./testing/test-env.sh -export GOOGLE_APPLICATION_CREDENTIALS=$(pwd)/testing/service-account.json - -# For cloud-run session, we activate the service account for gcloud sdk. -gcloud auth activate-service-account \ - --key-file "${GOOGLE_APPLICATION_CREDENTIALS}" - -export GOOGLE_CLIENT_SECRETS=$(pwd)/testing/client-secrets.json - -echo -e "\n******************** TESTING PROJECTS ********************" - -# Switch to 'fail at end' to allow all tests to complete before exiting. -set +e -# Use RTN to return a non-zero value if the test fails. -RTN=0 -ROOT=$(pwd) -# Find all requirements.txt in the samples directory (may break on whitespace). -for file in samples/**/requirements.txt; do - cd "$ROOT" - # Navigate to the project folder. - file=$(dirname "$file") - cd "$file" - - echo "------------------------------------------------------------" - echo "- testing $file" - echo "------------------------------------------------------------" - - # Use nox to execute the tests for the project. - python3.6 -m nox -s "$RUN_TESTS_SESSION" - EXIT=$? - - # If this is a periodic build, send the test log to the FlakyBot. - # See https://github.com/googleapis/repo-automation-bots/tree/master/packages/flakybot. - if [[ $KOKORO_BUILD_ARTIFACTS_SUBDIR = *"periodic"* ]]; then - chmod +x $KOKORO_GFILE_DIR/linux_amd64/flakybot - $KOKORO_GFILE_DIR/linux_amd64/flakybot + echo "The current head is: " + echo $(git rev-parse --verify HEAD) + echo "--- IMPORTANT IMPORTANT IMPORTANT ---" + # move back the test runner implementation if there's no file. + if [ ! -f .kokoro/test-samples-impl.sh ]; then + cp "${TMPDIR}/test-samples-impl.sh" .kokoro/test-samples-impl.sh fi +fi - if [[ $EXIT -ne 0 ]]; then - RTN=1 - echo -e "\n Testing failed: Nox returned a non-zero exit code. \n" - else - echo -e "\n Testing completed.\n" - fi - -done -cd "$ROOT" - -# Workaround for Kokoro permissions issue: delete secrets -rm testing/{test-env.sh,client-secrets.json,service-account.json} - -exit "$RTN" +exec .kokoro/test-samples-impl.sh diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a9024b15..32302e48 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -12,6 +12,6 @@ repos: hooks: - id: black - repo: https://gitlab.com/pycqa/flake8 - rev: 3.8.4 + rev: 3.9.0 hooks: - id: flake8 diff --git a/.trampolinerc b/.trampolinerc index 995ee291..383b6ec8 100644 --- a/.trampolinerc +++ b/.trampolinerc @@ -24,6 +24,7 @@ required_envvars+=( pass_down_envvars+=( "STAGING_BUCKET" "V2_STAGING_BUCKET" + "NOX_SESSION" ) # Prevent unintentional override on the default image. diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 35bf37c0..4f753672 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -70,9 +70,14 @@ We use `nox `__ to instrument our tests. - To test your changes, run unit tests with ``nox``:: $ nox -s unit-2.7 - $ nox -s unit-3.7 + $ nox -s unit-3.8 $ ... +- Args to pytest can be passed through the nox command separated by a `--`. For + example, to run a single test:: + + $ nox -s unit-3.8 -- -k + .. note:: The unit tests and system tests are described in the @@ -93,8 +98,12 @@ On Debian/Ubuntu:: ************ Coding Style ************ +- We use the automatic code formatter ``black``. You can run it using + the nox session ``blacken``. This will eliminate many lint errors. Run via:: + + $ nox -s blacken -- PEP8 compliance, with exceptions defined in the linter configuration. +- PEP8 compliance is required, with exceptions defined in the linter configuration. If you have ``nox`` installed, you can test that you have not introduced any non-compliant code via:: @@ -133,13 +142,18 @@ Running System Tests - To run system tests, you can execute:: - $ nox -s system-3.7 + # Run all system tests + $ nox -s system-3.8 $ nox -s system-2.7 + # Run a single system test + $ nox -s system-3.8 -- -k + + .. note:: System tests are only configured to run under Python 2.7 and - Python 3.7. For expediency, we do not run them in older versions + Python 3.8. For expediency, we do not run them in older versions of Python 3. This alone will not run the tests. You'll need to change some local diff --git a/MANIFEST.in b/MANIFEST.in index e9e29d12..e783f4c6 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -16,10 +16,10 @@ # Generated by synthtool. DO NOT EDIT! include README.rst LICENSE -recursive-include google *.json *.proto +recursive-include google *.json *.proto py.typed recursive-include tests * global-exclude *.py[co] global-exclude __pycache__ # Exclude scripts for samples readmegen -prune scripts/readme-gen \ No newline at end of file +prune scripts/readme-gen diff --git a/UPGRADING.md b/UPGRADING.md index f6c670c8..11bb021c 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -17,10 +17,10 @@ The 2.0.0 release requires Python 3.6+. Methods expect request objects. We provide a script that will convert most common use cases. -* Install the library +* Install the library with `libcst`. ```py -python3 -m pip install google-cloud-asset +python3 -m pip install google-cloud-asset[libcst] ``` * The script `fixup_asset_v1_keywords.py` is shipped with the library. It expects diff --git a/docs/asset_v1/asset_service.rst b/docs/asset_v1/asset_service.rst new file mode 100644 index 00000000..46426270 --- /dev/null +++ b/docs/asset_v1/asset_service.rst @@ -0,0 +1,11 @@ +AssetService +------------------------------ + +.. automodule:: google.cloud.asset_v1.services.asset_service + :members: + :inherited-members: + + +.. automodule:: google.cloud.asset_v1.services.asset_service.pagers + :members: + :inherited-members: diff --git a/docs/asset_v1/services.rst b/docs/asset_v1/services.rst index 7f520451..a5ddb91f 100644 --- a/docs/asset_v1/services.rst +++ b/docs/asset_v1/services.rst @@ -1,6 +1,6 @@ Services for Google Cloud Asset v1 API ====================================== +.. toctree:: + :maxdepth: 2 -.. automodule:: google.cloud.asset_v1.services.asset_service - :members: - :inherited-members: + asset_service diff --git a/docs/asset_v1/types.rst b/docs/asset_v1/types.rst index 750d9c16..c75a1efd 100644 --- a/docs/asset_v1/types.rst +++ b/docs/asset_v1/types.rst @@ -3,4 +3,5 @@ Types for Google Cloud Asset v1 API .. automodule:: google.cloud.asset_v1.types :members: + :undoc-members: :show-inheritance: diff --git a/docs/asset_v1p1beta1/asset_service.rst b/docs/asset_v1p1beta1/asset_service.rst new file mode 100644 index 00000000..f88f0e38 --- /dev/null +++ b/docs/asset_v1p1beta1/asset_service.rst @@ -0,0 +1,11 @@ +AssetService +------------------------------ + +.. automodule:: google.cloud.asset_v1p1beta1.services.asset_service + :members: + :inherited-members: + + +.. automodule:: google.cloud.asset_v1p1beta1.services.asset_service.pagers + :members: + :inherited-members: diff --git a/docs/asset_v1p1beta1/services.rst b/docs/asset_v1p1beta1/services.rst index e2f85315..2839e354 100644 --- a/docs/asset_v1p1beta1/services.rst +++ b/docs/asset_v1p1beta1/services.rst @@ -1,6 +1,6 @@ Services for Google Cloud Asset v1p1beta1 API ============================================= +.. toctree:: + :maxdepth: 2 -.. automodule:: google.cloud.asset_v1p1beta1.services.asset_service - :members: - :inherited-members: + asset_service diff --git a/docs/asset_v1p1beta1/types.rst b/docs/asset_v1p1beta1/types.rst index 0df91774..d0875802 100644 --- a/docs/asset_v1p1beta1/types.rst +++ b/docs/asset_v1p1beta1/types.rst @@ -3,4 +3,5 @@ Types for Google Cloud Asset v1p1beta1 API .. automodule:: google.cloud.asset_v1p1beta1.types :members: + :undoc-members: :show-inheritance: diff --git a/docs/asset_v1p2beta1/asset_service.rst b/docs/asset_v1p2beta1/asset_service.rst new file mode 100644 index 00000000..21bc405a --- /dev/null +++ b/docs/asset_v1p2beta1/asset_service.rst @@ -0,0 +1,6 @@ +AssetService +------------------------------ + +.. automodule:: google.cloud.asset_v1p2beta1.services.asset_service + :members: + :inherited-members: diff --git a/docs/asset_v1p2beta1/services.rst b/docs/asset_v1p2beta1/services.rst index 82401a22..f8ff126c 100644 --- a/docs/asset_v1p2beta1/services.rst +++ b/docs/asset_v1p2beta1/services.rst @@ -1,6 +1,6 @@ Services for Google Cloud Asset v1p2beta1 API ============================================= +.. toctree:: + :maxdepth: 2 -.. automodule:: google.cloud.asset_v1p2beta1.services.asset_service - :members: - :inherited-members: + asset_service diff --git a/docs/asset_v1p2beta1/types.rst b/docs/asset_v1p2beta1/types.rst index cfbf146e..b83adc35 100644 --- a/docs/asset_v1p2beta1/types.rst +++ b/docs/asset_v1p2beta1/types.rst @@ -3,4 +3,5 @@ Types for Google Cloud Asset v1p2beta1 API .. automodule:: google.cloud.asset_v1p2beta1.types :members: + :undoc-members: :show-inheritance: diff --git a/docs/asset_v1p4beta1/asset_service.rst b/docs/asset_v1p4beta1/asset_service.rst new file mode 100644 index 00000000..e46e3c5e --- /dev/null +++ b/docs/asset_v1p4beta1/asset_service.rst @@ -0,0 +1,6 @@ +AssetService +------------------------------ + +.. automodule:: google.cloud.asset_v1p4beta1.services.asset_service + :members: + :inherited-members: diff --git a/docs/asset_v1p4beta1/services.rst b/docs/asset_v1p4beta1/services.rst index 27b24147..6116177f 100644 --- a/docs/asset_v1p4beta1/services.rst +++ b/docs/asset_v1p4beta1/services.rst @@ -1,6 +1,6 @@ Services for Google Cloud Asset v1p4beta1 API ============================================= +.. toctree:: + :maxdepth: 2 -.. automodule:: google.cloud.asset_v1p4beta1.services.asset_service - :members: - :inherited-members: + asset_service diff --git a/docs/asset_v1p4beta1/types.rst b/docs/asset_v1p4beta1/types.rst index a91fd590..60ea41e5 100644 --- a/docs/asset_v1p4beta1/types.rst +++ b/docs/asset_v1p4beta1/types.rst @@ -3,4 +3,5 @@ Types for Google Cloud Asset v1p4beta1 API .. automodule:: google.cloud.asset_v1p4beta1.types :members: + :undoc-members: :show-inheritance: diff --git a/docs/asset_v1p5beta1/asset_service.rst b/docs/asset_v1p5beta1/asset_service.rst new file mode 100644 index 00000000..5286192b --- /dev/null +++ b/docs/asset_v1p5beta1/asset_service.rst @@ -0,0 +1,11 @@ +AssetService +------------------------------ + +.. automodule:: google.cloud.asset_v1p5beta1.services.asset_service + :members: + :inherited-members: + + +.. automodule:: google.cloud.asset_v1p5beta1.services.asset_service.pagers + :members: + :inherited-members: diff --git a/docs/asset_v1p5beta1/services.rst b/docs/asset_v1p5beta1/services.rst index 09749b31..9383f20c 100644 --- a/docs/asset_v1p5beta1/services.rst +++ b/docs/asset_v1p5beta1/services.rst @@ -1,6 +1,6 @@ Services for Google Cloud Asset v1p5beta1 API ============================================= +.. toctree:: + :maxdepth: 2 -.. automodule:: google.cloud.asset_v1p5beta1.services.asset_service - :members: - :inherited-members: + asset_service diff --git a/docs/asset_v1p5beta1/types.rst b/docs/asset_v1p5beta1/types.rst index 0d143122..31650c9a 100644 --- a/docs/asset_v1p5beta1/types.rst +++ b/docs/asset_v1p5beta1/types.rst @@ -3,4 +3,5 @@ Types for Google Cloud Asset v1p5beta1 API .. automodule:: google.cloud.asset_v1p5beta1.types :members: + :undoc-members: :show-inheritance: diff --git a/google/cloud/asset_v1/services/asset_service/async_client.py b/google/cloud/asset_v1/services/asset_service/async_client.py index 98c58ffa..56d7a1c2 100644 --- a/google/cloud/asset_v1/services/asset_service/async_client.py +++ b/google/cloud/asset_v1/services/asset_service/async_client.py @@ -78,7 +78,36 @@ class AssetServiceAsyncClient: AssetServiceClient.parse_common_location_path ) - from_service_account_file = AssetServiceClient.from_service_account_file + @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: + AssetServiceAsyncClient: The constructed client. + """ + return AssetServiceClient.from_service_account_info.__func__(AssetServiceAsyncClient, 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: + AssetServiceAsyncClient: The constructed client. + """ + return AssetServiceClient.from_service_account_file.__func__(AssetServiceAsyncClient, filename, *args, **kwargs) # type: ignore + from_service_account_json = from_service_account_file @property @@ -165,7 +194,7 @@ async def export_assets( the export operation usually finishes within 5 minutes. Args: - request (:class:`~.asset_service.ExportAssetsRequest`): + request (:class:`google.cloud.asset_v1.types.ExportAssetsRequest`): The request object. Export asset request. retry (google.api_core.retry.Retry): Designation of what errors, if any, @@ -175,16 +204,14 @@ async def export_assets( sent along with the request as metadata. Returns: - ~.operation_async.AsyncOperation: + google.api_core.operation_async.AsyncOperation: An object representing a long-running operation. - The result type for the operation will be - :class:``~.asset_service.ExportAssetsResponse``: The - export asset response. This message is returned by the - [google.longrunning.Operations.GetOperation][google.longrunning.Operations.GetOperation] - method in the returned - [google.longrunning.Operation.response][google.longrunning.Operation.response] - field. + The result type for the operation will be :class:`google.cloud.asset_v1.types.ExportAssetsResponse` The export asset response. This message is returned by the + [google.longrunning.Operations.GetOperation][google.longrunning.Operations.GetOperation] + method in the returned + [google.longrunning.Operation.response][google.longrunning.Operation.response] + field. """ # Create or coerce a protobuf request object. @@ -236,7 +263,7 @@ async def batch_get_assets_history( INVALID_ARGUMENT error. Args: - request (:class:`~.asset_service.BatchGetAssetsHistoryRequest`): + request (:class:`google.cloud.asset_v1.types.BatchGetAssetsHistoryRequest`): The request object. Batch get assets history request. retry (google.api_core.retry.Retry): Designation of what errors, if any, @@ -246,7 +273,7 @@ async def batch_get_assets_history( sent along with the request as metadata. Returns: - ~.asset_service.BatchGetAssetsHistoryResponse: + google.cloud.asset_v1.types.BatchGetAssetsHistoryResponse: Batch get assets history response. """ # Create or coerce a protobuf request object. @@ -264,6 +291,7 @@ async def batch_get_assets_history( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=60.0, ), default_timeout=60.0, client_info=DEFAULT_CLIENT_INFO, @@ -295,7 +323,7 @@ async def create_feed( updates. Args: - request (:class:`~.asset_service.CreateFeedRequest`): + request (:class:`google.cloud.asset_v1.types.CreateFeedRequest`): The request object. Create asset feed request. parent (:class:`str`): Required. The name of the @@ -307,6 +335,7 @@ async def create_feed( (such as "projects/my-project-id")", or a project number (such as "projects/12345"). + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -318,7 +347,7 @@ async def create_feed( sent along with the request as metadata. Returns: - ~.asset_service.Feed: + google.cloud.asset_v1.types.Feed: An asset feed used to export asset updates to a destinations. An asset feed filter controls what updates are @@ -378,13 +407,14 @@ async def get_feed( r"""Gets details about an asset feed. Args: - request (:class:`~.asset_service.GetFeedRequest`): + request (:class:`google.cloud.asset_v1.types.GetFeedRequest`): The request object. Get asset feed request. name (:class:`str`): Required. The name of the Feed and it must be in the format of: projects/project_number/feeds/feed_id folders/folder_number/feeds/feed_id organizations/organization_number/feeds/feed_id + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -396,7 +426,7 @@ async def get_feed( sent along with the request as metadata. Returns: - ~.asset_service.Feed: + google.cloud.asset_v1.types.Feed: An asset feed used to export asset updates to a destinations. An asset feed filter controls what updates are @@ -435,6 +465,7 @@ async def get_feed( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=60.0, ), default_timeout=60.0, client_info=DEFAULT_CLIENT_INFO, @@ -465,7 +496,7 @@ async def list_feeds( project/folder/organization. Args: - request (:class:`~.asset_service.ListFeedsRequest`): + request (:class:`google.cloud.asset_v1.types.ListFeedsRequest`): The request object. List asset feeds request. parent (:class:`str`): Required. The parent @@ -474,6 +505,7 @@ async def list_feeds( project/folder/organization number (such as "folders/12345")", or a project ID (such as "projects/my-project-id"). + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -485,7 +517,7 @@ async def list_feeds( sent along with the request as metadata. Returns: - ~.asset_service.ListFeedsResponse: + google.cloud.asset_v1.types.ListFeedsResponse: """ # Create or coerce a protobuf request object. @@ -517,6 +549,7 @@ async def list_feeds( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=60.0, ), default_timeout=60.0, client_info=DEFAULT_CLIENT_INFO, @@ -546,14 +579,15 @@ async def update_feed( r"""Updates an asset feed configuration. Args: - request (:class:`~.asset_service.UpdateFeedRequest`): + request (:class:`google.cloud.asset_v1.types.UpdateFeedRequest`): The request object. Update asset feed request. - feed (:class:`~.asset_service.Feed`): + feed (:class:`google.cloud.asset_v1.types.Feed`): Required. The new values of feed details. It must match an existing feed and the field ``name`` must be in the format of: projects/project_number/feeds/feed_id or folders/folder_number/feeds/feed_id or organizations/organization_number/feeds/feed_id. + This corresponds to the ``feed`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -565,7 +599,7 @@ async def update_feed( sent along with the request as metadata. Returns: - ~.asset_service.Feed: + google.cloud.asset_v1.types.Feed: An asset feed used to export asset updates to a destinations. An asset feed filter controls what updates are @@ -627,13 +661,14 @@ async def delete_feed( r"""Deletes an asset feed. Args: - request (:class:`~.asset_service.DeleteFeedRequest`): + request (:class:`google.cloud.asset_v1.types.DeleteFeedRequest`): The request object. name (:class:`str`): Required. The name of the feed and it must be in the format of: projects/project_number/feeds/feed_id folders/folder_number/feeds/feed_id organizations/organization_number/feeds/feed_id + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -673,6 +708,7 @@ async def delete_feed( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=60.0, ), default_timeout=60.0, client_info=DEFAULT_CLIENT_INFO, @@ -706,7 +742,7 @@ async def search_all_resources( desired scope, otherwise the request will be rejected. Args: - request (:class:`~.asset_service.SearchAllResourcesRequest`): + request (:class:`google.cloud.asset_v1.types.SearchAllResourcesRequest`): The request object. Search all resources request. scope (:class:`str`): Required. A scope can be a project, a folder, or an @@ -722,6 +758,7 @@ async def search_all_resources( - folders/{FOLDER_NUMBER} (e.g., "folders/1234567") - organizations/{ORGANIZATION_NUMBER} (e.g., "organizations/123456") + This corresponds to the ``scope`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -765,6 +802,7 @@ async def search_all_resources( Cloud resources that contain "Important" as a word in any of the searchable fields and are also located in the "us-west1" region or the "global" location. + This corresponds to the ``query`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -773,6 +811,7 @@ async def search_all_resources( searches for. If empty, it will search all the `searchable asset types `__. + This corresponds to the ``asset_types`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -784,7 +823,7 @@ async def search_all_resources( sent along with the request as metadata. Returns: - ~.pagers.SearchAllResourcesAsyncPager: + google.cloud.asset_v1.services.asset_service.pagers.SearchAllResourcesAsyncPager: Search all resources response. Iterating over this object will yield results and resolve additional pages @@ -825,6 +864,7 @@ async def search_all_resources( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=15.0, ), default_timeout=15.0, client_info=DEFAULT_CLIENT_INFO, @@ -864,7 +904,7 @@ async def search_all_iam_policies( desired scope, otherwise the request will be rejected. Args: - request (:class:`~.asset_service.SearchAllIamPoliciesRequest`): + request (:class:`google.cloud.asset_v1.types.SearchAllIamPoliciesRequest`): The request object. Search all IAM policies request. scope (:class:`str`): Required. A scope can be a project, a folder, or an @@ -880,6 +920,7 @@ async def search_all_iam_policies( - folders/{FOLDER_NUMBER} (e.g., "folders/1234567") - organizations/{ORGANIZATION_NUMBER} (e.g., "organizations/123456") + This corresponds to the ``scope`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -916,6 +957,7 @@ async def search_all_iam_policies( find IAM policy bindings that are set on resources "instance1" or "instance2" and also specify user "amy". + This corresponds to the ``query`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -927,7 +969,7 @@ async def search_all_iam_policies( sent along with the request as metadata. Returns: - ~.pagers.SearchAllIamPoliciesAsyncPager: + google.cloud.asset_v1.services.asset_service.pagers.SearchAllIamPoliciesAsyncPager: Search all IAM policies response. Iterating over this object will yield results and resolve additional pages @@ -965,6 +1007,7 @@ async def search_all_iam_policies( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=15.0, ), default_timeout=15.0, client_info=DEFAULT_CLIENT_INFO, @@ -1000,7 +1043,7 @@ async def analyze_iam_policy( what accesses on which resources. Args: - request (:class:`~.asset_service.AnalyzeIamPolicyRequest`): + request (:class:`google.cloud.asset_v1.types.AnalyzeIamPolicyRequest`): The request object. A request message for [AssetService.AnalyzeIamPolicy][google.cloud.asset.v1.AssetService.AnalyzeIamPolicy]. @@ -1011,7 +1054,7 @@ async def analyze_iam_policy( sent along with the request as metadata. Returns: - ~.asset_service.AnalyzeIamPolicyResponse: + google.cloud.asset_v1.types.AnalyzeIamPolicyResponse: A response message for [AssetService.AnalyzeIamPolicy][google.cloud.asset.v1.AssetService.AnalyzeIamPolicy]. @@ -1029,6 +1072,7 @@ async def analyze_iam_policy( maximum=60.0, multiplier=1.3, predicate=retries.if_exception_type(exceptions.ServiceUnavailable,), + deadline=300.0, ), default_timeout=300.0, client_info=DEFAULT_CLIENT_INFO, @@ -1070,7 +1114,7 @@ async def analyze_iam_policy_longrunning( to help callers to map responses to requests. Args: - request (:class:`~.asset_service.AnalyzeIamPolicyLongrunningRequest`): + request (:class:`google.cloud.asset_v1.types.AnalyzeIamPolicyLongrunningRequest`): The request object. A request message for [AssetService.AnalyzeIamPolicyLongrunning][google.cloud.asset.v1.AssetService.AnalyzeIamPolicyLongrunning]. @@ -1081,11 +1125,11 @@ async def analyze_iam_policy_longrunning( sent along with the request as metadata. Returns: - ~.operation_async.AsyncOperation: + google.api_core.operation_async.AsyncOperation: An object representing a long-running operation. The result type for the operation will be - :class:``~.asset_service.AnalyzeIamPolicyLongrunningResponse``: + :class:`google.cloud.asset_v1.types.AnalyzeIamPolicyLongrunningResponse` A response message for [AssetService.AnalyzeIamPolicyLongrunning][google.cloud.asset.v1.AssetService.AnalyzeIamPolicyLongrunning]. diff --git a/google/cloud/asset_v1/services/asset_service/client.py b/google/cloud/asset_v1/services/asset_service/client.py index ef31e4a0..f65e8ba8 100644 --- a/google/cloud/asset_v1/services/asset_service/client.py +++ b/google/cloud/asset_v1/services/asset_service/client.py @@ -112,6 +112,22 @@ def _get_default_mtls_endpoint(api_endpoint): 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: + AssetServiceClient: 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 @@ -124,7 +140,7 @@ def from_service_account_file(cls, filename: str, *args, **kwargs): kwargs: Additional arguments to pass to the constructor. Returns: - {@api.name}: The constructed client. + AssetServiceClient: The constructed client. """ credentials = service_account.Credentials.from_service_account_file(filename) kwargs["credentials"] = credentials @@ -232,10 +248,10 @@ def __init__( 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, ~.AssetServiceTransport]): The + transport (Union[str, AssetServiceTransport]): The transport to use. If set to None, a transport is chosen automatically. - client_options (client_options_lib.ClientOptions): Custom options for the + 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 @@ -271,21 +287,17 @@ def __init__( util.strtobool(os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false")) ) - ssl_credentials = None + client_cert_source_func = None is_mtls = False if use_client_cert: if client_options.client_cert_source: - import grpc # type: ignore - - cert, key = client_options.client_cert_source() - ssl_credentials = grpc.ssl_channel_credentials( - certificate_chain=cert, private_key=key - ) is_mtls = True + client_cert_source_func = client_options.client_cert_source else: - creds = SslCredentials() - is_mtls = creds.is_mtls - ssl_credentials = creds.ssl_credentials if is_mtls else None + is_mtls = mtls.has_default_client_cert_source() + client_cert_source_func = ( + mtls.default_client_cert_source() if is_mtls else None + ) # Figure out which api endpoint to use. if client_options.api_endpoint is not None: @@ -328,7 +340,7 @@ def __init__( credentials_file=client_options.credentials_file, host=api_endpoint, scopes=client_options.scopes, - ssl_channel_credentials=ssl_credentials, + client_cert_source_for_mtls=client_cert_source_func, quota_project_id=client_options.quota_project_id, client_info=client_info, ) @@ -356,7 +368,7 @@ def export_assets( the export operation usually finishes within 5 minutes. Args: - request (:class:`~.asset_service.ExportAssetsRequest`): + request (google.cloud.asset_v1.types.ExportAssetsRequest): The request object. Export asset request. retry (google.api_core.retry.Retry): Designation of what errors, if any, @@ -366,16 +378,14 @@ def export_assets( sent along with the request as metadata. Returns: - ~.operation.Operation: + google.api_core.operation.Operation: An object representing a long-running operation. - The result type for the operation will be - :class:``~.asset_service.ExportAssetsResponse``: The - export asset response. This message is returned by the - [google.longrunning.Operations.GetOperation][google.longrunning.Operations.GetOperation] - method in the returned - [google.longrunning.Operation.response][google.longrunning.Operation.response] - field. + The result type for the operation will be :class:`google.cloud.asset_v1.types.ExportAssetsResponse` The export asset response. This message is returned by the + [google.longrunning.Operations.GetOperation][google.longrunning.Operations.GetOperation] + method in the returned + [google.longrunning.Operation.response][google.longrunning.Operation.response] + field. """ # Create or coerce a protobuf request object. @@ -428,7 +438,7 @@ def batch_get_assets_history( INVALID_ARGUMENT error. Args: - request (:class:`~.asset_service.BatchGetAssetsHistoryRequest`): + request (google.cloud.asset_v1.types.BatchGetAssetsHistoryRequest): The request object. Batch get assets history request. retry (google.api_core.retry.Retry): Designation of what errors, if any, @@ -438,7 +448,7 @@ def batch_get_assets_history( sent along with the request as metadata. Returns: - ~.asset_service.BatchGetAssetsHistoryResponse: + google.cloud.asset_v1.types.BatchGetAssetsHistoryResponse: Batch get assets history response. """ # Create or coerce a protobuf request object. @@ -480,9 +490,9 @@ def create_feed( updates. Args: - request (:class:`~.asset_service.CreateFeedRequest`): + request (google.cloud.asset_v1.types.CreateFeedRequest): The request object. Create asset feed request. - parent (:class:`str`): + parent (str): Required. The name of the project/folder/organization where this feed should be created in. It can only @@ -492,6 +502,7 @@ def create_feed( (such as "projects/my-project-id")", or a project number (such as "projects/12345"). + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -503,7 +514,7 @@ def create_feed( sent along with the request as metadata. Returns: - ~.asset_service.Feed: + google.cloud.asset_v1.types.Feed: An asset feed used to export asset updates to a destinations. An asset feed filter controls what updates are @@ -564,13 +575,14 @@ def get_feed( r"""Gets details about an asset feed. Args: - request (:class:`~.asset_service.GetFeedRequest`): + request (google.cloud.asset_v1.types.GetFeedRequest): The request object. Get asset feed request. - name (:class:`str`): + name (str): Required. The name of the Feed and it must be in the format of: projects/project_number/feeds/feed_id folders/folder_number/feeds/feed_id organizations/organization_number/feeds/feed_id + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -582,7 +594,7 @@ def get_feed( sent along with the request as metadata. Returns: - ~.asset_service.Feed: + google.cloud.asset_v1.types.Feed: An asset feed used to export asset updates to a destinations. An asset feed filter controls what updates are @@ -644,15 +656,16 @@ def list_feeds( project/folder/organization. Args: - request (:class:`~.asset_service.ListFeedsRequest`): + request (google.cloud.asset_v1.types.ListFeedsRequest): The request object. List asset feeds request. - parent (:class:`str`): + parent (str): Required. The parent project/folder/organization whose feeds are to be listed. It can only be using project/folder/organization number (such as "folders/12345")", or a project ID (such as "projects/my-project-id"). + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -664,7 +677,7 @@ def list_feeds( sent along with the request as metadata. Returns: - ~.asset_service.ListFeedsResponse: + google.cloud.asset_v1.types.ListFeedsResponse: """ # Create or coerce a protobuf request object. @@ -718,14 +731,15 @@ def update_feed( r"""Updates an asset feed configuration. Args: - request (:class:`~.asset_service.UpdateFeedRequest`): + request (google.cloud.asset_v1.types.UpdateFeedRequest): The request object. Update asset feed request. - feed (:class:`~.asset_service.Feed`): + feed (google.cloud.asset_v1.types.Feed): Required. The new values of feed details. It must match an existing feed and the field ``name`` must be in the format of: projects/project_number/feeds/feed_id or folders/folder_number/feeds/feed_id or organizations/organization_number/feeds/feed_id. + This corresponds to the ``feed`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -737,7 +751,7 @@ def update_feed( sent along with the request as metadata. Returns: - ~.asset_service.Feed: + google.cloud.asset_v1.types.Feed: An asset feed used to export asset updates to a destinations. An asset feed filter controls what updates are @@ -800,13 +814,14 @@ def delete_feed( r"""Deletes an asset feed. Args: - request (:class:`~.asset_service.DeleteFeedRequest`): + request (google.cloud.asset_v1.types.DeleteFeedRequest): The request object. - name (:class:`str`): + name (str): Required. The name of the feed and it must be in the format of: projects/project_number/feeds/feed_id folders/folder_number/feeds/feed_id organizations/organization_number/feeds/feed_id + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -872,9 +887,9 @@ def search_all_resources( desired scope, otherwise the request will be rejected. Args: - request (:class:`~.asset_service.SearchAllResourcesRequest`): + request (google.cloud.asset_v1.types.SearchAllResourcesRequest): The request object. Search all resources request. - scope (:class:`str`): + scope (str): Required. A scope can be a project, a folder, or an organization. The search is limited to the resources within the ``scope``. The caller must be granted the @@ -888,10 +903,11 @@ def search_all_resources( - folders/{FOLDER_NUMBER} (e.g., "folders/1234567") - organizations/{ORGANIZATION_NUMBER} (e.g., "organizations/123456") + This corresponds to the ``scope`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - query (:class:`str`): + query (str): Optional. The query statement. See `how to construct a query `__ for more information. If not specified or empty, it will @@ -931,14 +947,16 @@ def search_all_resources( Cloud resources that contain "Important" as a word in any of the searchable fields and are also located in the "us-west1" region or the "global" location. + This corresponds to the ``query`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - asset_types (:class:`Sequence[str]`): + asset_types (Sequence[str]): Optional. A list of asset types that this request searches for. If empty, it will search all the `searchable asset types `__. + This corresponds to the ``asset_types`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -950,7 +968,7 @@ def search_all_resources( sent along with the request as metadata. Returns: - ~.pagers.SearchAllResourcesPager: + google.cloud.asset_v1.services.asset_service.pagers.SearchAllResourcesPager: Search all resources response. Iterating over this object will yield results and resolve additional pages @@ -981,9 +999,8 @@ def search_all_resources( request.scope = scope if query is not None: request.query = query - - if asset_types: - request.asset_types.extend(asset_types) + if asset_types is not None: + request.asset_types = asset_types # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. @@ -1023,9 +1040,9 @@ def search_all_iam_policies( desired scope, otherwise the request will be rejected. Args: - request (:class:`~.asset_service.SearchAllIamPoliciesRequest`): + request (google.cloud.asset_v1.types.SearchAllIamPoliciesRequest): The request object. Search all IAM policies request. - scope (:class:`str`): + scope (str): Required. A scope can be a project, a folder, or an organization. The search is limited to the IAM policies within the ``scope``. The caller must be granted the @@ -1039,10 +1056,11 @@ def search_all_iam_policies( - folders/{FOLDER_NUMBER} (e.g., "folders/1234567") - organizations/{ORGANIZATION_NUMBER} (e.g., "organizations/123456") + This corresponds to the ``scope`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - query (:class:`str`): + query (str): Optional. The query statement. See `how to construct a query `__ for more information. If not specified or empty, it will @@ -1075,6 +1093,7 @@ def search_all_iam_policies( find IAM policy bindings that are set on resources "instance1" or "instance2" and also specify user "amy". + This corresponds to the ``query`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -1086,7 +1105,7 @@ def search_all_iam_policies( sent along with the request as metadata. Returns: - ~.pagers.SearchAllIamPoliciesPager: + google.cloud.asset_v1.services.asset_service.pagers.SearchAllIamPoliciesPager: Search all IAM policies response. Iterating over this object will yield results and resolve additional pages @@ -1152,7 +1171,7 @@ def analyze_iam_policy( what accesses on which resources. Args: - request (:class:`~.asset_service.AnalyzeIamPolicyRequest`): + request (google.cloud.asset_v1.types.AnalyzeIamPolicyRequest): The request object. A request message for [AssetService.AnalyzeIamPolicy][google.cloud.asset.v1.AssetService.AnalyzeIamPolicy]. @@ -1163,7 +1182,7 @@ def analyze_iam_policy( sent along with the request as metadata. Returns: - ~.asset_service.AnalyzeIamPolicyResponse: + google.cloud.asset_v1.types.AnalyzeIamPolicyResponse: A response message for [AssetService.AnalyzeIamPolicy][google.cloud.asset.v1.AssetService.AnalyzeIamPolicy]. @@ -1217,7 +1236,7 @@ def analyze_iam_policy_longrunning( to help callers to map responses to requests. Args: - request (:class:`~.asset_service.AnalyzeIamPolicyLongrunningRequest`): + request (google.cloud.asset_v1.types.AnalyzeIamPolicyLongrunningRequest): The request object. A request message for [AssetService.AnalyzeIamPolicyLongrunning][google.cloud.asset.v1.AssetService.AnalyzeIamPolicyLongrunning]. @@ -1228,11 +1247,11 @@ def analyze_iam_policy_longrunning( sent along with the request as metadata. Returns: - ~.operation.Operation: + google.api_core.operation.Operation: An object representing a long-running operation. The result type for the operation will be - :class:``~.asset_service.AnalyzeIamPolicyLongrunningResponse``: + :class:`google.cloud.asset_v1.types.AnalyzeIamPolicyLongrunningResponse` A response message for [AssetService.AnalyzeIamPolicyLongrunning][google.cloud.asset.v1.AssetService.AnalyzeIamPolicyLongrunning]. diff --git a/google/cloud/asset_v1/services/asset_service/pagers.py b/google/cloud/asset_v1/services/asset_service/pagers.py index 84531887..1c251731 100644 --- a/google/cloud/asset_v1/services/asset_service/pagers.py +++ b/google/cloud/asset_v1/services/asset_service/pagers.py @@ -15,7 +15,16 @@ # limitations under the License. # -from typing import Any, AsyncIterable, Awaitable, Callable, Iterable, Sequence, Tuple +from typing import ( + Any, + AsyncIterable, + Awaitable, + Callable, + Iterable, + Sequence, + Tuple, + Optional, +) from google.cloud.asset_v1.types import asset_service from google.cloud.asset_v1.types import assets @@ -25,7 +34,7 @@ class SearchAllResourcesPager: """A pager for iterating through ``search_all_resources`` requests. This class thinly wraps an initial - :class:`~.asset_service.SearchAllResourcesResponse` object, and + :class:`google.cloud.asset_v1.types.SearchAllResourcesResponse` object, and provides an ``__iter__`` method to iterate through its ``results`` field. @@ -34,7 +43,7 @@ class SearchAllResourcesPager: through the ``results`` field on the corresponding responses. - All the usual :class:`~.asset_service.SearchAllResourcesResponse` + All the usual :class:`google.cloud.asset_v1.types.SearchAllResourcesResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -52,9 +61,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.asset_service.SearchAllResourcesRequest`): + request (google.cloud.asset_v1.types.SearchAllResourcesRequest): The initial request object. - response (:class:`~.asset_service.SearchAllResourcesResponse`): + response (google.cloud.asset_v1.types.SearchAllResourcesResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -87,7 +96,7 @@ class SearchAllResourcesAsyncPager: """A pager for iterating through ``search_all_resources`` requests. This class thinly wraps an initial - :class:`~.asset_service.SearchAllResourcesResponse` object, and + :class:`google.cloud.asset_v1.types.SearchAllResourcesResponse` object, and provides an ``__aiter__`` method to iterate through its ``results`` field. @@ -96,7 +105,7 @@ class SearchAllResourcesAsyncPager: through the ``results`` field on the corresponding responses. - All the usual :class:`~.asset_service.SearchAllResourcesResponse` + All the usual :class:`google.cloud.asset_v1.types.SearchAllResourcesResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -114,9 +123,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.asset_service.SearchAllResourcesRequest`): + request (google.cloud.asset_v1.types.SearchAllResourcesRequest): The initial request object. - response (:class:`~.asset_service.SearchAllResourcesResponse`): + response (google.cloud.asset_v1.types.SearchAllResourcesResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -153,7 +162,7 @@ class SearchAllIamPoliciesPager: """A pager for iterating through ``search_all_iam_policies`` requests. This class thinly wraps an initial - :class:`~.asset_service.SearchAllIamPoliciesResponse` object, and + :class:`google.cloud.asset_v1.types.SearchAllIamPoliciesResponse` object, and provides an ``__iter__`` method to iterate through its ``results`` field. @@ -162,7 +171,7 @@ class SearchAllIamPoliciesPager: through the ``results`` field on the corresponding responses. - All the usual :class:`~.asset_service.SearchAllIamPoliciesResponse` + All the usual :class:`google.cloud.asset_v1.types.SearchAllIamPoliciesResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -180,9 +189,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.asset_service.SearchAllIamPoliciesRequest`): + request (google.cloud.asset_v1.types.SearchAllIamPoliciesRequest): The initial request object. - response (:class:`~.asset_service.SearchAllIamPoliciesResponse`): + response (google.cloud.asset_v1.types.SearchAllIamPoliciesResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -215,7 +224,7 @@ class SearchAllIamPoliciesAsyncPager: """A pager for iterating through ``search_all_iam_policies`` requests. This class thinly wraps an initial - :class:`~.asset_service.SearchAllIamPoliciesResponse` object, and + :class:`google.cloud.asset_v1.types.SearchAllIamPoliciesResponse` object, and provides an ``__aiter__`` method to iterate through its ``results`` field. @@ -224,7 +233,7 @@ class SearchAllIamPoliciesAsyncPager: through the ``results`` field on the corresponding responses. - All the usual :class:`~.asset_service.SearchAllIamPoliciesResponse` + All the usual :class:`google.cloud.asset_v1.types.SearchAllIamPoliciesResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -242,9 +251,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.asset_service.SearchAllIamPoliciesRequest`): + request (google.cloud.asset_v1.types.SearchAllIamPoliciesRequest): The initial request object. - response (:class:`~.asset_service.SearchAllIamPoliciesResponse`): + response (google.cloud.asset_v1.types.SearchAllIamPoliciesResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. diff --git a/google/cloud/asset_v1/services/asset_service/transports/base.py b/google/cloud/asset_v1/services/asset_service/transports/base.py index 2440e350..22201371 100644 --- a/google/cloud/asset_v1/services/asset_service/transports/base.py +++ b/google/cloud/asset_v1/services/asset_service/transports/base.py @@ -70,10 +70,10 @@ def __init__( scope (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 + 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. """ # Save the hostname. Default to port 443 (HTTPS) if none is specified. @@ -81,6 +81,9 @@ def __init__( host += ":443" self._host = host + # Save the scopes. + self._scopes = scopes or self.AUTH_SCOPES + # If no credentials are provided, then determine the appropriate # defaults. if credentials and credentials_file: @@ -90,20 +93,17 @@ def __init__( if credentials_file is not None: credentials, _ = auth.load_credentials_from_file( - credentials_file, scopes=scopes, quota_project_id=quota_project_id + credentials_file, scopes=self._scopes, quota_project_id=quota_project_id ) elif credentials is None: credentials, _ = auth.default( - scopes=scopes, quota_project_id=quota_project_id + scopes=self._scopes, quota_project_id=quota_project_id ) # Save the credentials. self._credentials = credentials - # Lifted into its own function so it can be stubbed out during tests. - self._prep_wrapped_messages(client_info) - def _prep_wrapped_messages(self, client_info): # Precompute the wrapped methods. self._wrapped_methods = { @@ -119,6 +119,7 @@ def _prep_wrapped_messages(self, client_info): predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=60.0, ), default_timeout=60.0, client_info=client_info, @@ -135,6 +136,7 @@ def _prep_wrapped_messages(self, client_info): predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=60.0, ), default_timeout=60.0, client_info=client_info, @@ -148,6 +150,7 @@ def _prep_wrapped_messages(self, client_info): predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=60.0, ), default_timeout=60.0, client_info=client_info, @@ -164,6 +167,7 @@ def _prep_wrapped_messages(self, client_info): predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=60.0, ), default_timeout=60.0, client_info=client_info, @@ -177,6 +181,7 @@ def _prep_wrapped_messages(self, client_info): predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=15.0, ), default_timeout=15.0, client_info=client_info, @@ -190,6 +195,7 @@ def _prep_wrapped_messages(self, client_info): predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=15.0, ), default_timeout=15.0, client_info=client_info, @@ -201,6 +207,7 @@ def _prep_wrapped_messages(self, client_info): maximum=60.0, multiplier=1.3, predicate=retries.if_exception_type(exceptions.ServiceUnavailable,), + deadline=300.0, ), default_timeout=300.0, client_info=client_info, diff --git a/google/cloud/asset_v1/services/asset_service/transports/grpc.py b/google/cloud/asset_v1/services/asset_service/transports/grpc.py index acfa9f03..daf07dfa 100644 --- a/google/cloud/asset_v1/services/asset_service/transports/grpc.py +++ b/google/cloud/asset_v1/services/asset_service/transports/grpc.py @@ -60,6 +60,7 @@ def __init__( 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, ) -> None: @@ -90,6 +91,10 @@ def __init__( ``api_mtls_endpoint`` is None. ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials for 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 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): @@ -104,72 +109,61 @@ def __init__( 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 = 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: - # Sanity check: Ensure that channel and credentials are not both - # provided. + # 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 - elif api_mtls_endpoint: - warnings.warn( - "api_mtls_endpoint and client_cert_source are deprecated", - DeprecationWarning, - ) - host = ( - api_mtls_endpoint - if ":" in api_mtls_endpoint - else api_mtls_endpoint + ":443" - ) + 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 - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) - - # Create SSL credentials with client_cert_source or application - # default SSL credentials. - if client_cert_source: - cert, key = client_cert_source() - ssl_credentials = grpc.ssl_channel_credentials( - certificate_chain=cert, private_key=key - ) else: - ssl_credentials = SslCredentials().ssl_credentials + 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 + ) - # create a new channel. The provided one is ignored. - self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, - credentials_file=credentials_file, - ssl_credentials=ssl_credentials, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - options=[ - ("grpc.max_send_message_length", -1), - ("grpc.max_receive_message_length", -1), - ], - ) - self._ssl_channel_credentials = ssl_credentials - else: - host = host if ":" in host else host + ":443" - - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) + # 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, + ) - # create a new channel. The provided one is ignored. + if not self._grpc_channel: self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, + self._host, + credentials=self._credentials, credentials_file=credentials_file, - ssl_credentials=ssl_channel_credentials, - scopes=scopes or self.AUTH_SCOPES, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, quota_project_id=quota_project_id, options=[ ("grpc.max_send_message_length", -1), @@ -177,18 +171,8 @@ def __init__( ], ) - self._stubs = {} # type: Dict[str, Callable] - self._operations_client = None - - # Run the base constructor. - super().__init__( - host=host, - credentials=credentials, - credentials_file=credentials_file, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - client_info=client_info, - ) + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) @classmethod def create_channel( @@ -202,7 +186,7 @@ def create_channel( ) -> grpc.Channel: """Create and return a gRPC channel object. Args: - address (Optional[str]): The host for the channel to use. + 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 diff --git a/google/cloud/asset_v1/services/asset_service/transports/grpc_asyncio.py b/google/cloud/asset_v1/services/asset_service/transports/grpc_asyncio.py index ae98bc22..2bb35c01 100644 --- a/google/cloud/asset_v1/services/asset_service/transports/grpc_asyncio.py +++ b/google/cloud/asset_v1/services/asset_service/transports/grpc_asyncio.py @@ -64,7 +64,7 @@ def create_channel( ) -> aio.Channel: """Create and return a gRPC AsyncIO channel object. Args: - address (Optional[str]): The host for the channel to use. + 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 @@ -104,6 +104,7 @@ def __init__( 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, ) -> None: @@ -135,12 +136,16 @@ def __init__( ``api_mtls_endpoint`` is None. ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials for 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 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 + 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: @@ -149,72 +154,61 @@ def __init__( 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 = 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: - # Sanity check: Ensure that channel and credentials are not both - # provided. + # 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 - elif api_mtls_endpoint: - warnings.warn( - "api_mtls_endpoint and client_cert_source are deprecated", - DeprecationWarning, - ) - host = ( - api_mtls_endpoint - if ":" in api_mtls_endpoint - else api_mtls_endpoint + ":443" - ) + 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 - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) - - # Create SSL credentials with client_cert_source or application - # default SSL credentials. - if client_cert_source: - cert, key = client_cert_source() - ssl_credentials = grpc.ssl_channel_credentials( - certificate_chain=cert, private_key=key - ) else: - ssl_credentials = SslCredentials().ssl_credentials + 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 + ) - # create a new channel. The provided one is ignored. - self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, - credentials_file=credentials_file, - ssl_credentials=ssl_credentials, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - options=[ - ("grpc.max_send_message_length", -1), - ("grpc.max_receive_message_length", -1), - ], - ) - self._ssl_channel_credentials = ssl_credentials - else: - host = host if ":" in host else host + ":443" - - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) + # 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, + ) - # create a new channel. The provided one is ignored. + if not self._grpc_channel: self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, + self._host, + credentials=self._credentials, credentials_file=credentials_file, - ssl_credentials=ssl_channel_credentials, - scopes=scopes or self.AUTH_SCOPES, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, quota_project_id=quota_project_id, options=[ ("grpc.max_send_message_length", -1), @@ -222,18 +216,8 @@ def __init__( ], ) - # Run the base constructor. - super().__init__( - host=host, - credentials=credentials, - credentials_file=credentials_file, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - client_info=client_info, - ) - - self._stubs = {} - self._operations_client = None + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) @property def grpc_channel(self) -> aio.Channel: diff --git a/google/cloud/asset_v1/types/__init__.py b/google/cloud/asset_v1/types/__init__.py index 1dfca4b9..1143f78b 100644 --- a/google/cloud/asset_v1/types/__init__.py +++ b/google/cloud/asset_v1/types/__init__.py @@ -15,86 +15,86 @@ # limitations under the License. # -from .assets import ( - TemporalAsset, - TimeWindow, - Asset, - Resource, - ResourceSearchResult, - IamPolicySearchResult, - IamPolicyAnalysisState, - IamPolicyAnalysisResult, -) from .asset_service import ( - ExportAssetsRequest, - ExportAssetsResponse, + AnalyzeIamPolicyLongrunningRequest, + AnalyzeIamPolicyLongrunningResponse, + AnalyzeIamPolicyRequest, + AnalyzeIamPolicyResponse, BatchGetAssetsHistoryRequest, BatchGetAssetsHistoryResponse, + BigQueryDestination, CreateFeedRequest, + DeleteFeedRequest, + ExportAssetsRequest, + ExportAssetsResponse, + Feed, + FeedOutputConfig, + GcsDestination, + GcsOutputResult, GetFeedRequest, + IamPolicyAnalysisOutputConfig, + IamPolicyAnalysisQuery, ListFeedsRequest, ListFeedsResponse, - UpdateFeedRequest, - DeleteFeedRequest, OutputConfig, OutputResult, - GcsOutputResult, - GcsDestination, - BigQueryDestination, PartitionSpec, PubsubDestination, - FeedOutputConfig, - Feed, - SearchAllResourcesRequest, - SearchAllResourcesResponse, SearchAllIamPoliciesRequest, SearchAllIamPoliciesResponse, - IamPolicyAnalysisQuery, - AnalyzeIamPolicyRequest, - AnalyzeIamPolicyResponse, - IamPolicyAnalysisOutputConfig, - AnalyzeIamPolicyLongrunningRequest, - AnalyzeIamPolicyLongrunningResponse, + SearchAllResourcesRequest, + SearchAllResourcesResponse, + UpdateFeedRequest, ContentType, ) +from .assets import ( + Asset, + IamPolicyAnalysisResult, + IamPolicyAnalysisState, + IamPolicySearchResult, + Resource, + ResourceSearchResult, + TemporalAsset, + TimeWindow, +) __all__ = ( - "TemporalAsset", - "TimeWindow", - "Asset", - "Resource", - "ResourceSearchResult", - "IamPolicySearchResult", - "IamPolicyAnalysisState", - "IamPolicyAnalysisResult", - "ExportAssetsRequest", - "ExportAssetsResponse", + "AnalyzeIamPolicyLongrunningRequest", + "AnalyzeIamPolicyLongrunningResponse", + "AnalyzeIamPolicyRequest", + "AnalyzeIamPolicyResponse", "BatchGetAssetsHistoryRequest", "BatchGetAssetsHistoryResponse", + "BigQueryDestination", "CreateFeedRequest", + "DeleteFeedRequest", + "ExportAssetsRequest", + "ExportAssetsResponse", + "Feed", + "FeedOutputConfig", + "GcsDestination", + "GcsOutputResult", "GetFeedRequest", + "IamPolicyAnalysisOutputConfig", + "IamPolicyAnalysisQuery", "ListFeedsRequest", "ListFeedsResponse", - "UpdateFeedRequest", - "DeleteFeedRequest", "OutputConfig", "OutputResult", - "GcsOutputResult", - "GcsDestination", - "BigQueryDestination", "PartitionSpec", "PubsubDestination", - "FeedOutputConfig", - "Feed", - "SearchAllResourcesRequest", - "SearchAllResourcesResponse", "SearchAllIamPoliciesRequest", "SearchAllIamPoliciesResponse", - "IamPolicyAnalysisQuery", - "AnalyzeIamPolicyRequest", - "AnalyzeIamPolicyResponse", - "IamPolicyAnalysisOutputConfig", - "AnalyzeIamPolicyLongrunningRequest", - "AnalyzeIamPolicyLongrunningResponse", + "SearchAllResourcesRequest", + "SearchAllResourcesResponse", + "UpdateFeedRequest", "ContentType", + "Asset", + "IamPolicyAnalysisResult", + "IamPolicyAnalysisState", + "IamPolicySearchResult", + "Resource", + "ResourceSearchResult", + "TemporalAsset", + "TimeWindow", ) diff --git a/google/cloud/asset_v1/types/asset_service.py b/google/cloud/asset_v1/types/asset_service.py index c1606428..02fca9fe 100644 --- a/google/cloud/asset_v1/types/asset_service.py +++ b/google/cloud/asset_v1/types/asset_service.py @@ -83,7 +83,7 @@ class ExportAssetsRequest(proto.Message): (such as "projects/my-project-id"), or a project number (such as "projects/12345"), or a folder number (such as "folders/123"). - read_time (~.timestamp.Timestamp): + read_time (google.protobuf.timestamp_pb2.Timestamp): Timestamp to take an asset snapshot. This can only be set to a timestamp between the current time and the current time minus 35 days @@ -115,10 +115,10 @@ class ExportAssetsRequest(proto.Message): `Introduction to Cloud Asset Inventory `__ for all supported asset types. - content_type (~.asset_service.ContentType): + content_type (google.cloud.asset_v1.types.ContentType): Asset content type. If not specified, no content but the asset name will be returned. - output_config (~.asset_service.OutputConfig): + output_config (google.cloud.asset_v1.types.OutputConfig): Required. Output configuration indicating where the results will be output to. """ @@ -142,12 +142,12 @@ class ExportAssetsResponse(proto.Message): field. Attributes: - read_time (~.timestamp.Timestamp): + read_time (google.protobuf.timestamp_pb2.Timestamp): Time the snapshot was taken. - output_config (~.asset_service.OutputConfig): + output_config (google.cloud.asset_v1.types.OutputConfig): Output configuration indicating where the results were output to. - output_result (~.asset_service.OutputResult): + output_result (google.cloud.asset_v1.types.OutputResult): Output result indicating where the assets were exported to. For example, a set of actual Google Cloud Storage object uris where the assets are exported to. The uris can be @@ -183,9 +183,9 @@ class BatchGetAssetsHistoryRequest(proto.Message): The request becomes a no-op if the asset name list is empty, and the max size of the asset name list is 100 in one request. - content_type (~.asset_service.ContentType): + content_type (google.cloud.asset_v1.types.ContentType): Optional. The content type. - read_time_window (~.gca_assets.TimeWindow): + read_time_window (google.cloud.asset_v1.types.TimeWindow): Optional. The time window for the asset history. Both start_time and end_time are optional and if set, it must be after the current time minus 35 days. If end_time is not @@ -210,7 +210,7 @@ class BatchGetAssetsHistoryResponse(proto.Message): r"""Batch get assets history response. Attributes: - assets (Sequence[~.gca_assets.TemporalAsset]): + assets (Sequence[google.cloud.asset_v1.types.TemporalAsset]): A list of assets with valid time windows. """ @@ -236,7 +236,7 @@ class CreateFeedRequest(proto.Message): Required. This is the client-assigned asset feed identifier and it needs to be unique under a specific parent project/folder/organization. - feed (~.asset_service.Feed): + feed (google.cloud.asset_v1.types.Feed): Required. The feed details. The field ``name`` must be empty and it will be generated in the format of: projects/project_number/feeds/feed_id @@ -285,7 +285,7 @@ class ListFeedsResponse(proto.Message): r""" Attributes: - feeds (Sequence[~.asset_service.Feed]): + feeds (Sequence[google.cloud.asset_v1.types.Feed]): A list of feeds. """ @@ -296,13 +296,13 @@ class UpdateFeedRequest(proto.Message): r"""Update asset feed request. Attributes: - feed (~.asset_service.Feed): + feed (google.cloud.asset_v1.types.Feed): Required. The new values of feed details. It must match an existing feed and the field ``name`` must be in the format of: projects/project_number/feeds/feed_id or folders/folder_number/feeds/feed_id or organizations/organization_number/feeds/feed_id. - update_mask (~.field_mask.FieldMask): + update_mask (google.protobuf.field_mask_pb2.FieldMask): Required. Only updates the ``feed`` fields indicated by this mask. The field mask must not be empty, and it must not contain fields that are immutable or only set by the server. @@ -331,9 +331,9 @@ class OutputConfig(proto.Message): r"""Output configuration for export assets destination. Attributes: - gcs_destination (~.asset_service.GcsDestination): + gcs_destination (google.cloud.asset_v1.types.GcsDestination): Destination on Cloud Storage. - bigquery_destination (~.asset_service.BigQueryDestination): + bigquery_destination (google.cloud.asset_v1.types.BigQueryDestination): Destination on BigQuery. The output table stores the fields in asset proto as columns in BigQuery. @@ -352,7 +352,7 @@ class OutputResult(proto.Message): r"""Output result of export assets. Attributes: - gcs_result (~.asset_service.GcsOutputResult): + gcs_result (google.cloud.asset_v1.types.GcsOutputResult): Export result on Cloud Storage. """ @@ -420,7 +420,7 @@ class BigQueryDestination(proto.Message): assets snapshot. If the flag is ``FALSE`` or unset and the destination table already exists, the export call returns an INVALID_ARGUMEMT error. - partition_spec (~.asset_service.PartitionSpec): + partition_spec (google.cloud.asset_v1.types.PartitionSpec): [partition_spec] determines whether to export to partitioned table(s) and how to partition the data. @@ -494,7 +494,7 @@ class PartitionSpec(proto.Message): destination. Attributes: - partition_key (~.asset_service.PartitionSpec.PartitionKey): + partition_key (google.cloud.asset_v1.types.PartitionSpec.PartitionKey): The partition key for BigQuery partitioned table. """ @@ -529,7 +529,7 @@ class FeedOutputConfig(proto.Message): r"""Output configuration for asset feed destination. Attributes: - pubsub_destination (~.asset_service.PubsubDestination): + pubsub_destination (google.cloud.asset_v1.types.PubsubDestination): Destination on Pub/Sub. """ @@ -576,14 +576,14 @@ class Feed(proto.Message): See `this topic `__ for a list of all supported asset types. - content_type (~.asset_service.ContentType): + content_type (google.cloud.asset_v1.types.ContentType): Asset content type. If not specified, no content but the asset name and type will be returned. - feed_output_config (~.asset_service.FeedOutputConfig): + feed_output_config (google.cloud.asset_v1.types.FeedOutputConfig): Required. Feed output configuration defining where the asset updates are published to. - condition (~.expr.Expr): + condition (google.type.expr_pb2.Expr): A condition which determines whether an asset update should be published. If specified, an asset will be returned only when the expression evaluates to true. When set, @@ -717,7 +717,7 @@ class SearchAllResourcesResponse(proto.Message): r"""Search all resources response. Attributes: - results (Sequence[~.gca_assets.ResourceSearchResult]): + results (Sequence[google.cloud.asset_v1.types.ResourceSearchResult]): A list of Resources that match the search query. It contains the resource standard metadata information. @@ -814,7 +814,7 @@ class SearchAllIamPoliciesResponse(proto.Message): r"""Search all IAM policies response. Attributes: - results (Sequence[~.gca_assets.IamPolicySearchResult]): + results (Sequence[google.cloud.asset_v1.types.IamPolicySearchResult]): A list of IamPolicy that match the search query. Related information such as the associated resource is returned along with the @@ -856,14 +856,14 @@ class IamPolicyAnalysisQuery(proto.Message): To know how to get folder or project id, visit `here `__. - resource_selector (~.asset_service.IamPolicyAnalysisQuery.ResourceSelector): + resource_selector (google.cloud.asset_v1.types.IamPolicyAnalysisQuery.ResourceSelector): Optional. Specifies a resource for analysis. - identity_selector (~.asset_service.IamPolicyAnalysisQuery.IdentitySelector): + identity_selector (google.cloud.asset_v1.types.IamPolicyAnalysisQuery.IdentitySelector): Optional. Specifies an identity for analysis. - access_selector (~.asset_service.IamPolicyAnalysisQuery.AccessSelector): + access_selector (google.cloud.asset_v1.types.IamPolicyAnalysisQuery.AccessSelector): Optional. Specifies roles or permissions for analysis. This is optional. - options (~.asset_service.IamPolicyAnalysisQuery.Options): + options (google.cloud.asset_v1.types.IamPolicyAnalysisQuery.Options): Optional. The query options. """ @@ -1043,9 +1043,9 @@ class AnalyzeIamPolicyRequest(proto.Message): [AssetService.AnalyzeIamPolicy][google.cloud.asset.v1.AssetService.AnalyzeIamPolicy]. Attributes: - analysis_query (~.asset_service.IamPolicyAnalysisQuery): + analysis_query (google.cloud.asset_v1.types.IamPolicyAnalysisQuery): Required. The request query. - execution_timeout (~.duration.Duration): + execution_timeout (google.protobuf.duration_pb2.Duration): Optional. Amount of time executable has to complete. See JSON representation of `Duration `__. @@ -1072,10 +1072,10 @@ class AnalyzeIamPolicyResponse(proto.Message): [AssetService.AnalyzeIamPolicy][google.cloud.asset.v1.AssetService.AnalyzeIamPolicy]. Attributes: - main_analysis (~.asset_service.AnalyzeIamPolicyResponse.IamPolicyAnalysis): + main_analysis (google.cloud.asset_v1.types.AnalyzeIamPolicyResponse.IamPolicyAnalysis): The main analysis that matches the original request. - service_account_impersonation_analysis (Sequence[~.asset_service.AnalyzeIamPolicyResponse.IamPolicyAnalysis]): + service_account_impersonation_analysis (Sequence[google.cloud.asset_v1.types.AnalyzeIamPolicyResponse.IamPolicyAnalysis]): The service account impersonation analysis if [AnalyzeIamPolicyRequest.analyze_service_account_impersonation][] is enabled. @@ -1091,9 +1091,9 @@ class IamPolicyAnalysis(proto.Message): r"""An analysis message to group the query and results. Attributes: - analysis_query (~.asset_service.IamPolicyAnalysisQuery): + analysis_query (google.cloud.asset_v1.types.IamPolicyAnalysisQuery): The analysis query. - analysis_results (Sequence[~.gca_assets.IamPolicyAnalysisResult]): + analysis_results (Sequence[google.cloud.asset_v1.types.IamPolicyAnalysisResult]): A list of [IamPolicyAnalysisResult][google.cloud.asset.v1.IamPolicyAnalysisResult] that matches the analysis query, or empty if no result is @@ -1102,7 +1102,7 @@ class IamPolicyAnalysis(proto.Message): Represents whether all entries in the [analysis_results][google.cloud.asset.v1.AnalyzeIamPolicyResponse.IamPolicyAnalysis.analysis_results] have been fully explored to answer the query. - non_critical_errors (Sequence[~.gca_assets.IamPolicyAnalysisState]): + non_critical_errors (Sequence[google.cloud.asset_v1.types.IamPolicyAnalysisState]): A list of non-critical errors happened during the query handling. """ @@ -1135,9 +1135,9 @@ class IamPolicyAnalysisOutputConfig(proto.Message): destination. Attributes: - gcs_destination (~.asset_service.IamPolicyAnalysisOutputConfig.GcsDestination): + gcs_destination (google.cloud.asset_v1.types.IamPolicyAnalysisOutputConfig.GcsDestination): Destination on Cloud Storage. - bigquery_destination (~.asset_service.IamPolicyAnalysisOutputConfig.BigQueryDestination): + bigquery_destination (google.cloud.asset_v1.types.IamPolicyAnalysisOutputConfig.BigQueryDestination): Destination on BigQuery. """ @@ -1177,7 +1177,7 @@ class BigQueryDestination(proto.Message): [IamPolicyAnalysisResult][google.cloud.asset.v1.IamPolicyAnalysisResult]. When [partition_key] is specified, both tables will be partitioned based on the [partition_key]. - partition_key (~.asset_service.IamPolicyAnalysisOutputConfig.BigQueryDestination.PartitionKey): + partition_key (google.cloud.asset_v1.types.IamPolicyAnalysisOutputConfig.BigQueryDestination.PartitionKey): The partition key for BigQuery partitioned table. write_disposition (str): @@ -1236,9 +1236,9 @@ class AnalyzeIamPolicyLongrunningRequest(proto.Message): [AssetService.AnalyzeIamPolicyLongrunning][google.cloud.asset.v1.AssetService.AnalyzeIamPolicyLongrunning]. Attributes: - analysis_query (~.asset_service.IamPolicyAnalysisQuery): + analysis_query (google.cloud.asset_v1.types.IamPolicyAnalysisQuery): Required. The request query. - output_config (~.asset_service.IamPolicyAnalysisOutputConfig): + output_config (google.cloud.asset_v1.types.IamPolicyAnalysisOutputConfig): Required. Output configuration indicating where the results will be output to. """ diff --git a/google/cloud/asset_v1/types/assets.py b/google/cloud/asset_v1/types/assets.py index fbbac89c..43eb2482 100644 --- a/google/cloud/asset_v1/types/assets.py +++ b/google/cloud/asset_v1/types/assets.py @@ -50,16 +50,16 @@ class TemporalAsset(proto.Message): window. Attributes: - window (~.assets.TimeWindow): + window (google.cloud.asset_v1.types.TimeWindow): The time window when the asset data and state was observed. deleted (bool): Whether the asset has been deleted or not. - asset (~.assets.Asset): + asset (google.cloud.asset_v1.types.Asset): An asset in Google Cloud. - prior_asset_state (~.assets.TemporalAsset.PriorAssetState): + prior_asset_state (google.cloud.asset_v1.types.TemporalAsset.PriorAssetState): State of prior_asset. - prior_asset (~.assets.Asset): + prior_asset (google.cloud.asset_v1.types.Asset): Prior copy of the asset. Populated if prior_asset_state is PRESENT. Currently this is only set for responses in Real-Time Feed. @@ -88,9 +88,9 @@ class TimeWindow(proto.Message): r"""A time window specified by its ``start_time`` and ``end_time``. Attributes: - start_time (~.timestamp.Timestamp): + start_time (google.protobuf.timestamp_pb2.Timestamp): Start time of the time window (exclusive). - end_time (~.timestamp.Timestamp): + end_time (google.protobuf.timestamp_pb2.Timestamp): End time of the time window (inclusive). If not specified, the current timestamp is used instead. @@ -112,7 +112,7 @@ class Asset(proto.Message): for more information. Attributes: - update_time (~.timestamp.Timestamp): + update_time (google.protobuf.timestamp_pb2.Timestamp): The last update timestamp of an asset. update_time is updated when create/update/delete operation is performed. name (str): @@ -129,9 +129,9 @@ class Asset(proto.Message): See `Supported asset types `__ for more information. - resource (~.assets.Resource): + resource (google.cloud.asset_v1.types.Resource): A representation of the resource. - iam_policy (~.gi_policy.Policy): + iam_policy (google.iam.v1.policy_pb2.Policy): A representation of the Cloud IAM policy set on a Google Cloud resource. There can be a maximum of one Cloud IAM policy set on any given resource. In addition, Cloud IAM @@ -143,21 +143,21 @@ class Asset(proto.Message): See `this topic `__ for more information. - org_policy (Sequence[~.orgpolicy.Policy]): + org_policy (Sequence[google.cloud.orgpolicy.v1.orgpolicy_pb2.Policy]): A representation of an `organization policy `__. There can be more than one organization policy with different constraints set on a given resource. - access_policy (~.gia_access_policy.AccessPolicy): + access_policy (google.identity.accesscontextmanager.v1.access_policy_pb2.AccessPolicy): Please also refer to the `access policy user guide `__. - access_level (~.gia_access_level.AccessLevel): + access_level (google.identity.accesscontextmanager.v1.access_level_pb2.AccessLevel): Please also refer to the `access level user guide `__. - service_perimeter (~.gia_service_perimeter.ServicePerimeter): + service_perimeter (google.identity.accesscontextmanager.v1.service_perimeter_pb2.ServicePerimeter): Please also refer to the `service perimeter user guide `__. - os_inventory (~.inventory.Inventory): + os_inventory (google.cloud.osconfig.v1.inventory_pb2.Inventory): A representation of runtime OS Inventory information. See `this topic `__ @@ -251,7 +251,7 @@ class Resource(proto.Message): ``//cloudresourcemanager.googleapis.com/projects/my_project_123`` For third-party assets, this field may be set differently. - data (~.struct.Struct): + data (google.protobuf.struct_pb2.Struct): The content of the resource, in which some sensitive fields are removed and may not be present. @@ -333,7 +333,7 @@ class ResourceSearchResult(proto.Message): - use a field query. Example: ``location:us-west*`` - use a free text query. Example: ``us-west*`` - labels (Sequence[~.assets.ResourceSearchResult.LabelsEntry]): + labels (Sequence[google.cloud.asset_v1.types.ResourceSearchResult.LabelsEntry]): Labels associated with this resource. See `Labelling and grouping GCP resources `__ @@ -361,7 +361,7 @@ class ResourceSearchResult(proto.Message): - use a field query. Example: ``networkTags:internal`` - use a free text query. Example: ``internal`` - additional_attributes (~.struct.Struct): + additional_attributes (google.protobuf.struct_pb2.Struct): The additional searchable attributes of this resource. The attributes may vary from one resource type to another. Examples: ``projectId`` for Project, ``dnsName`` for DNS @@ -433,7 +433,7 @@ class IamPolicySearchResult(proto.Message): - specify the ``scope`` field as this project in your search request. - policy (~.gi_policy.Policy): + policy (google.iam.v1.policy_pb2.Policy): The IAM policy directly set on the given resource. Note that the original IAM policy can contain multiple bindings. This only contains the bindings that match the given query. For @@ -451,7 +451,7 @@ class IamPolicySearchResult(proto.Message): - query by the policy contained roles' included permissions. Example: ``policy.role.permissions:compute.instances.create`` - explanation (~.assets.IamPolicySearchResult.Explanation): + explanation (google.cloud.asset_v1.types.IamPolicySearchResult.Explanation): Explanation about the IAM policy search result. It contains additional information to explain why the search result matches the query. @@ -461,7 +461,7 @@ class Explanation(proto.Message): r"""Explanation about the IAM policy search result. Attributes: - matched_permissions (Sequence[~.assets.IamPolicySearchResult.Explanation.MatchedPermissionsEntry]): + matched_permissions (Sequence[google.cloud.asset_v1.types.IamPolicySearchResult.Explanation.MatchedPermissionsEntry]): The map from roles to their included permissions that match the permission query (i.e., a query containing ``policy.role.permissions:``). Example: if query @@ -506,7 +506,7 @@ class IamPolicyAnalysisState(proto.Message): such as a resource, an identity or an access. Attributes: - code (~.gr_code.Code): + code (google.rpc.code_pb2.Code): The Google standard error code that best describes the state. For example: @@ -537,14 +537,14 @@ class IamPolicyAnalysisResult(proto.Message): of the resource to which the [iam_binding][google.cloud.asset.v1.IamPolicyAnalysisResult.iam_binding] policy attaches. - iam_binding (~.gi_policy.Binding): + iam_binding (google.iam.v1.policy_pb2.Binding): The Cloud IAM policy binding under analysis. - access_control_lists (Sequence[~.assets.IamPolicyAnalysisResult.AccessControlList]): + access_control_lists (Sequence[google.cloud.asset_v1.types.IamPolicyAnalysisResult.AccessControlList]): The access control lists derived from the [iam_binding][google.cloud.asset.v1.IamPolicyAnalysisResult.iam_binding] that match or potentially match resource and access selectors specified in the request. - identity_list (~.assets.IamPolicyAnalysisResult.IdentityList): + identity_list (google.cloud.asset_v1.types.IamPolicyAnalysisResult.IdentityList): The identity list derived from members of the [iam_binding][google.cloud.asset.v1.IamPolicyAnalysisResult.iam_binding] that match or potentially match identity selector specified @@ -562,7 +562,7 @@ class Resource(proto.Message): full_resource_name (str): The `full resource name `__ - analysis_state (~.assets.IamPolicyAnalysisState): + analysis_state (google.cloud.asset_v1.types.IamPolicyAnalysisState): The analysis state of this resource. """ @@ -580,7 +580,7 @@ class Access(proto.Message): The role. permission (str): The permission. - analysis_state (~.assets.IamPolicyAnalysisState): + analysis_state (google.cloud.asset_v1.types.IamPolicyAnalysisState): The analysis state of this access. """ @@ -609,7 +609,7 @@ class Identity(proto.Message): - domain:google.com - allUsers - etc. - analysis_state (~.assets.IamPolicyAnalysisState): + analysis_state (google.cloud.asset_v1.types.IamPolicyAnalysisState): The analysis state of this identity. """ @@ -658,19 +658,19 @@ class AccessControlList(proto.Message): - AccessControlList 2: [R2, R3], [P3] Attributes: - resources (Sequence[~.assets.IamPolicyAnalysisResult.Resource]): + resources (Sequence[google.cloud.asset_v1.types.IamPolicyAnalysisResult.Resource]): The resources that match one of the following conditions: - The resource_selector, if it is specified in request; - Otherwise, resources reachable from the policy attached resource. - accesses (Sequence[~.assets.IamPolicyAnalysisResult.Access]): + accesses (Sequence[google.cloud.asset_v1.types.IamPolicyAnalysisResult.Access]): The accesses that match one of the following conditions: - The access_selector, if it is specified in request; - Otherwise, access specifiers reachable from the policy binding's role. - resource_edges (Sequence[~.assets.IamPolicyAnalysisResult.Edge]): + resource_edges (Sequence[google.cloud.asset_v1.types.IamPolicyAnalysisResult.Edge]): Resource edges of the graph starting from the policy attached resource to any descendant resources. The [Edge.source_node][google.cloud.asset.v1.IamPolicyAnalysisResult.Edge.source_node] @@ -697,14 +697,14 @@ class IdentityList(proto.Message): r"""The identities and group edges. Attributes: - identities (Sequence[~.assets.IamPolicyAnalysisResult.Identity]): + identities (Sequence[google.cloud.asset_v1.types.IamPolicyAnalysisResult.Identity]): Only the identities that match one of the following conditions will be presented: - The identity_selector, if it is specified in request; - Otherwise, identities reachable from the policy binding's members. - group_edges (Sequence[~.assets.IamPolicyAnalysisResult.Edge]): + group_edges (Sequence[google.cloud.asset_v1.types.IamPolicyAnalysisResult.Edge]): Group identity edges of the graph starting from the binding's group members to any node of the [identities][google.cloud.asset.v1.IamPolicyAnalysisResult.IdentityList.identities]. diff --git a/google/cloud/asset_v1p1beta1/services/asset_service/async_client.py b/google/cloud/asset_v1p1beta1/services/asset_service/async_client.py index 5656381e..056f1410 100644 --- a/google/cloud/asset_v1p1beta1/services/asset_service/async_client.py +++ b/google/cloud/asset_v1p1beta1/services/asset_service/async_client.py @@ -70,7 +70,36 @@ class AssetServiceAsyncClient: AssetServiceClient.parse_common_location_path ) - from_service_account_file = AssetServiceClient.from_service_account_file + @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: + AssetServiceAsyncClient: The constructed client. + """ + return AssetServiceClient.from_service_account_info.__func__(AssetServiceAsyncClient, 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: + AssetServiceAsyncClient: The constructed client. + """ + return AssetServiceClient.from_service_account_file.__func__(AssetServiceAsyncClient, filename, *args, **kwargs) # type: ignore + from_service_account_json = from_service_account_file @property @@ -154,7 +183,7 @@ async def search_all_resources( requested scope, otherwise it will be rejected. Args: - request (:class:`~.asset_service.SearchAllResourcesRequest`): + request (:class:`google.cloud.asset_v1p1beta1.types.SearchAllResourcesRequest`): The request object. Search all resources request. scope (:class:`str`): Required. The relative name of an asset. The search is @@ -165,6 +194,7 @@ async def search_all_resources( - Folder number(such as "folders/1234") - Project number (such as "projects/12345") - Project id (such as "projects/abc") + This corresponds to the ``scope`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -178,6 +208,7 @@ async def search_all_resources( this request searches for. If empty, it will search all the supported asset types. + This corresponds to the ``asset_types`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -189,7 +220,7 @@ async def search_all_resources( sent along with the request as metadata. Returns: - ~.pagers.SearchAllResourcesAsyncPager: + google.cloud.asset_v1p1beta1.services.asset_service.pagers.SearchAllResourcesAsyncPager: Search all resources response. Iterating over this object will yield results and resolve additional pages @@ -230,6 +261,7 @@ async def search_all_resources( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=15.0, ), default_timeout=15.0, client_info=DEFAULT_CLIENT_INFO, @@ -273,7 +305,7 @@ async def search_all_iam_policies( requested scope, otherwise it will be rejected. Args: - request (:class:`~.asset_service.SearchAllIamPoliciesRequest`): + request (:class:`google.cloud.asset_v1p1beta1.types.SearchAllIamPoliciesRequest`): The request object. Search all IAM policies request. scope (:class:`str`): Required. The relative name of an asset. The search is @@ -284,6 +316,7 @@ async def search_all_iam_policies( - Folder number(such as "folders/1234") - Project number (such as "projects/12345") - Project id (such as "projects/abc") + This corresponds to the ``scope`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -291,7 +324,8 @@ async def search_all_iam_policies( Optional. The query statement. Examples: - "policy:myuser@mydomain.com" - - "policy:(myuser@mydomain.com viewer)". + - "policy:(myuser@mydomain.com viewer)" + This corresponds to the ``query`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -303,7 +337,7 @@ async def search_all_iam_policies( sent along with the request as metadata. Returns: - ~.pagers.SearchAllIamPoliciesAsyncPager: + google.cloud.asset_v1p1beta1.services.asset_service.pagers.SearchAllIamPoliciesAsyncPager: Search all IAM policies response. Iterating over this object will yield results and resolve additional pages @@ -341,6 +375,7 @@ async def search_all_iam_policies( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=15.0, ), default_timeout=15.0, client_info=DEFAULT_CLIENT_INFO, diff --git a/google/cloud/asset_v1p1beta1/services/asset_service/client.py b/google/cloud/asset_v1p1beta1/services/asset_service/client.py index 416ec43a..e2a25499 100644 --- a/google/cloud/asset_v1p1beta1/services/asset_service/client.py +++ b/google/cloud/asset_v1p1beta1/services/asset_service/client.py @@ -109,6 +109,22 @@ def _get_default_mtls_endpoint(api_endpoint): 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: + AssetServiceClient: 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 @@ -121,7 +137,7 @@ def from_service_account_file(cls, filename: str, *args, **kwargs): kwargs: Additional arguments to pass to the constructor. Returns: - {@api.name}: The constructed client. + AssetServiceClient: The constructed client. """ credentials = service_account.Credentials.from_service_account_file(filename) kwargs["credentials"] = credentials @@ -213,10 +229,10 @@ def __init__( 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, ~.AssetServiceTransport]): The + transport (Union[str, AssetServiceTransport]): The transport to use. If set to None, a transport is chosen automatically. - client_options (client_options_lib.ClientOptions): Custom options for the + 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 @@ -252,21 +268,17 @@ def __init__( util.strtobool(os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false")) ) - ssl_credentials = None + client_cert_source_func = None is_mtls = False if use_client_cert: if client_options.client_cert_source: - import grpc # type: ignore - - cert, key = client_options.client_cert_source() - ssl_credentials = grpc.ssl_channel_credentials( - certificate_chain=cert, private_key=key - ) is_mtls = True + client_cert_source_func = client_options.client_cert_source else: - creds = SslCredentials() - is_mtls = creds.is_mtls - ssl_credentials = creds.ssl_credentials if is_mtls else None + is_mtls = mtls.has_default_client_cert_source() + client_cert_source_func = ( + mtls.default_client_cert_source() if is_mtls else None + ) # Figure out which api endpoint to use. if client_options.api_endpoint is not None: @@ -309,7 +321,7 @@ def __init__( credentials_file=client_options.credentials_file, host=api_endpoint, scopes=client_options.scopes, - ssl_channel_credentials=ssl_credentials, + client_cert_source_for_mtls=client_cert_source_func, quota_project_id=client_options.quota_project_id, client_info=client_info, ) @@ -334,9 +346,9 @@ def search_all_resources( requested scope, otherwise it will be rejected. Args: - request (:class:`~.asset_service.SearchAllResourcesRequest`): + request (google.cloud.asset_v1p1beta1.types.SearchAllResourcesRequest): The request object. Search all resources request. - scope (:class:`str`): + scope (str): Required. The relative name of an asset. The search is limited to the resources within the ``scope``. The allowed value must be: @@ -345,19 +357,21 @@ def search_all_resources( - Folder number(such as "folders/1234") - Project number (such as "projects/12345") - Project id (such as "projects/abc") + This corresponds to the ``scope`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - query (:class:`str`): + query (str): Optional. The query statement. This corresponds to the ``query`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - asset_types (:class:`Sequence[str]`): + asset_types (Sequence[str]): Optional. A list of asset types that this request searches for. If empty, it will search all the supported asset types. + This corresponds to the ``asset_types`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -369,7 +383,7 @@ def search_all_resources( sent along with the request as metadata. Returns: - ~.pagers.SearchAllResourcesPager: + google.cloud.asset_v1p1beta1.services.asset_service.pagers.SearchAllResourcesPager: Search all resources response. Iterating over this object will yield results and resolve additional pages @@ -400,9 +414,8 @@ def search_all_resources( request.scope = scope if query is not None: request.query = query - - if asset_types: - request.asset_types.extend(asset_types) + if asset_types is not None: + request.asset_types = asset_types # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. @@ -446,9 +459,9 @@ def search_all_iam_policies( requested scope, otherwise it will be rejected. Args: - request (:class:`~.asset_service.SearchAllIamPoliciesRequest`): + request (google.cloud.asset_v1p1beta1.types.SearchAllIamPoliciesRequest): The request object. Search all IAM policies request. - scope (:class:`str`): + scope (str): Required. The relative name of an asset. The search is limited to the resources within the ``scope``. The allowed value must be: @@ -457,14 +470,16 @@ def search_all_iam_policies( - Folder number(such as "folders/1234") - Project number (such as "projects/12345") - Project id (such as "projects/abc") + This corresponds to the ``scope`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - query (:class:`str`): + query (str): Optional. The query statement. Examples: - "policy:myuser@mydomain.com" - - "policy:(myuser@mydomain.com viewer)". + - "policy:(myuser@mydomain.com viewer)" + This corresponds to the ``query`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -476,7 +491,7 @@ def search_all_iam_policies( sent along with the request as metadata. Returns: - ~.pagers.SearchAllIamPoliciesPager: + google.cloud.asset_v1p1beta1.services.asset_service.pagers.SearchAllIamPoliciesPager: Search all IAM policies response. Iterating over this object will yield results and resolve additional pages diff --git a/google/cloud/asset_v1p1beta1/services/asset_service/pagers.py b/google/cloud/asset_v1p1beta1/services/asset_service/pagers.py index d41893a2..234b82b0 100644 --- a/google/cloud/asset_v1p1beta1/services/asset_service/pagers.py +++ b/google/cloud/asset_v1p1beta1/services/asset_service/pagers.py @@ -15,7 +15,16 @@ # limitations under the License. # -from typing import Any, AsyncIterable, Awaitable, Callable, Iterable, Sequence, Tuple +from typing import ( + Any, + AsyncIterable, + Awaitable, + Callable, + Iterable, + Sequence, + Tuple, + Optional, +) from google.cloud.asset_v1p1beta1.types import asset_service from google.cloud.asset_v1p1beta1.types import assets @@ -25,7 +34,7 @@ class SearchAllResourcesPager: """A pager for iterating through ``search_all_resources`` requests. This class thinly wraps an initial - :class:`~.asset_service.SearchAllResourcesResponse` object, and + :class:`google.cloud.asset_v1p1beta1.types.SearchAllResourcesResponse` object, and provides an ``__iter__`` method to iterate through its ``results`` field. @@ -34,7 +43,7 @@ class SearchAllResourcesPager: through the ``results`` field on the corresponding responses. - All the usual :class:`~.asset_service.SearchAllResourcesResponse` + All the usual :class:`google.cloud.asset_v1p1beta1.types.SearchAllResourcesResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -52,9 +61,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.asset_service.SearchAllResourcesRequest`): + request (google.cloud.asset_v1p1beta1.types.SearchAllResourcesRequest): The initial request object. - response (:class:`~.asset_service.SearchAllResourcesResponse`): + response (google.cloud.asset_v1p1beta1.types.SearchAllResourcesResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -87,7 +96,7 @@ class SearchAllResourcesAsyncPager: """A pager for iterating through ``search_all_resources`` requests. This class thinly wraps an initial - :class:`~.asset_service.SearchAllResourcesResponse` object, and + :class:`google.cloud.asset_v1p1beta1.types.SearchAllResourcesResponse` object, and provides an ``__aiter__`` method to iterate through its ``results`` field. @@ -96,7 +105,7 @@ class SearchAllResourcesAsyncPager: through the ``results`` field on the corresponding responses. - All the usual :class:`~.asset_service.SearchAllResourcesResponse` + All the usual :class:`google.cloud.asset_v1p1beta1.types.SearchAllResourcesResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -114,9 +123,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.asset_service.SearchAllResourcesRequest`): + request (google.cloud.asset_v1p1beta1.types.SearchAllResourcesRequest): The initial request object. - response (:class:`~.asset_service.SearchAllResourcesResponse`): + response (google.cloud.asset_v1p1beta1.types.SearchAllResourcesResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -153,7 +162,7 @@ class SearchAllIamPoliciesPager: """A pager for iterating through ``search_all_iam_policies`` requests. This class thinly wraps an initial - :class:`~.asset_service.SearchAllIamPoliciesResponse` object, and + :class:`google.cloud.asset_v1p1beta1.types.SearchAllIamPoliciesResponse` object, and provides an ``__iter__`` method to iterate through its ``results`` field. @@ -162,7 +171,7 @@ class SearchAllIamPoliciesPager: through the ``results`` field on the corresponding responses. - All the usual :class:`~.asset_service.SearchAllIamPoliciesResponse` + All the usual :class:`google.cloud.asset_v1p1beta1.types.SearchAllIamPoliciesResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -180,9 +189,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.asset_service.SearchAllIamPoliciesRequest`): + request (google.cloud.asset_v1p1beta1.types.SearchAllIamPoliciesRequest): The initial request object. - response (:class:`~.asset_service.SearchAllIamPoliciesResponse`): + response (google.cloud.asset_v1p1beta1.types.SearchAllIamPoliciesResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -215,7 +224,7 @@ class SearchAllIamPoliciesAsyncPager: """A pager for iterating through ``search_all_iam_policies`` requests. This class thinly wraps an initial - :class:`~.asset_service.SearchAllIamPoliciesResponse` object, and + :class:`google.cloud.asset_v1p1beta1.types.SearchAllIamPoliciesResponse` object, and provides an ``__aiter__`` method to iterate through its ``results`` field. @@ -224,7 +233,7 @@ class SearchAllIamPoliciesAsyncPager: through the ``results`` field on the corresponding responses. - All the usual :class:`~.asset_service.SearchAllIamPoliciesResponse` + All the usual :class:`google.cloud.asset_v1p1beta1.types.SearchAllIamPoliciesResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -242,9 +251,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.asset_service.SearchAllIamPoliciesRequest`): + request (google.cloud.asset_v1p1beta1.types.SearchAllIamPoliciesRequest): The initial request object. - response (:class:`~.asset_service.SearchAllIamPoliciesResponse`): + response (google.cloud.asset_v1p1beta1.types.SearchAllIamPoliciesResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. diff --git a/google/cloud/asset_v1p1beta1/services/asset_service/transports/base.py b/google/cloud/asset_v1p1beta1/services/asset_service/transports/base.py index f43cae3f..ac7805cf 100644 --- a/google/cloud/asset_v1p1beta1/services/asset_service/transports/base.py +++ b/google/cloud/asset_v1p1beta1/services/asset_service/transports/base.py @@ -67,10 +67,10 @@ def __init__( scope (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 + 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. """ # Save the hostname. Default to port 443 (HTTPS) if none is specified. @@ -78,6 +78,9 @@ def __init__( host += ":443" self._host = host + # Save the scopes. + self._scopes = scopes or self.AUTH_SCOPES + # If no credentials are provided, then determine the appropriate # defaults. if credentials and credentials_file: @@ -87,20 +90,17 @@ def __init__( if credentials_file is not None: credentials, _ = auth.load_credentials_from_file( - credentials_file, scopes=scopes, quota_project_id=quota_project_id + credentials_file, scopes=self._scopes, quota_project_id=quota_project_id ) elif credentials is None: credentials, _ = auth.default( - scopes=scopes, quota_project_id=quota_project_id + scopes=self._scopes, quota_project_id=quota_project_id ) # Save the credentials. self._credentials = credentials - # Lifted into its own function so it can be stubbed out during tests. - self._prep_wrapped_messages(client_info) - def _prep_wrapped_messages(self, client_info): # Precompute the wrapped methods. self._wrapped_methods = { @@ -113,6 +113,7 @@ def _prep_wrapped_messages(self, client_info): predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=15.0, ), default_timeout=15.0, client_info=client_info, @@ -126,6 +127,7 @@ def _prep_wrapped_messages(self, client_info): predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=15.0, ), default_timeout=15.0, client_info=client_info, diff --git a/google/cloud/asset_v1p1beta1/services/asset_service/transports/grpc.py b/google/cloud/asset_v1p1beta1/services/asset_service/transports/grpc.py index 1310afdb..ddeedcc9 100644 --- a/google/cloud/asset_v1p1beta1/services/asset_service/transports/grpc.py +++ b/google/cloud/asset_v1p1beta1/services/asset_service/transports/grpc.py @@ -57,6 +57,7 @@ def __init__( 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, ) -> None: @@ -87,6 +88,10 @@ def __init__( ``api_mtls_endpoint`` is None. ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials for 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 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): @@ -101,72 +106,60 @@ def __init__( google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` and ``credentials_file`` are passed. """ + self._grpc_channel = None self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} + + if api_mtls_endpoint: + warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning) + if client_cert_source: + warnings.warn("client_cert_source is deprecated", DeprecationWarning) if channel: - # Sanity check: Ensure that channel and credentials are not both - # provided. + # 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 - elif api_mtls_endpoint: - warnings.warn( - "api_mtls_endpoint and client_cert_source are deprecated", - DeprecationWarning, - ) - host = ( - api_mtls_endpoint - if ":" in api_mtls_endpoint - else api_mtls_endpoint + ":443" - ) + 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 - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) - - # Create SSL credentials with client_cert_source or application - # default SSL credentials. - if client_cert_source: - cert, key = client_cert_source() - ssl_credentials = grpc.ssl_channel_credentials( - certificate_chain=cert, private_key=key - ) else: - ssl_credentials = SslCredentials().ssl_credentials - - # create a new channel. The provided one is ignored. - self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, - credentials_file=credentials_file, - ssl_credentials=ssl_credentials, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - options=[ - ("grpc.max_send_message_length", -1), - ("grpc.max_receive_message_length", -1), - ], - ) - self._ssl_channel_credentials = ssl_credentials - else: - host = host if ":" in host else host + ":443" + 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 + ) - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) + # 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, + ) - # create a new channel. The provided one is ignored. + if not self._grpc_channel: self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, + self._host, + credentials=self._credentials, credentials_file=credentials_file, - ssl_credentials=ssl_channel_credentials, - scopes=scopes or self.AUTH_SCOPES, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, quota_project_id=quota_project_id, options=[ ("grpc.max_send_message_length", -1), @@ -174,17 +167,8 @@ def __init__( ], ) - self._stubs = {} # type: Dict[str, Callable] - - # Run the base constructor. - super().__init__( - host=host, - credentials=credentials, - credentials_file=credentials_file, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - client_info=client_info, - ) + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) @classmethod def create_channel( @@ -198,7 +182,7 @@ def create_channel( ) -> grpc.Channel: """Create and return a gRPC channel object. Args: - address (Optional[str]): The host for the channel to use. + 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 diff --git a/google/cloud/asset_v1p1beta1/services/asset_service/transports/grpc_asyncio.py b/google/cloud/asset_v1p1beta1/services/asset_service/transports/grpc_asyncio.py index 6810dd05..fc04ac39 100644 --- a/google/cloud/asset_v1p1beta1/services/asset_service/transports/grpc_asyncio.py +++ b/google/cloud/asset_v1p1beta1/services/asset_service/transports/grpc_asyncio.py @@ -61,7 +61,7 @@ def create_channel( ) -> aio.Channel: """Create and return a gRPC AsyncIO channel object. Args: - address (Optional[str]): The host for the channel to use. + 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 @@ -101,6 +101,7 @@ def __init__( 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, ) -> None: @@ -132,12 +133,16 @@ def __init__( ``api_mtls_endpoint`` is None. ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials for 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 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 + 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: @@ -146,72 +151,60 @@ def __init__( google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` and ``credentials_file`` are passed. """ + self._grpc_channel = None self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} + + if api_mtls_endpoint: + warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning) + if client_cert_source: + warnings.warn("client_cert_source is deprecated", DeprecationWarning) if channel: - # Sanity check: Ensure that channel and credentials are not both - # provided. + # 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 - elif api_mtls_endpoint: - warnings.warn( - "api_mtls_endpoint and client_cert_source are deprecated", - DeprecationWarning, - ) - host = ( - api_mtls_endpoint - if ":" in api_mtls_endpoint - else api_mtls_endpoint + ":443" - ) + 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 - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) - - # Create SSL credentials with client_cert_source or application - # default SSL credentials. - if client_cert_source: - cert, key = client_cert_source() - ssl_credentials = grpc.ssl_channel_credentials( - certificate_chain=cert, private_key=key - ) else: - ssl_credentials = SslCredentials().ssl_credentials - - # create a new channel. The provided one is ignored. - self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, - credentials_file=credentials_file, - ssl_credentials=ssl_credentials, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - options=[ - ("grpc.max_send_message_length", -1), - ("grpc.max_receive_message_length", -1), - ], - ) - self._ssl_channel_credentials = ssl_credentials - else: - host = host if ":" in host else host + ":443" + 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 + ) - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) + # 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, + ) - # create a new channel. The provided one is ignored. + if not self._grpc_channel: self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, + self._host, + credentials=self._credentials, credentials_file=credentials_file, - ssl_credentials=ssl_channel_credentials, - scopes=scopes or self.AUTH_SCOPES, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, quota_project_id=quota_project_id, options=[ ("grpc.max_send_message_length", -1), @@ -219,17 +212,8 @@ def __init__( ], ) - # Run the base constructor. - super().__init__( - host=host, - credentials=credentials, - credentials_file=credentials_file, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - client_info=client_info, - ) - - self._stubs = {} + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) @property def grpc_channel(self) -> aio.Channel: diff --git a/google/cloud/asset_v1p1beta1/types/__init__.py b/google/cloud/asset_v1p1beta1/types/__init__.py index a5dd1af7..47321140 100644 --- a/google/cloud/asset_v1p1beta1/types/__init__.py +++ b/google/cloud/asset_v1p1beta1/types/__init__.py @@ -15,24 +15,24 @@ # limitations under the License. # -from .assets import ( - StandardResourceMetadata, - IamPolicySearchResult, - Permissions, -) from .asset_service import ( - SearchAllResourcesRequest, - SearchAllResourcesResponse, SearchAllIamPoliciesRequest, SearchAllIamPoliciesResponse, + SearchAllResourcesRequest, + SearchAllResourcesResponse, +) +from .assets import ( + IamPolicySearchResult, + Permissions, + StandardResourceMetadata, ) __all__ = ( - "StandardResourceMetadata", - "IamPolicySearchResult", - "Permissions", - "SearchAllResourcesRequest", - "SearchAllResourcesResponse", "SearchAllIamPoliciesRequest", "SearchAllIamPoliciesResponse", + "SearchAllResourcesRequest", + "SearchAllResourcesResponse", + "IamPolicySearchResult", + "Permissions", + "StandardResourceMetadata", ) diff --git a/google/cloud/asset_v1p1beta1/types/asset_service.py b/google/cloud/asset_v1p1beta1/types/asset_service.py index 71aa5286..b0c8459f 100644 --- a/google/cloud/asset_v1p1beta1/types/asset_service.py +++ b/google/cloud/asset_v1p1beta1/types/asset_service.py @@ -90,7 +90,7 @@ class SearchAllResourcesResponse(proto.Message): r"""Search all resources response. Attributes: - results (Sequence[~.assets.StandardResourceMetadata]): + results (Sequence[google.cloud.asset_v1p1beta1.types.StandardResourceMetadata]): A list of resource that match the search query. next_page_token (str): @@ -157,7 +157,7 @@ class SearchAllIamPoliciesResponse(proto.Message): r"""Search all IAM policies response. Attributes: - results (Sequence[~.assets.IamPolicySearchResult]): + results (Sequence[google.cloud.asset_v1p1beta1.types.IamPolicySearchResult]): A list of IamPolicy that match the search query. Related information such as the associated resource is returned along with the diff --git a/google/cloud/asset_v1p1beta1/types/assets.py b/google/cloud/asset_v1p1beta1/types/assets.py index d53fa624..9fa19903 100644 --- a/google/cloud/asset_v1p1beta1/types/assets.py +++ b/google/cloud/asset_v1p1beta1/types/assets.py @@ -57,7 +57,7 @@ class StandardResourceMetadata(proto.Message): location (str): Location can be "global", regional like "us- ast1", or zonal like "us-west1-b". - labels (Sequence[~.assets.StandardResourceMetadata.LabelsEntry]): + labels (Sequence[google.cloud.asset_v1p1beta1.types.StandardResourceMetadata.LabelsEntry]): Labels associated with this resource. See `Labelling and grouping GCP resources `__ @@ -104,7 +104,7 @@ class IamPolicySearchResult(proto.Message): bucket), the project field will indicate the project that contains the resource. If an IAM policy is set on a folder or orgnization, the project field will be empty. - policy (~.giv_policy.Policy): + policy (google.iam.v1.policy_pb2.Policy): The IAM policy directly set on the given resource. Note that the original IAM policy can contain multiple bindings. This only contains @@ -112,7 +112,7 @@ class IamPolicySearchResult(proto.Message): queries that don't contain a constrain on policies (e.g. an empty query), this contains all the bindings. - explanation (~.assets.IamPolicySearchResult.Explanation): + explanation (google.cloud.asset_v1p1beta1.types.IamPolicySearchResult.Explanation): Explanation about the IAM policy search result. It contains additional information to explain why the search result matches the query. @@ -122,7 +122,7 @@ class Explanation(proto.Message): r"""Explanation about the IAM policy search result. Attributes: - matched_permissions (Sequence[~.assets.IamPolicySearchResult.Explanation.MatchedPermissionsEntry]): + matched_permissions (Sequence[google.cloud.asset_v1p1beta1.types.IamPolicySearchResult.Explanation.MatchedPermissionsEntry]): The map from roles to their included permission matching the permission query (e.g. containing ``policy.role.permissions:``). A sample role string: diff --git a/google/cloud/asset_v1p2beta1/services/asset_service/async_client.py b/google/cloud/asset_v1p2beta1/services/asset_service/async_client.py index 11230e08..b6ab2109 100644 --- a/google/cloud/asset_v1p2beta1/services/asset_service/async_client.py +++ b/google/cloud/asset_v1p2beta1/services/asset_service/async_client.py @@ -71,7 +71,36 @@ class AssetServiceAsyncClient: AssetServiceClient.parse_common_location_path ) - from_service_account_file = AssetServiceClient.from_service_account_file + @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: + AssetServiceAsyncClient: The constructed client. + """ + return AssetServiceClient.from_service_account_info.__func__(AssetServiceAsyncClient, 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: + AssetServiceAsyncClient: The constructed client. + """ + return AssetServiceClient.from_service_account_file.__func__(AssetServiceAsyncClient, filename, *args, **kwargs) # type: ignore + from_service_account_json = from_service_account_file @property @@ -149,7 +178,7 @@ async def create_feed( updates. Args: - request (:class:`~.asset_service.CreateFeedRequest`): + request (:class:`google.cloud.asset_v1p2beta1.types.CreateFeedRequest`): The request object. Create asset feed request. parent (:class:`str`): Required. The name of the @@ -161,6 +190,7 @@ async def create_feed( (such as "projects/my-project-id")", or a project number (such as "projects/12345"). + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -172,7 +202,7 @@ async def create_feed( sent along with the request as metadata. Returns: - ~.asset_service.Feed: + google.cloud.asset_v1p2beta1.types.Feed: An asset feed used to export asset updates to a destinations. An asset feed filter controls what updates are @@ -232,13 +262,14 @@ async def get_feed( r"""Gets details about an asset feed. Args: - request (:class:`~.asset_service.GetFeedRequest`): + request (:class:`google.cloud.asset_v1p2beta1.types.GetFeedRequest`): The request object. Get asset feed request. name (:class:`str`): Required. The name of the Feed and it must be in the format of: projects/project_number/feeds/feed_id folders/folder_number/feeds/feed_id organizations/organization_number/feeds/feed_id + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -250,7 +281,7 @@ async def get_feed( sent along with the request as metadata. Returns: - ~.asset_service.Feed: + google.cloud.asset_v1p2beta1.types.Feed: An asset feed used to export asset updates to a destinations. An asset feed filter controls what updates are @@ -289,6 +320,7 @@ async def get_feed( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=60.0, ), default_timeout=60.0, client_info=DEFAULT_CLIENT_INFO, @@ -319,7 +351,7 @@ async def list_feeds( project/folder/organization. Args: - request (:class:`~.asset_service.ListFeedsRequest`): + request (:class:`google.cloud.asset_v1p2beta1.types.ListFeedsRequest`): The request object. List asset feeds request. parent (:class:`str`): Required. The parent @@ -328,6 +360,7 @@ async def list_feeds( project/folder/organization number (such as "folders/12345")", or a project ID (such as "projects/my-project-id"). + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -339,7 +372,7 @@ async def list_feeds( sent along with the request as metadata. Returns: - ~.asset_service.ListFeedsResponse: + google.cloud.asset_v1p2beta1.types.ListFeedsResponse: """ # Create or coerce a protobuf request object. @@ -371,6 +404,7 @@ async def list_feeds( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=60.0, ), default_timeout=60.0, client_info=DEFAULT_CLIENT_INFO, @@ -400,14 +434,15 @@ async def update_feed( r"""Updates an asset feed configuration. Args: - request (:class:`~.asset_service.UpdateFeedRequest`): + request (:class:`google.cloud.asset_v1p2beta1.types.UpdateFeedRequest`): The request object. Update asset feed request. - feed (:class:`~.asset_service.Feed`): + feed (:class:`google.cloud.asset_v1p2beta1.types.Feed`): Required. The new values of feed details. It must match an existing feed and the field ``name`` must be in the format of: projects/project_number/feeds/feed_id or folders/folder_number/feeds/feed_id or organizations/organization_number/feeds/feed_id. + This corresponds to the ``feed`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -419,7 +454,7 @@ async def update_feed( sent along with the request as metadata. Returns: - ~.asset_service.Feed: + google.cloud.asset_v1p2beta1.types.Feed: An asset feed used to export asset updates to a destinations. An asset feed filter controls what updates are @@ -481,13 +516,14 @@ async def delete_feed( r"""Deletes an asset feed. Args: - request (:class:`~.asset_service.DeleteFeedRequest`): + request (:class:`google.cloud.asset_v1p2beta1.types.DeleteFeedRequest`): The request object. name (:class:`str`): Required. The name of the feed and it must be in the format of: projects/project_number/feeds/feed_id folders/folder_number/feeds/feed_id organizations/organization_number/feeds/feed_id + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -527,6 +563,7 @@ async def delete_feed( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=60.0, ), default_timeout=60.0, client_info=DEFAULT_CLIENT_INFO, diff --git a/google/cloud/asset_v1p2beta1/services/asset_service/client.py b/google/cloud/asset_v1p2beta1/services/asset_service/client.py index 36f37947..a2ddcef1 100644 --- a/google/cloud/asset_v1p2beta1/services/asset_service/client.py +++ b/google/cloud/asset_v1p2beta1/services/asset_service/client.py @@ -107,6 +107,22 @@ def _get_default_mtls_endpoint(api_endpoint): 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: + AssetServiceClient: 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 @@ -119,7 +135,7 @@ def from_service_account_file(cls, filename: str, *args, **kwargs): kwargs: Additional arguments to pass to the constructor. Returns: - {@api.name}: The constructed client. + AssetServiceClient: The constructed client. """ credentials = service_account.Credentials.from_service_account_file(filename) kwargs["credentials"] = credentials @@ -222,10 +238,10 @@ def __init__( 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, ~.AssetServiceTransport]): The + transport (Union[str, AssetServiceTransport]): The transport to use. If set to None, a transport is chosen automatically. - client_options (client_options_lib.ClientOptions): Custom options for the + 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 @@ -261,21 +277,17 @@ def __init__( util.strtobool(os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false")) ) - ssl_credentials = None + client_cert_source_func = None is_mtls = False if use_client_cert: if client_options.client_cert_source: - import grpc # type: ignore - - cert, key = client_options.client_cert_source() - ssl_credentials = grpc.ssl_channel_credentials( - certificate_chain=cert, private_key=key - ) is_mtls = True + client_cert_source_func = client_options.client_cert_source else: - creds = SslCredentials() - is_mtls = creds.is_mtls - ssl_credentials = creds.ssl_credentials if is_mtls else None + is_mtls = mtls.has_default_client_cert_source() + client_cert_source_func = ( + mtls.default_client_cert_source() if is_mtls else None + ) # Figure out which api endpoint to use. if client_options.api_endpoint is not None: @@ -318,7 +330,7 @@ def __init__( credentials_file=client_options.credentials_file, host=api_endpoint, scopes=client_options.scopes, - ssl_channel_credentials=ssl_credentials, + client_cert_source_for_mtls=client_cert_source_func, quota_project_id=client_options.quota_project_id, client_info=client_info, ) @@ -337,9 +349,9 @@ def create_feed( updates. Args: - request (:class:`~.asset_service.CreateFeedRequest`): + request (google.cloud.asset_v1p2beta1.types.CreateFeedRequest): The request object. Create asset feed request. - parent (:class:`str`): + parent (str): Required. The name of the project/folder/organization where this feed should be created in. It can only @@ -349,6 +361,7 @@ def create_feed( (such as "projects/my-project-id")", or a project number (such as "projects/12345"). + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -360,7 +373,7 @@ def create_feed( sent along with the request as metadata. Returns: - ~.asset_service.Feed: + google.cloud.asset_v1p2beta1.types.Feed: An asset feed used to export asset updates to a destinations. An asset feed filter controls what updates are @@ -421,13 +434,14 @@ def get_feed( r"""Gets details about an asset feed. Args: - request (:class:`~.asset_service.GetFeedRequest`): + request (google.cloud.asset_v1p2beta1.types.GetFeedRequest): The request object. Get asset feed request. - name (:class:`str`): + name (str): Required. The name of the Feed and it must be in the format of: projects/project_number/feeds/feed_id folders/folder_number/feeds/feed_id organizations/organization_number/feeds/feed_id + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -439,7 +453,7 @@ def get_feed( sent along with the request as metadata. Returns: - ~.asset_service.Feed: + google.cloud.asset_v1p2beta1.types.Feed: An asset feed used to export asset updates to a destinations. An asset feed filter controls what updates are @@ -501,15 +515,16 @@ def list_feeds( project/folder/organization. Args: - request (:class:`~.asset_service.ListFeedsRequest`): + request (google.cloud.asset_v1p2beta1.types.ListFeedsRequest): The request object. List asset feeds request. - parent (:class:`str`): + parent (str): Required. The parent project/folder/organization whose feeds are to be listed. It can only be using project/folder/organization number (such as "folders/12345")", or a project ID (such as "projects/my-project-id"). + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -521,7 +536,7 @@ def list_feeds( sent along with the request as metadata. Returns: - ~.asset_service.ListFeedsResponse: + google.cloud.asset_v1p2beta1.types.ListFeedsResponse: """ # Create or coerce a protobuf request object. @@ -575,14 +590,15 @@ def update_feed( r"""Updates an asset feed configuration. Args: - request (:class:`~.asset_service.UpdateFeedRequest`): + request (google.cloud.asset_v1p2beta1.types.UpdateFeedRequest): The request object. Update asset feed request. - feed (:class:`~.asset_service.Feed`): + feed (google.cloud.asset_v1p2beta1.types.Feed): Required. The new values of feed details. It must match an existing feed and the field ``name`` must be in the format of: projects/project_number/feeds/feed_id or folders/folder_number/feeds/feed_id or organizations/organization_number/feeds/feed_id. + This corresponds to the ``feed`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -594,7 +610,7 @@ def update_feed( sent along with the request as metadata. Returns: - ~.asset_service.Feed: + google.cloud.asset_v1p2beta1.types.Feed: An asset feed used to export asset updates to a destinations. An asset feed filter controls what updates are @@ -657,13 +673,14 @@ def delete_feed( r"""Deletes an asset feed. Args: - request (:class:`~.asset_service.DeleteFeedRequest`): + request (google.cloud.asset_v1p2beta1.types.DeleteFeedRequest): The request object. - name (:class:`str`): + name (str): Required. The name of the feed and it must be in the format of: projects/project_number/feeds/feed_id folders/folder_number/feeds/feed_id organizations/organization_number/feeds/feed_id + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. diff --git a/google/cloud/asset_v1p2beta1/services/asset_service/transports/base.py b/google/cloud/asset_v1p2beta1/services/asset_service/transports/base.py index 7f9a2afa..fae4c7be 100644 --- a/google/cloud/asset_v1p2beta1/services/asset_service/transports/base.py +++ b/google/cloud/asset_v1p2beta1/services/asset_service/transports/base.py @@ -68,10 +68,10 @@ def __init__( scope (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 + 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. """ # Save the hostname. Default to port 443 (HTTPS) if none is specified. @@ -79,6 +79,9 @@ def __init__( host += ":443" self._host = host + # Save the scopes. + self._scopes = scopes or self.AUTH_SCOPES + # If no credentials are provided, then determine the appropriate # defaults. if credentials and credentials_file: @@ -88,20 +91,17 @@ def __init__( if credentials_file is not None: credentials, _ = auth.load_credentials_from_file( - credentials_file, scopes=scopes, quota_project_id=quota_project_id + credentials_file, scopes=self._scopes, quota_project_id=quota_project_id ) elif credentials is None: credentials, _ = auth.default( - scopes=scopes, quota_project_id=quota_project_id + scopes=self._scopes, quota_project_id=quota_project_id ) # Save the credentials. self._credentials = credentials - # Lifted into its own function so it can be stubbed out during tests. - self._prep_wrapped_messages(client_info) - def _prep_wrapped_messages(self, client_info): # Precompute the wrapped methods. self._wrapped_methods = { @@ -117,6 +117,7 @@ def _prep_wrapped_messages(self, client_info): predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=60.0, ), default_timeout=60.0, client_info=client_info, @@ -130,6 +131,7 @@ def _prep_wrapped_messages(self, client_info): predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=60.0, ), default_timeout=60.0, client_info=client_info, @@ -146,6 +148,7 @@ def _prep_wrapped_messages(self, client_info): predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=60.0, ), default_timeout=60.0, client_info=client_info, diff --git a/google/cloud/asset_v1p2beta1/services/asset_service/transports/grpc.py b/google/cloud/asset_v1p2beta1/services/asset_service/transports/grpc.py index e30ae165..70d3ab33 100644 --- a/google/cloud/asset_v1p2beta1/services/asset_service/transports/grpc.py +++ b/google/cloud/asset_v1p2beta1/services/asset_service/transports/grpc.py @@ -58,6 +58,7 @@ def __init__( 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, ) -> None: @@ -88,6 +89,10 @@ def __init__( ``api_mtls_endpoint`` is None. ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials for 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 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): @@ -102,72 +107,60 @@ def __init__( google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` and ``credentials_file`` are passed. """ + self._grpc_channel = None self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} + + if api_mtls_endpoint: + warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning) + if client_cert_source: + warnings.warn("client_cert_source is deprecated", DeprecationWarning) if channel: - # Sanity check: Ensure that channel and credentials are not both - # provided. + # 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 - elif api_mtls_endpoint: - warnings.warn( - "api_mtls_endpoint and client_cert_source are deprecated", - DeprecationWarning, - ) - host = ( - api_mtls_endpoint - if ":" in api_mtls_endpoint - else api_mtls_endpoint + ":443" - ) + 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 - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) - - # Create SSL credentials with client_cert_source or application - # default SSL credentials. - if client_cert_source: - cert, key = client_cert_source() - ssl_credentials = grpc.ssl_channel_credentials( - certificate_chain=cert, private_key=key - ) else: - ssl_credentials = SslCredentials().ssl_credentials - - # create a new channel. The provided one is ignored. - self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, - credentials_file=credentials_file, - ssl_credentials=ssl_credentials, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - options=[ - ("grpc.max_send_message_length", -1), - ("grpc.max_receive_message_length", -1), - ], - ) - self._ssl_channel_credentials = ssl_credentials - else: - host = host if ":" in host else host + ":443" + 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 + ) - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) + # 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, + ) - # create a new channel. The provided one is ignored. + if not self._grpc_channel: self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, + self._host, + credentials=self._credentials, credentials_file=credentials_file, - ssl_credentials=ssl_channel_credentials, - scopes=scopes or self.AUTH_SCOPES, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, quota_project_id=quota_project_id, options=[ ("grpc.max_send_message_length", -1), @@ -175,17 +168,8 @@ def __init__( ], ) - self._stubs = {} # type: Dict[str, Callable] - - # Run the base constructor. - super().__init__( - host=host, - credentials=credentials, - credentials_file=credentials_file, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - client_info=client_info, - ) + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) @classmethod def create_channel( @@ -199,7 +183,7 @@ def create_channel( ) -> grpc.Channel: """Create and return a gRPC channel object. Args: - address (Optional[str]): The host for the channel to use. + 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 diff --git a/google/cloud/asset_v1p2beta1/services/asset_service/transports/grpc_asyncio.py b/google/cloud/asset_v1p2beta1/services/asset_service/transports/grpc_asyncio.py index 59b54443..275c68d3 100644 --- a/google/cloud/asset_v1p2beta1/services/asset_service/transports/grpc_asyncio.py +++ b/google/cloud/asset_v1p2beta1/services/asset_service/transports/grpc_asyncio.py @@ -62,7 +62,7 @@ def create_channel( ) -> aio.Channel: """Create and return a gRPC AsyncIO channel object. Args: - address (Optional[str]): The host for the channel to use. + 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 @@ -102,6 +102,7 @@ def __init__( 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, ) -> None: @@ -133,12 +134,16 @@ def __init__( ``api_mtls_endpoint`` is None. ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials for 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 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 + 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: @@ -147,72 +152,60 @@ def __init__( google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` and ``credentials_file`` are passed. """ + self._grpc_channel = None self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} + + if api_mtls_endpoint: + warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning) + if client_cert_source: + warnings.warn("client_cert_source is deprecated", DeprecationWarning) if channel: - # Sanity check: Ensure that channel and credentials are not both - # provided. + # 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 - elif api_mtls_endpoint: - warnings.warn( - "api_mtls_endpoint and client_cert_source are deprecated", - DeprecationWarning, - ) - host = ( - api_mtls_endpoint - if ":" in api_mtls_endpoint - else api_mtls_endpoint + ":443" - ) + 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 - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) - - # Create SSL credentials with client_cert_source or application - # default SSL credentials. - if client_cert_source: - cert, key = client_cert_source() - ssl_credentials = grpc.ssl_channel_credentials( - certificate_chain=cert, private_key=key - ) else: - ssl_credentials = SslCredentials().ssl_credentials - - # create a new channel. The provided one is ignored. - self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, - credentials_file=credentials_file, - ssl_credentials=ssl_credentials, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - options=[ - ("grpc.max_send_message_length", -1), - ("grpc.max_receive_message_length", -1), - ], - ) - self._ssl_channel_credentials = ssl_credentials - else: - host = host if ":" in host else host + ":443" + 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 + ) - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) + # 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, + ) - # create a new channel. The provided one is ignored. + if not self._grpc_channel: self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, + self._host, + credentials=self._credentials, credentials_file=credentials_file, - ssl_credentials=ssl_channel_credentials, - scopes=scopes or self.AUTH_SCOPES, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, quota_project_id=quota_project_id, options=[ ("grpc.max_send_message_length", -1), @@ -220,17 +213,8 @@ def __init__( ], ) - # Run the base constructor. - super().__init__( - host=host, - credentials=credentials, - credentials_file=credentials_file, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - client_info=client_info, - ) - - self._stubs = {} + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) @property def grpc_channel(self) -> aio.Channel: diff --git a/google/cloud/asset_v1p2beta1/types/__init__.py b/google/cloud/asset_v1p2beta1/types/__init__.py index 7c5b86e3..0976221c 100644 --- a/google/cloud/asset_v1p2beta1/types/__init__.py +++ b/google/cloud/asset_v1p2beta1/types/__init__.py @@ -15,42 +15,42 @@ # limitations under the License. # -from .assets import ( - TemporalAsset, - TimeWindow, - Asset, - Resource, -) from .asset_service import ( CreateFeedRequest, + DeleteFeedRequest, + Feed, + FeedOutputConfig, + GcsDestination, GetFeedRequest, ListFeedsRequest, ListFeedsResponse, - UpdateFeedRequest, - DeleteFeedRequest, OutputConfig, - GcsDestination, PubsubDestination, - FeedOutputConfig, - Feed, + UpdateFeedRequest, ContentType, ) +from .assets import ( + Asset, + Resource, + TemporalAsset, + TimeWindow, +) __all__ = ( - "TemporalAsset", - "TimeWindow", - "Asset", - "Resource", "CreateFeedRequest", + "DeleteFeedRequest", + "Feed", + "FeedOutputConfig", + "GcsDestination", "GetFeedRequest", "ListFeedsRequest", "ListFeedsResponse", - "UpdateFeedRequest", - "DeleteFeedRequest", "OutputConfig", - "GcsDestination", "PubsubDestination", - "FeedOutputConfig", - "Feed", + "UpdateFeedRequest", "ContentType", + "Asset", + "Resource", + "TemporalAsset", + "TimeWindow", ) diff --git a/google/cloud/asset_v1p2beta1/types/asset_service.py b/google/cloud/asset_v1p2beta1/types/asset_service.py index 43aa2f1a..74a242ca 100644 --- a/google/cloud/asset_v1p2beta1/types/asset_service.py +++ b/google/cloud/asset_v1p2beta1/types/asset_service.py @@ -64,7 +64,7 @@ class CreateFeedRequest(proto.Message): Required. This is the client-assigned asset feed identifier and it needs to be unique under a specific parent project/folder/organization. - feed (~.asset_service.Feed): + feed (google.cloud.asset_v1p2beta1.types.Feed): Required. The feed details. The field ``name`` must be empty and it will be generated in the format of: projects/project_number/feeds/feed_id @@ -113,7 +113,7 @@ class ListFeedsResponse(proto.Message): r""" Attributes: - feeds (Sequence[~.asset_service.Feed]): + feeds (Sequence[google.cloud.asset_v1p2beta1.types.Feed]): A list of feeds. """ @@ -124,13 +124,13 @@ class UpdateFeedRequest(proto.Message): r"""Update asset feed request. Attributes: - feed (~.asset_service.Feed): + feed (google.cloud.asset_v1p2beta1.types.Feed): Required. The new values of feed details. It must match an existing feed and the field ``name`` must be in the format of: projects/project_number/feeds/feed_id or folders/folder_number/feeds/feed_id or organizations/organization_number/feeds/feed_id. - update_mask (~.field_mask.FieldMask): + update_mask (google.protobuf.field_mask_pb2.FieldMask): Required. Only updates the ``feed`` fields indicated by this mask. The field mask must not be empty, and it must not contain fields that are immutable or only set by the server. @@ -159,7 +159,7 @@ class OutputConfig(proto.Message): r"""Output configuration for export assets destination. Attributes: - gcs_destination (~.asset_service.GcsDestination): + gcs_destination (google.cloud.asset_v1p2beta1.types.GcsDestination): Destination on Cloud Storage. """ @@ -200,7 +200,7 @@ class FeedOutputConfig(proto.Message): r"""Output configuration for asset feed destination. Attributes: - pubsub_destination (~.asset_service.PubsubDestination): + pubsub_destination (google.cloud.asset_v1p2beta1.types.PubsubDestination): Destination on Cloud Pubsub. """ @@ -246,11 +246,11 @@ class Feed(proto.Message): Asset Inventory `__ for all supported asset types. - content_type (~.asset_service.ContentType): + content_type (google.cloud.asset_v1p2beta1.types.ContentType): Asset content type. If not specified, no content but the asset name and type will be returned. - feed_output_config (~.asset_service.FeedOutputConfig): + feed_output_config (google.cloud.asset_v1p2beta1.types.FeedOutputConfig): Required. Feed output configuration defining where the asset updates are published to. """ diff --git a/google/cloud/asset_v1p2beta1/types/assets.py b/google/cloud/asset_v1p2beta1/types/assets.py index 84f260f3..aa225389 100644 --- a/google/cloud/asset_v1p2beta1/types/assets.py +++ b/google/cloud/asset_v1p2beta1/types/assets.py @@ -35,12 +35,12 @@ class TemporalAsset(proto.Message): it. Attributes: - window (~.assets.TimeWindow): + window (google.cloud.asset_v1p2beta1.types.TimeWindow): The time window when the asset data and state was observed. deleted (bool): If the asset is deleted or not. - asset (~.assets.Asset): + asset (google.cloud.asset_v1p2beta1.types.Asset): Asset. """ @@ -55,9 +55,9 @@ class TimeWindow(proto.Message): r"""A time window of (start_time, end_time]. Attributes: - start_time (~.timestamp.Timestamp): + start_time (google.protobuf.timestamp_pb2.Timestamp): Start time of the time window (exclusive). - end_time (~.timestamp.Timestamp): + end_time (google.protobuf.timestamp_pb2.Timestamp): End time of the time window (inclusive). Current timestamp if not specified. """ @@ -81,9 +81,9 @@ class Asset(proto.Message): asset_type (str): Type of the asset. Example: "compute.googleapis.com/Disk". - resource (~.assets.Resource): + resource (google.cloud.asset_v1p2beta1.types.Resource): Representation of the resource. - iam_policy (~.policy.Policy): + iam_policy (google.iam.v1.policy_pb2.Policy): Representation of the actual Cloud IAM policy set on a cloud resource. For each resource, there must be at most one Cloud IAM policy set @@ -147,7 +147,7 @@ class Resource(proto.Message): ``"//cloudresourcemanager.googleapis.com/projects/my_project_123"``. For third-party assets, it is up to the users to define. - data (~.struct.Struct): + data (google.protobuf.struct_pb2.Struct): The content of the resource, in which some sensitive fields are scrubbed away and may not be present. diff --git a/google/cloud/asset_v1p4beta1/services/asset_service/async_client.py b/google/cloud/asset_v1p4beta1/services/asset_service/async_client.py index f3880182..d4267794 100644 --- a/google/cloud/asset_v1p4beta1/services/asset_service/async_client.py +++ b/google/cloud/asset_v1p4beta1/services/asset_service/async_client.py @@ -71,7 +71,36 @@ class AssetServiceAsyncClient: AssetServiceClient.parse_common_location_path ) - from_service_account_file = AssetServiceClient.from_service_account_file + @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: + AssetServiceAsyncClient: The constructed client. + """ + return AssetServiceClient.from_service_account_info.__func__(AssetServiceAsyncClient, 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: + AssetServiceAsyncClient: The constructed client. + """ + return AssetServiceClient.from_service_account_file.__func__(AssetServiceAsyncClient, filename, *args, **kwargs) # type: ignore + from_service_account_json = from_service_account_file @property @@ -149,7 +178,7 @@ async def analyze_iam_policy( matching the request. Args: - request (:class:`~.asset_service.AnalyzeIamPolicyRequest`): + request (:class:`google.cloud.asset_v1p4beta1.types.AnalyzeIamPolicyRequest`): The request object. A request message for [AssetService.AnalyzeIamPolicy][google.cloud.asset.v1p4beta1.AssetService.AnalyzeIamPolicy]. @@ -160,7 +189,7 @@ async def analyze_iam_policy( sent along with the request as metadata. Returns: - ~.asset_service.AnalyzeIamPolicyResponse: + google.cloud.asset_v1p4beta1.types.AnalyzeIamPolicyResponse: A response message for [AssetService.AnalyzeIamPolicy][google.cloud.asset.v1p4beta1.AssetService.AnalyzeIamPolicy]. @@ -178,6 +207,7 @@ async def analyze_iam_policy( maximum=60.0, multiplier=1.3, predicate=retries.if_exception_type(exceptions.ServiceUnavailable,), + deadline=300.0, ), default_timeout=300.0, client_info=DEFAULT_CLIENT_INFO, @@ -212,7 +242,7 @@ async def export_iam_policy_analysis( the request to help callers to map responses to requests. Args: - request (:class:`~.asset_service.ExportIamPolicyAnalysisRequest`): + request (:class:`google.cloud.asset_v1p4beta1.types.ExportIamPolicyAnalysisRequest`): The request object. A request message for [AssetService.ExportIamPolicyAnalysis][google.cloud.asset.v1p4beta1.AssetService.ExportIamPolicyAnalysis]. @@ -223,16 +253,13 @@ async def export_iam_policy_analysis( sent along with the request as metadata. Returns: - ~.operation_async.AsyncOperation: + google.api_core.operation_async.AsyncOperation: An object representing a long-running operation. - The result type for the operation will be - :class:``~.asset_service.ExportIamPolicyAnalysisResponse``: - The export IAM policy analysis response. This message is - returned by the - [google.longrunning.Operations.GetOperation][] method in - the returned [google.longrunning.Operation.response][] - field. + The result type for the operation will be :class:`google.cloud.asset_v1p4beta1.types.ExportIamPolicyAnalysisResponse` The export IAM policy analysis response. This message is returned by the + [google.longrunning.Operations.GetOperation][] method + in the returned + [google.longrunning.Operation.response][] field. """ # Create or coerce a protobuf request object. diff --git a/google/cloud/asset_v1p4beta1/services/asset_service/client.py b/google/cloud/asset_v1p4beta1/services/asset_service/client.py index 7fe58691..f5a39adb 100644 --- a/google/cloud/asset_v1p4beta1/services/asset_service/client.py +++ b/google/cloud/asset_v1p4beta1/services/asset_service/client.py @@ -110,6 +110,22 @@ def _get_default_mtls_endpoint(api_endpoint): 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: + AssetServiceClient: 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 @@ -122,7 +138,7 @@ def from_service_account_file(cls, filename: str, *args, **kwargs): kwargs: Additional arguments to pass to the constructor. Returns: - {@api.name}: The constructed client. + AssetServiceClient: The constructed client. """ credentials = service_account.Credentials.from_service_account_file(filename) kwargs["credentials"] = credentials @@ -214,10 +230,10 @@ def __init__( 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, ~.AssetServiceTransport]): The + transport (Union[str, AssetServiceTransport]): The transport to use. If set to None, a transport is chosen automatically. - client_options (client_options_lib.ClientOptions): Custom options for the + 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 @@ -253,21 +269,17 @@ def __init__( util.strtobool(os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false")) ) - ssl_credentials = None + client_cert_source_func = None is_mtls = False if use_client_cert: if client_options.client_cert_source: - import grpc # type: ignore - - cert, key = client_options.client_cert_source() - ssl_credentials = grpc.ssl_channel_credentials( - certificate_chain=cert, private_key=key - ) is_mtls = True + client_cert_source_func = client_options.client_cert_source else: - creds = SslCredentials() - is_mtls = creds.is_mtls - ssl_credentials = creds.ssl_credentials if is_mtls else None + is_mtls = mtls.has_default_client_cert_source() + client_cert_source_func = ( + mtls.default_client_cert_source() if is_mtls else None + ) # Figure out which api endpoint to use. if client_options.api_endpoint is not None: @@ -310,7 +322,7 @@ def __init__( credentials_file=client_options.credentials_file, host=api_endpoint, scopes=client_options.scopes, - ssl_channel_credentials=ssl_credentials, + client_cert_source_for_mtls=client_cert_source_func, quota_project_id=client_options.quota_project_id, client_info=client_info, ) @@ -329,7 +341,7 @@ def analyze_iam_policy( matching the request. Args: - request (:class:`~.asset_service.AnalyzeIamPolicyRequest`): + request (google.cloud.asset_v1p4beta1.types.AnalyzeIamPolicyRequest): The request object. A request message for [AssetService.AnalyzeIamPolicy][google.cloud.asset.v1p4beta1.AssetService.AnalyzeIamPolicy]. @@ -340,7 +352,7 @@ def analyze_iam_policy( sent along with the request as metadata. Returns: - ~.asset_service.AnalyzeIamPolicyResponse: + google.cloud.asset_v1p4beta1.types.AnalyzeIamPolicyResponse: A response message for [AssetService.AnalyzeIamPolicy][google.cloud.asset.v1p4beta1.AssetService.AnalyzeIamPolicy]. @@ -387,7 +399,7 @@ def export_iam_policy_analysis( the request to help callers to map responses to requests. Args: - request (:class:`~.asset_service.ExportIamPolicyAnalysisRequest`): + request (google.cloud.asset_v1p4beta1.types.ExportIamPolicyAnalysisRequest): The request object. A request message for [AssetService.ExportIamPolicyAnalysis][google.cloud.asset.v1p4beta1.AssetService.ExportIamPolicyAnalysis]. @@ -398,16 +410,13 @@ def export_iam_policy_analysis( sent along with the request as metadata. Returns: - ~.operation.Operation: + google.api_core.operation.Operation: An object representing a long-running operation. - The result type for the operation will be - :class:``~.asset_service.ExportIamPolicyAnalysisResponse``: - The export IAM policy analysis response. This message is - returned by the - [google.longrunning.Operations.GetOperation][] method in - the returned [google.longrunning.Operation.response][] - field. + The result type for the operation will be :class:`google.cloud.asset_v1p4beta1.types.ExportIamPolicyAnalysisResponse` The export IAM policy analysis response. This message is returned by the + [google.longrunning.Operations.GetOperation][] method + in the returned + [google.longrunning.Operation.response][] field. """ # Create or coerce a protobuf request object. diff --git a/google/cloud/asset_v1p4beta1/services/asset_service/transports/base.py b/google/cloud/asset_v1p4beta1/services/asset_service/transports/base.py index 190c8cda..8702f39f 100644 --- a/google/cloud/asset_v1p4beta1/services/asset_service/transports/base.py +++ b/google/cloud/asset_v1p4beta1/services/asset_service/transports/base.py @@ -69,10 +69,10 @@ def __init__( scope (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 + 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. """ # Save the hostname. Default to port 443 (HTTPS) if none is specified. @@ -80,6 +80,9 @@ def __init__( host += ":443" self._host = host + # Save the scopes. + self._scopes = scopes or self.AUTH_SCOPES + # If no credentials are provided, then determine the appropriate # defaults. if credentials and credentials_file: @@ -89,20 +92,17 @@ def __init__( if credentials_file is not None: credentials, _ = auth.load_credentials_from_file( - credentials_file, scopes=scopes, quota_project_id=quota_project_id + credentials_file, scopes=self._scopes, quota_project_id=quota_project_id ) elif credentials is None: credentials, _ = auth.default( - scopes=scopes, quota_project_id=quota_project_id + scopes=self._scopes, quota_project_id=quota_project_id ) # Save the credentials. self._credentials = credentials - # Lifted into its own function so it can be stubbed out during tests. - self._prep_wrapped_messages(client_info) - def _prep_wrapped_messages(self, client_info): # Precompute the wrapped methods. self._wrapped_methods = { @@ -113,6 +113,7 @@ def _prep_wrapped_messages(self, client_info): maximum=60.0, multiplier=1.3, predicate=retries.if_exception_type(exceptions.ServiceUnavailable,), + deadline=300.0, ), default_timeout=300.0, client_info=client_info, diff --git a/google/cloud/asset_v1p4beta1/services/asset_service/transports/grpc.py b/google/cloud/asset_v1p4beta1/services/asset_service/transports/grpc.py index 301fb6f9..7d2c0298 100644 --- a/google/cloud/asset_v1p4beta1/services/asset_service/transports/grpc.py +++ b/google/cloud/asset_v1p4beta1/services/asset_service/transports/grpc.py @@ -59,6 +59,7 @@ def __init__( 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, ) -> None: @@ -89,6 +90,10 @@ def __init__( ``api_mtls_endpoint`` is None. ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials for 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 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): @@ -103,72 +108,61 @@ def __init__( 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 = 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: - # Sanity check: Ensure that channel and credentials are not both - # provided. + # 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 - elif api_mtls_endpoint: - warnings.warn( - "api_mtls_endpoint and client_cert_source are deprecated", - DeprecationWarning, - ) - host = ( - api_mtls_endpoint - if ":" in api_mtls_endpoint - else api_mtls_endpoint + ":443" - ) + 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 - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) - - # Create SSL credentials with client_cert_source or application - # default SSL credentials. - if client_cert_source: - cert, key = client_cert_source() - ssl_credentials = grpc.ssl_channel_credentials( - certificate_chain=cert, private_key=key - ) else: - ssl_credentials = SslCredentials().ssl_credentials + 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 + ) - # create a new channel. The provided one is ignored. - self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, - credentials_file=credentials_file, - ssl_credentials=ssl_credentials, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - options=[ - ("grpc.max_send_message_length", -1), - ("grpc.max_receive_message_length", -1), - ], - ) - self._ssl_channel_credentials = ssl_credentials - else: - host = host if ":" in host else host + ":443" - - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) + # 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, + ) - # create a new channel. The provided one is ignored. + if not self._grpc_channel: self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, + self._host, + credentials=self._credentials, credentials_file=credentials_file, - ssl_credentials=ssl_channel_credentials, - scopes=scopes or self.AUTH_SCOPES, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, quota_project_id=quota_project_id, options=[ ("grpc.max_send_message_length", -1), @@ -176,18 +170,8 @@ def __init__( ], ) - self._stubs = {} # type: Dict[str, Callable] - self._operations_client = None - - # Run the base constructor. - super().__init__( - host=host, - credentials=credentials, - credentials_file=credentials_file, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - client_info=client_info, - ) + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) @classmethod def create_channel( @@ -201,7 +185,7 @@ def create_channel( ) -> grpc.Channel: """Create and return a gRPC channel object. Args: - address (Optional[str]): The host for the channel to use. + 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 diff --git a/google/cloud/asset_v1p4beta1/services/asset_service/transports/grpc_asyncio.py b/google/cloud/asset_v1p4beta1/services/asset_service/transports/grpc_asyncio.py index 52f74e7d..f61d756b 100644 --- a/google/cloud/asset_v1p4beta1/services/asset_service/transports/grpc_asyncio.py +++ b/google/cloud/asset_v1p4beta1/services/asset_service/transports/grpc_asyncio.py @@ -63,7 +63,7 @@ def create_channel( ) -> aio.Channel: """Create and return a gRPC AsyncIO channel object. Args: - address (Optional[str]): The host for the channel to use. + 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 @@ -103,6 +103,7 @@ def __init__( 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, ) -> None: @@ -134,12 +135,16 @@ def __init__( ``api_mtls_endpoint`` is None. ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials for 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 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 + 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: @@ -148,72 +153,61 @@ def __init__( 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 = 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: - # Sanity check: Ensure that channel and credentials are not both - # provided. + # 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 - elif api_mtls_endpoint: - warnings.warn( - "api_mtls_endpoint and client_cert_source are deprecated", - DeprecationWarning, - ) - host = ( - api_mtls_endpoint - if ":" in api_mtls_endpoint - else api_mtls_endpoint + ":443" - ) + 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 - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) - - # Create SSL credentials with client_cert_source or application - # default SSL credentials. - if client_cert_source: - cert, key = client_cert_source() - ssl_credentials = grpc.ssl_channel_credentials( - certificate_chain=cert, private_key=key - ) else: - ssl_credentials = SslCredentials().ssl_credentials + 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 + ) - # create a new channel. The provided one is ignored. - self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, - credentials_file=credentials_file, - ssl_credentials=ssl_credentials, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - options=[ - ("grpc.max_send_message_length", -1), - ("grpc.max_receive_message_length", -1), - ], - ) - self._ssl_channel_credentials = ssl_credentials - else: - host = host if ":" in host else host + ":443" - - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) + # 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, + ) - # create a new channel. The provided one is ignored. + if not self._grpc_channel: self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, + self._host, + credentials=self._credentials, credentials_file=credentials_file, - ssl_credentials=ssl_channel_credentials, - scopes=scopes or self.AUTH_SCOPES, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, quota_project_id=quota_project_id, options=[ ("grpc.max_send_message_length", -1), @@ -221,18 +215,8 @@ def __init__( ], ) - # Run the base constructor. - super().__init__( - host=host, - credentials=credentials, - credentials_file=credentials_file, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - client_info=client_info, - ) - - self._stubs = {} - self._operations_client = None + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) @property def grpc_channel(self) -> aio.Channel: diff --git a/google/cloud/asset_v1p4beta1/types/__init__.py b/google/cloud/asset_v1p4beta1/types/__init__.py index 72b608ca..cfe344dd 100644 --- a/google/cloud/asset_v1p4beta1/types/__init__.py +++ b/google/cloud/asset_v1p4beta1/types/__init__.py @@ -15,22 +15,22 @@ # limitations under the License. # -from .assets import IamPolicyAnalysisResult from .asset_service import ( - IamPolicyAnalysisQuery, AnalyzeIamPolicyRequest, AnalyzeIamPolicyResponse, - IamPolicyAnalysisOutputConfig, ExportIamPolicyAnalysisRequest, ExportIamPolicyAnalysisResponse, + IamPolicyAnalysisOutputConfig, + IamPolicyAnalysisQuery, ) +from .assets import IamPolicyAnalysisResult __all__ = ( - "IamPolicyAnalysisResult", - "IamPolicyAnalysisQuery", "AnalyzeIamPolicyRequest", "AnalyzeIamPolicyResponse", - "IamPolicyAnalysisOutputConfig", "ExportIamPolicyAnalysisRequest", "ExportIamPolicyAnalysisResponse", + "IamPolicyAnalysisOutputConfig", + "IamPolicyAnalysisQuery", + "IamPolicyAnalysisResult", ) diff --git a/google/cloud/asset_v1p4beta1/types/asset_service.py b/google/cloud/asset_v1p4beta1/types/asset_service.py index 2f9285b2..67002613 100644 --- a/google/cloud/asset_v1p4beta1/types/asset_service.py +++ b/google/cloud/asset_v1p4beta1/types/asset_service.py @@ -46,13 +46,13 @@ class IamPolicyAnalysisQuery(proto.Message): organization number (such as "organizations/123") or a folder number (such as "folders/123"). - resource_selector (~.asset_service.IamPolicyAnalysisQuery.ResourceSelector): + resource_selector (google.cloud.asset_v1p4beta1.types.IamPolicyAnalysisQuery.ResourceSelector): Optional. Specifies a resource for analysis. Leaving it empty means ANY. - identity_selector (~.asset_service.IamPolicyAnalysisQuery.IdentitySelector): + identity_selector (google.cloud.asset_v1p4beta1.types.IamPolicyAnalysisQuery.IdentitySelector): Optional. Specifies an identity for analysis. Leaving it empty means ANY. - access_selector (~.asset_service.IamPolicyAnalysisQuery.AccessSelector): + access_selector (google.cloud.asset_v1p4beta1.types.IamPolicyAnalysisQuery.AccessSelector): Optional. Specifies roles or permissions for analysis. Leaving it empty means ANY. """ @@ -122,9 +122,9 @@ class AnalyzeIamPolicyRequest(proto.Message): [AssetService.AnalyzeIamPolicy][google.cloud.asset.v1p4beta1.AssetService.AnalyzeIamPolicy]. Attributes: - analysis_query (~.asset_service.IamPolicyAnalysisQuery): + analysis_query (google.cloud.asset_v1p4beta1.types.IamPolicyAnalysisQuery): Required. The request query. - options (~.asset_service.AnalyzeIamPolicyRequest.Options): + options (google.cloud.asset_v1p4beta1.types.AnalyzeIamPolicyRequest.Options): Optional. The request options. """ @@ -200,7 +200,7 @@ class Options(proto.Message): [AnalyzeIamPolicyResponse.service_account_impersonation_analysis][google.cloud.asset.v1p4beta1.AnalyzeIamPolicyResponse.service_account_impersonation_analysis]. Default is false. - execution_timeout (~.duration.Duration): + execution_timeout (google.protobuf.duration_pb2.Duration): Optional. Amount of time executable has to complete. See JSON representation of `Duration `__. @@ -243,10 +243,10 @@ class AnalyzeIamPolicyResponse(proto.Message): [AssetService.AnalyzeIamPolicy][google.cloud.asset.v1p4beta1.AssetService.AnalyzeIamPolicy]. Attributes: - main_analysis (~.asset_service.AnalyzeIamPolicyResponse.IamPolicyAnalysis): + main_analysis (google.cloud.asset_v1p4beta1.types.AnalyzeIamPolicyResponse.IamPolicyAnalysis): The main analysis that matches the original request. - service_account_impersonation_analysis (Sequence[~.asset_service.AnalyzeIamPolicyResponse.IamPolicyAnalysis]): + service_account_impersonation_analysis (Sequence[google.cloud.asset_v1p4beta1.types.AnalyzeIamPolicyResponse.IamPolicyAnalysis]): The service account impersonation analysis if [AnalyzeIamPolicyRequest.analyze_service_account_impersonation][] is enabled. @@ -256,7 +256,7 @@ class AnalyzeIamPolicyResponse(proto.Message): and [service_account_impersonation_analysis][google.cloud.asset.v1p4beta1.AnalyzeIamPolicyResponse.service_account_impersonation_analysis] have been fully explored to answer the query in the request. - non_critical_errors (Sequence[~.assets.IamPolicyAnalysisResult.AnalysisState]): + non_critical_errors (Sequence[google.cloud.asset_v1p4beta1.types.IamPolicyAnalysisResult.AnalysisState]): A list of non-critical errors happened during the request handling to explain why ``fully_explored`` is false, or empty if no error happened. @@ -266,9 +266,9 @@ class IamPolicyAnalysis(proto.Message): r"""An analysis message to group the query and results. Attributes: - analysis_query (~.asset_service.IamPolicyAnalysisQuery): + analysis_query (google.cloud.asset_v1p4beta1.types.IamPolicyAnalysisQuery): The analysis query. - analysis_results (Sequence[~.assets.IamPolicyAnalysisResult]): + analysis_results (Sequence[google.cloud.asset_v1p4beta1.types.IamPolicyAnalysisResult]): A list of [IamPolicyAnalysisResult][google.cloud.asset.v1p4beta1.IamPolicyAnalysisResult] that matches the analysis query, or empty if no result is @@ -307,7 +307,7 @@ class IamPolicyAnalysisOutputConfig(proto.Message): destination. Attributes: - gcs_destination (~.asset_service.IamPolicyAnalysisOutputConfig.GcsDestination): + gcs_destination (google.cloud.asset_v1p4beta1.types.IamPolicyAnalysisOutputConfig.GcsDestination): Destination on Cloud Storage. """ @@ -336,11 +336,11 @@ class ExportIamPolicyAnalysisRequest(proto.Message): [AssetService.ExportIamPolicyAnalysis][google.cloud.asset.v1p4beta1.AssetService.ExportIamPolicyAnalysis]. Attributes: - analysis_query (~.asset_service.IamPolicyAnalysisQuery): + analysis_query (google.cloud.asset_v1p4beta1.types.IamPolicyAnalysisQuery): Required. The request query. - options (~.asset_service.ExportIamPolicyAnalysisRequest.Options): + options (google.cloud.asset_v1p4beta1.types.ExportIamPolicyAnalysisRequest.Options): Optional. The request options. - output_config (~.asset_service.IamPolicyAnalysisOutputConfig): + output_config (google.cloud.asset_v1p4beta1.types.IamPolicyAnalysisOutputConfig): Required. Output configuration indicating where the results will be output to. """ @@ -447,7 +447,7 @@ class ExportIamPolicyAnalysisResponse(proto.Message): returned [google.longrunning.Operation.response][] field. Attributes: - output_config (~.asset_service.IamPolicyAnalysisOutputConfig): + output_config (google.cloud.asset_v1p4beta1.types.IamPolicyAnalysisOutputConfig): Output configuration indicating where the results were output to. """ diff --git a/google/cloud/asset_v1p4beta1/types/assets.py b/google/cloud/asset_v1p4beta1/types/assets.py index af57f224..92609db9 100644 --- a/google/cloud/asset_v1p4beta1/types/assets.py +++ b/google/cloud/asset_v1p4beta1/types/assets.py @@ -36,14 +36,14 @@ class IamPolicyAnalysisResult(proto.Message): The full name of the resource to which the [iam_binding][google.cloud.asset.v1p4beta1.IamPolicyAnalysisResult.iam_binding] policy attaches. - iam_binding (~.policy.Binding): + iam_binding (google.iam.v1.policy_pb2.Binding): The Cloud IAM policy binding under analysis. - access_control_lists (Sequence[~.assets.IamPolicyAnalysisResult.AccessControlList]): + access_control_lists (Sequence[google.cloud.asset_v1p4beta1.types.IamPolicyAnalysisResult.AccessControlList]): The access control lists derived from the [iam_binding][google.cloud.asset.v1p4beta1.IamPolicyAnalysisResult.iam_binding] that match or potentially match resource and access selectors specified in the request. - identity_list (~.assets.IamPolicyAnalysisResult.IdentityList): + identity_list (google.cloud.asset_v1p4beta1.types.IamPolicyAnalysisResult.IdentityList): The identity list derived from members of the [iam_binding][google.cloud.asset.v1p4beta1.IamPolicyAnalysisResult.iam_binding] that match or potentially match identity selector specified @@ -60,7 +60,7 @@ class AnalysisState(proto.Message): non-critical errors in the response. Attributes: - code (~.gr_code.Code): + code (google.rpc.code_pb2.Code): The Google standard error code that best describes the state. For example: @@ -85,7 +85,7 @@ class Resource(proto.Message): full_resource_name (str): The `full resource name `__. - analysis_state (~.assets.IamPolicyAnalysisResult.AnalysisState): + analysis_state (google.cloud.asset_v1p4beta1.types.IamPolicyAnalysisResult.AnalysisState): The analysis state of this resource node. """ @@ -103,7 +103,7 @@ class Access(proto.Message): The role. permission (str): The permission. - analysis_state (~.assets.IamPolicyAnalysisResult.AnalysisState): + analysis_state (google.cloud.asset_v1p4beta1.types.IamPolicyAnalysisResult.AnalysisState): The analysis state of this access node. """ @@ -146,7 +146,7 @@ class Identity(proto.Message): - domain:google.com - allUsers - etc. - analysis_state (~.assets.IamPolicyAnalysisResult.AnalysisState): + analysis_state (google.cloud.asset_v1p4beta1.types.IamPolicyAnalysisResult.AnalysisState): The analysis state of this identity node. """ @@ -177,19 +177,19 @@ class AccessControlList(proto.Message): - AccessControlList 2: [R2, R3], [P3] Attributes: - resources (Sequence[~.assets.IamPolicyAnalysisResult.Resource]): + resources (Sequence[google.cloud.asset_v1p4beta1.types.IamPolicyAnalysisResult.Resource]): The resources that match one of the following conditions: - The resource_selector, if it is specified in request; - Otherwise, resources reachable from the policy attached resource. - accesses (Sequence[~.assets.IamPolicyAnalysisResult.Access]): + accesses (Sequence[google.cloud.asset_v1p4beta1.types.IamPolicyAnalysisResult.Access]): The accesses that match one of the following conditions: - The access_selector, if it is specified in request; - Otherwise, access specifiers reachable from the policy binding's role. - resource_edges (Sequence[~.assets.IamPolicyAnalysisResult.Edge]): + resource_edges (Sequence[google.cloud.asset_v1p4beta1.types.IamPolicyAnalysisResult.Edge]): Resource edges of the graph starting from the policy attached resource to any descendant resources. The [Edge.source_node][google.cloud.asset.v1p4beta1.IamPolicyAnalysisResult.Edge.source_node] @@ -216,14 +216,14 @@ class IdentityList(proto.Message): r""" Attributes: - identities (Sequence[~.assets.IamPolicyAnalysisResult.Identity]): + identities (Sequence[google.cloud.asset_v1p4beta1.types.IamPolicyAnalysisResult.Identity]): Only the identities that match one of the following conditions will be presented: - The identity_selector, if it is specified in request; - Otherwise, identities reachable from the policy binding's members. - group_edges (Sequence[~.assets.IamPolicyAnalysisResult.Edge]): + group_edges (Sequence[google.cloud.asset_v1p4beta1.types.IamPolicyAnalysisResult.Edge]): Group identity edges of the graph starting from the binding's group members to any node of the [identities][google.cloud.asset.v1p4beta1.IamPolicyAnalysisResult.IdentityList.identities]. diff --git a/google/cloud/asset_v1p5beta1/services/asset_service/async_client.py b/google/cloud/asset_v1p5beta1/services/asset_service/async_client.py index e5d56974..537bc1d9 100644 --- a/google/cloud/asset_v1p5beta1/services/asset_service/async_client.py +++ b/google/cloud/asset_v1p5beta1/services/asset_service/async_client.py @@ -72,7 +72,36 @@ class AssetServiceAsyncClient: AssetServiceClient.parse_common_location_path ) - from_service_account_file = AssetServiceClient.from_service_account_file + @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: + AssetServiceAsyncClient: The constructed client. + """ + return AssetServiceClient.from_service_account_info.__func__(AssetServiceAsyncClient, 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: + AssetServiceAsyncClient: The constructed client. + """ + return AssetServiceClient.from_service_account_file.__func__(AssetServiceAsyncClient, filename, *args, **kwargs) # type: ignore + from_service_account_json = from_service_account_file @property @@ -148,7 +177,7 @@ async def list_assets( paged results in response. Args: - request (:class:`~.asset_service.ListAssetsRequest`): + request (:class:`google.cloud.asset_v1p5beta1.types.ListAssetsRequest`): The request object. ListAssets request. retry (google.api_core.retry.Retry): Designation of what errors, if any, @@ -158,7 +187,7 @@ async def list_assets( sent along with the request as metadata. Returns: - ~.pagers.ListAssetsAsyncPager: + google.cloud.asset_v1p5beta1.services.asset_service.pagers.ListAssetsAsyncPager: ListAssets response. Iterating over this object will yield results and resolve additional pages @@ -180,6 +209,7 @@ async def list_assets( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=60.0, ), default_timeout=60.0, client_info=DEFAULT_CLIENT_INFO, diff --git a/google/cloud/asset_v1p5beta1/services/asset_service/client.py b/google/cloud/asset_v1p5beta1/services/asset_service/client.py index 0ba04274..64df55d1 100644 --- a/google/cloud/asset_v1p5beta1/services/asset_service/client.py +++ b/google/cloud/asset_v1p5beta1/services/asset_service/client.py @@ -109,6 +109,22 @@ def _get_default_mtls_endpoint(api_endpoint): 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: + AssetServiceClient: 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 @@ -121,7 +137,7 @@ def from_service_account_file(cls, filename: str, *args, **kwargs): kwargs: Additional arguments to pass to the constructor. Returns: - {@api.name}: The constructed client. + AssetServiceClient: The constructed client. """ credentials = service_account.Credentials.from_service_account_file(filename) kwargs["credentials"] = credentials @@ -218,10 +234,10 @@ def __init__( 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, ~.AssetServiceTransport]): The + transport (Union[str, AssetServiceTransport]): The transport to use. If set to None, a transport is chosen automatically. - client_options (client_options_lib.ClientOptions): Custom options for the + 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 @@ -257,21 +273,17 @@ def __init__( util.strtobool(os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false")) ) - ssl_credentials = None + client_cert_source_func = None is_mtls = False if use_client_cert: if client_options.client_cert_source: - import grpc # type: ignore - - cert, key = client_options.client_cert_source() - ssl_credentials = grpc.ssl_channel_credentials( - certificate_chain=cert, private_key=key - ) is_mtls = True + client_cert_source_func = client_options.client_cert_source else: - creds = SslCredentials() - is_mtls = creds.is_mtls - ssl_credentials = creds.ssl_credentials if is_mtls else None + is_mtls = mtls.has_default_client_cert_source() + client_cert_source_func = ( + mtls.default_client_cert_source() if is_mtls else None + ) # Figure out which api endpoint to use. if client_options.api_endpoint is not None: @@ -314,7 +326,7 @@ def __init__( credentials_file=client_options.credentials_file, host=api_endpoint, scopes=client_options.scopes, - ssl_channel_credentials=ssl_credentials, + client_cert_source_for_mtls=client_cert_source_func, quota_project_id=client_options.quota_project_id, client_info=client_info, ) @@ -331,7 +343,7 @@ def list_assets( paged results in response. Args: - request (:class:`~.asset_service.ListAssetsRequest`): + request (google.cloud.asset_v1p5beta1.types.ListAssetsRequest): The request object. ListAssets request. retry (google.api_core.retry.Retry): Designation of what errors, if any, @@ -341,7 +353,7 @@ def list_assets( sent along with the request as metadata. Returns: - ~.pagers.ListAssetsPager: + google.cloud.asset_v1p5beta1.services.asset_service.pagers.ListAssetsPager: ListAssets response. Iterating over this object will yield results and resolve additional pages diff --git a/google/cloud/asset_v1p5beta1/services/asset_service/pagers.py b/google/cloud/asset_v1p5beta1/services/asset_service/pagers.py index 734e01aa..ddd260b9 100644 --- a/google/cloud/asset_v1p5beta1/services/asset_service/pagers.py +++ b/google/cloud/asset_v1p5beta1/services/asset_service/pagers.py @@ -15,7 +15,16 @@ # limitations under the License. # -from typing import Any, AsyncIterable, Awaitable, Callable, Iterable, Sequence, Tuple +from typing import ( + Any, + AsyncIterable, + Awaitable, + Callable, + Iterable, + Sequence, + Tuple, + Optional, +) from google.cloud.asset_v1p5beta1.types import asset_service from google.cloud.asset_v1p5beta1.types import assets @@ -25,7 +34,7 @@ class ListAssetsPager: """A pager for iterating through ``list_assets`` requests. This class thinly wraps an initial - :class:`~.asset_service.ListAssetsResponse` object, and + :class:`google.cloud.asset_v1p5beta1.types.ListAssetsResponse` object, and provides an ``__iter__`` method to iterate through its ``assets`` field. @@ -34,7 +43,7 @@ class ListAssetsPager: through the ``assets`` field on the corresponding responses. - All the usual :class:`~.asset_service.ListAssetsResponse` + All the usual :class:`google.cloud.asset_v1p5beta1.types.ListAssetsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -52,9 +61,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.asset_service.ListAssetsRequest`): + request (google.cloud.asset_v1p5beta1.types.ListAssetsRequest): The initial request object. - response (:class:`~.asset_service.ListAssetsResponse`): + response (google.cloud.asset_v1p5beta1.types.ListAssetsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -87,7 +96,7 @@ class ListAssetsAsyncPager: """A pager for iterating through ``list_assets`` requests. This class thinly wraps an initial - :class:`~.asset_service.ListAssetsResponse` object, and + :class:`google.cloud.asset_v1p5beta1.types.ListAssetsResponse` object, and provides an ``__aiter__`` method to iterate through its ``assets`` field. @@ -96,7 +105,7 @@ class ListAssetsAsyncPager: through the ``assets`` field on the corresponding responses. - All the usual :class:`~.asset_service.ListAssetsResponse` + All the usual :class:`google.cloud.asset_v1p5beta1.types.ListAssetsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -114,9 +123,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.asset_service.ListAssetsRequest`): + request (google.cloud.asset_v1p5beta1.types.ListAssetsRequest): The initial request object. - response (:class:`~.asset_service.ListAssetsResponse`): + response (google.cloud.asset_v1p5beta1.types.ListAssetsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. diff --git a/google/cloud/asset_v1p5beta1/services/asset_service/transports/base.py b/google/cloud/asset_v1p5beta1/services/asset_service/transports/base.py index 53bdd621..0eedae11 100644 --- a/google/cloud/asset_v1p5beta1/services/asset_service/transports/base.py +++ b/google/cloud/asset_v1p5beta1/services/asset_service/transports/base.py @@ -67,10 +67,10 @@ def __init__( scope (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 + 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. """ # Save the hostname. Default to port 443 (HTTPS) if none is specified. @@ -78,6 +78,9 @@ def __init__( host += ":443" self._host = host + # Save the scopes. + self._scopes = scopes or self.AUTH_SCOPES + # If no credentials are provided, then determine the appropriate # defaults. if credentials and credentials_file: @@ -87,20 +90,17 @@ def __init__( if credentials_file is not None: credentials, _ = auth.load_credentials_from_file( - credentials_file, scopes=scopes, quota_project_id=quota_project_id + credentials_file, scopes=self._scopes, quota_project_id=quota_project_id ) elif credentials is None: credentials, _ = auth.default( - scopes=scopes, quota_project_id=quota_project_id + scopes=self._scopes, quota_project_id=quota_project_id ) # Save the credentials. self._credentials = credentials - # Lifted into its own function so it can be stubbed out during tests. - self._prep_wrapped_messages(client_info) - def _prep_wrapped_messages(self, client_info): # Precompute the wrapped methods. self._wrapped_methods = { @@ -113,6 +113,7 @@ def _prep_wrapped_messages(self, client_info): predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=60.0, ), default_timeout=60.0, client_info=client_info, diff --git a/google/cloud/asset_v1p5beta1/services/asset_service/transports/grpc.py b/google/cloud/asset_v1p5beta1/services/asset_service/transports/grpc.py index 85dd47c6..b135deaa 100644 --- a/google/cloud/asset_v1p5beta1/services/asset_service/transports/grpc.py +++ b/google/cloud/asset_v1p5beta1/services/asset_service/transports/grpc.py @@ -57,6 +57,7 @@ def __init__( 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, ) -> None: @@ -87,6 +88,10 @@ def __init__( ``api_mtls_endpoint`` is None. ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials for 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 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): @@ -101,72 +106,60 @@ def __init__( google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` and ``credentials_file`` are passed. """ + self._grpc_channel = None self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} + + if api_mtls_endpoint: + warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning) + if client_cert_source: + warnings.warn("client_cert_source is deprecated", DeprecationWarning) if channel: - # Sanity check: Ensure that channel and credentials are not both - # provided. + # 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 - elif api_mtls_endpoint: - warnings.warn( - "api_mtls_endpoint and client_cert_source are deprecated", - DeprecationWarning, - ) - - host = ( - api_mtls_endpoint - if ":" in api_mtls_endpoint - else api_mtls_endpoint + ":443" - ) - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) + 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 - # Create SSL credentials with client_cert_source or application - # default SSL credentials. - if client_cert_source: - cert, key = client_cert_source() - ssl_credentials = grpc.ssl_channel_credentials( - certificate_chain=cert, private_key=key - ) else: - ssl_credentials = SslCredentials().ssl_credentials - - # create a new channel. The provided one is ignored. - self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, - credentials_file=credentials_file, - ssl_credentials=ssl_credentials, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - options=[ - ("grpc.max_send_message_length", -1), - ("grpc.max_receive_message_length", -1), - ], - ) - self._ssl_channel_credentials = ssl_credentials - else: - host = host if ":" in host else host + ":443" + 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 + ) - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) + # 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, + ) - # create a new channel. The provided one is ignored. + if not self._grpc_channel: self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, + self._host, + credentials=self._credentials, credentials_file=credentials_file, - ssl_credentials=ssl_channel_credentials, - scopes=scopes or self.AUTH_SCOPES, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, quota_project_id=quota_project_id, options=[ ("grpc.max_send_message_length", -1), @@ -174,17 +167,8 @@ def __init__( ], ) - self._stubs = {} # type: Dict[str, Callable] - - # Run the base constructor. - super().__init__( - host=host, - credentials=credentials, - credentials_file=credentials_file, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - client_info=client_info, - ) + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) @classmethod def create_channel( @@ -198,7 +182,7 @@ def create_channel( ) -> grpc.Channel: """Create and return a gRPC channel object. Args: - address (Optional[str]): The host for the channel to use. + 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 diff --git a/google/cloud/asset_v1p5beta1/services/asset_service/transports/grpc_asyncio.py b/google/cloud/asset_v1p5beta1/services/asset_service/transports/grpc_asyncio.py index 5c2586db..2df9b35f 100644 --- a/google/cloud/asset_v1p5beta1/services/asset_service/transports/grpc_asyncio.py +++ b/google/cloud/asset_v1p5beta1/services/asset_service/transports/grpc_asyncio.py @@ -61,7 +61,7 @@ def create_channel( ) -> aio.Channel: """Create and return a gRPC AsyncIO channel object. Args: - address (Optional[str]): The host for the channel to use. + 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 @@ -101,6 +101,7 @@ def __init__( 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, ) -> None: @@ -132,12 +133,16 @@ def __init__( ``api_mtls_endpoint`` is None. ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials for 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 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 + 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: @@ -146,72 +151,60 @@ def __init__( google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` and ``credentials_file`` are passed. """ + self._grpc_channel = None self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} + + if api_mtls_endpoint: + warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning) + if client_cert_source: + warnings.warn("client_cert_source is deprecated", DeprecationWarning) if channel: - # Sanity check: Ensure that channel and credentials are not both - # provided. + # 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 - elif api_mtls_endpoint: - warnings.warn( - "api_mtls_endpoint and client_cert_source are deprecated", - DeprecationWarning, - ) - - host = ( - api_mtls_endpoint - if ":" in api_mtls_endpoint - else api_mtls_endpoint + ":443" - ) - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) + 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 - # Create SSL credentials with client_cert_source or application - # default SSL credentials. - if client_cert_source: - cert, key = client_cert_source() - ssl_credentials = grpc.ssl_channel_credentials( - certificate_chain=cert, private_key=key - ) else: - ssl_credentials = SslCredentials().ssl_credentials - - # create a new channel. The provided one is ignored. - self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, - credentials_file=credentials_file, - ssl_credentials=ssl_credentials, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - options=[ - ("grpc.max_send_message_length", -1), - ("grpc.max_receive_message_length", -1), - ], - ) - self._ssl_channel_credentials = ssl_credentials - else: - host = host if ":" in host else host + ":443" + 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 + ) - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) + # 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, + ) - # create a new channel. The provided one is ignored. + if not self._grpc_channel: self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, + self._host, + credentials=self._credentials, credentials_file=credentials_file, - ssl_credentials=ssl_channel_credentials, - scopes=scopes or self.AUTH_SCOPES, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, quota_project_id=quota_project_id, options=[ ("grpc.max_send_message_length", -1), @@ -219,17 +212,8 @@ def __init__( ], ) - # Run the base constructor. - super().__init__( - host=host, - credentials=credentials, - credentials_file=credentials_file, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - client_info=client_info, - ) - - self._stubs = {} + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) @property def grpc_channel(self) -> aio.Channel: diff --git a/google/cloud/asset_v1p5beta1/types/__init__.py b/google/cloud/asset_v1p5beta1/types/__init__.py index c5930340..656ff62a 100644 --- a/google/cloud/asset_v1p5beta1/types/__init__.py +++ b/google/cloud/asset_v1p5beta1/types/__init__.py @@ -15,20 +15,20 @@ # limitations under the License. # -from .assets import ( - Asset, - Resource, -) from .asset_service import ( ListAssetsRequest, ListAssetsResponse, ContentType, ) +from .assets import ( + Asset, + Resource, +) __all__ = ( - "Asset", - "Resource", "ListAssetsRequest", "ListAssetsResponse", "ContentType", + "Asset", + "Resource", ) diff --git a/google/cloud/asset_v1p5beta1/types/asset_service.py b/google/cloud/asset_v1p5beta1/types/asset_service.py index 69ae1423..6dc79759 100644 --- a/google/cloud/asset_v1p5beta1/types/asset_service.py +++ b/google/cloud/asset_v1p5beta1/types/asset_service.py @@ -47,7 +47,7 @@ class ListAssetsRequest(proto.Message): (such as "organizations/123"), "projects/[project-number]" (such as "projects/my-project-id"), or "projects/[project-id]" (such as "projects/12345"). - read_time (~.timestamp.Timestamp): + read_time (google.protobuf.timestamp_pb2.Timestamp): Timestamp to take an asset snapshot. This can only be set to a timestamp between 2018-10-02 UTC (inclusive) and the current time. If not @@ -62,7 +62,7 @@ class ListAssetsRequest(proto.Message): Asset Inventory `__ for all supported asset types. - content_type (~.asset_service.ContentType): + content_type (google.cloud.asset_v1p5beta1.types.ContentType): Asset content type. If not specified, no content but the asset name will be returned. page_size (int): @@ -94,9 +94,9 @@ class ListAssetsResponse(proto.Message): r"""ListAssets response. Attributes: - read_time (~.timestamp.Timestamp): + read_time (google.protobuf.timestamp_pb2.Timestamp): Time the snapshot was taken. - assets (Sequence[~.gca_assets.Asset]): + assets (Sequence[google.cloud.asset_v1p5beta1.types.Asset]): Assets. next_page_token (str): Token to retrieve the next page of results. diff --git a/google/cloud/asset_v1p5beta1/types/assets.py b/google/cloud/asset_v1p5beta1/types/assets.py index dd32160e..8f62070c 100644 --- a/google/cloud/asset_v1p5beta1/types/assets.py +++ b/google/cloud/asset_v1p5beta1/types/assets.py @@ -45,23 +45,23 @@ class Asset(proto.Message): asset_type (str): Type of the asset. Example: "compute.googleapis.com/Disk". - resource (~.assets.Resource): + resource (google.cloud.asset_v1p5beta1.types.Resource): Representation of the resource. - iam_policy (~.policy.Policy): + iam_policy (google.iam.v1.policy_pb2.Policy): Representation of the actual Cloud IAM policy set on a cloud resource. For each resource, there must be at most one Cloud IAM policy set on it. - org_policy (Sequence[~.orgpolicy.Policy]): + org_policy (Sequence[google.cloud.orgpolicy.v1.orgpolicy_pb2.Policy]): Representation of the Cloud Organization Policy set on an asset. For each asset, there could be multiple Organization policies with different constraints. - access_policy (~.giav_access_policy.AccessPolicy): + access_policy (google.identity.accesscontextmanager.v1.access_policy_pb2.AccessPolicy): - access_level (~.giav_access_level.AccessLevel): + access_level (google.identity.accesscontextmanager.v1.access_level_pb2.AccessLevel): - service_perimeter (~.giav_service_perimeter.ServicePerimeter): + service_perimeter (google.identity.accesscontextmanager.v1.service_perimeter_pb2.ServicePerimeter): ancestors (Sequence[str]): Asset's ancestry path in Cloud Resource Manager (CRM) @@ -145,7 +145,7 @@ class Resource(proto.Message): ``"//cloudresourcemanager.googleapis.com/projects/my_project_123"``. For third-party assets, it is up to the users to define. - data (~.struct.Struct): + data (google.protobuf.struct_pb2.Struct): The content of the resource, in which some sensitive fields are scrubbed away and may not be present. diff --git a/noxfile.py b/noxfile.py index 41eeb037..6e8aafb9 100644 --- a/noxfile.py +++ b/noxfile.py @@ -18,6 +18,7 @@ from __future__ import absolute_import import os +import pathlib import shutil import nox @@ -30,6 +31,22 @@ SYSTEM_TEST_PYTHON_VERSIONS = ["3.8"] UNIT_TEST_PYTHON_VERSIONS = ["3.6", "3.7", "3.8", "3.9"] +CURRENT_DIRECTORY = pathlib.Path(__file__).parent.absolute() + +# 'docfx' is excluded since it only needs to run in 'docs-presubmit' +nox.options.sessions = [ + "unit", + "system", + "cover", + "lint", + "lint_setup_py", + "blacken", + "docs", +] + +# Error if a python version is missing +nox.options.error_on_missing_interpreters = True + @nox.session(python=DEFAULT_PYTHON_VERSION) def lint(session): @@ -70,17 +87,21 @@ def lint_setup_py(session): def default(session): # Install all test dependencies, then install this package in-place. - session.install("asyncmock", "pytest-asyncio") - session.install( - "mock", "pytest", "pytest-cov", + constraints_path = str( + CURRENT_DIRECTORY / "testing" / f"constraints-{session.python}.txt" ) - session.install("-e", ".") + session.install("asyncmock", "pytest-asyncio", "-c", constraints_path) + + session.install("mock", "pytest", "pytest-cov", "-c", constraints_path) + + session.install("-e", ".", "-c", constraints_path) # Run py.test against the unit tests. session.run( "py.test", "--quiet", + f"--junitxml=unit_{session.python}_sponge_log.xml", "--cov=google/cloud", "--cov=tests/unit", "--cov-append", @@ -101,6 +122,9 @@ def unit(session): @nox.session(python=SYSTEM_TEST_PYTHON_VERSIONS) def system(session): """Run the system test suite.""" + constraints_path = str( + CURRENT_DIRECTORY / "testing" / f"constraints-{session.python}.txt" + ) system_test_path = os.path.join("tests", "system.py") system_test_folder_path = os.path.join("tests", "system") @@ -110,6 +134,9 @@ def system(session): # Sanity check: Only run tests if the environment variable is set. if not os.environ.get("GOOGLE_APPLICATION_CREDENTIALS", ""): session.skip("Credentials must be set via environment variable") + # Install pyopenssl for mTLS testing. + if os.environ.get("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false") == "true": + session.install("pyopenssl") system_test_exists = os.path.exists(system_test_path) system_test_folder_exists = os.path.exists(system_test_folder_path) @@ -122,16 +149,26 @@ def system(session): # Install all test dependencies, then install this package into the # virtualenv's dist-packages. - session.install( - "mock", "pytest", "google-cloud-testutils", - ) - session.install("-e", ".") + session.install("mock", "pytest", "google-cloud-testutils", "-c", constraints_path) + session.install("-e", ".", "-c", constraints_path) # Run py.test against the system tests. if system_test_exists: - session.run("py.test", "--quiet", system_test_path, *session.posargs) + session.run( + "py.test", + "--quiet", + f"--junitxml=system_{session.python}_sponge_log.xml", + system_test_path, + *session.posargs, + ) if system_test_folder_exists: - session.run("py.test", "--quiet", system_test_folder_path, *session.posargs) + session.run( + "py.test", + "--quiet", + f"--junitxml=system_{session.python}_sponge_log.xml", + system_test_folder_path, + *session.posargs, + ) @nox.session(python=DEFAULT_PYTHON_VERSION) @@ -142,7 +179,7 @@ def cover(session): test runs (not system test runs), and then erases coverage data. """ session.install("coverage", "pytest-cov") - session.run("coverage", "report", "--show-missing", "--fail-under=99") + session.run("coverage", "report", "--show-missing", "--fail-under=98") session.run("coverage", "erase") @@ -174,9 +211,7 @@ def docfx(session): """Build the docfx yaml files for this library.""" session.install("-e", ".") - # sphinx-docfx-yaml supports up to sphinx version 1.5.5. - # https://github.com/docascode/sphinx-docfx-yaml/issues/97 - session.install("sphinx==1.5.5", "alabaster", "recommonmark", "sphinx-docfx-yaml") + session.install("sphinx", "alabaster", "recommonmark", "gcp-sphinx-docfx-yaml") shutil.rmtree(os.path.join("docs", "_build"), ignore_errors=True) session.run( diff --git a/renovate.json b/renovate.json index 4fa94931..f08bc22c 100644 --- a/renovate.json +++ b/renovate.json @@ -1,5 +1,6 @@ { "extends": [ "config:base", ":preserveSemverRanges" - ] + ], + "ignorePaths": [".pre-commit-config.yaml"] } diff --git a/samples/snippets/noxfile.py b/samples/snippets/noxfile.py index bca0522e..97bf7da8 100644 --- a/samples/snippets/noxfile.py +++ b/samples/snippets/noxfile.py @@ -85,7 +85,7 @@ def get_pytest_env_vars() -> Dict[str, str]: # DO NOT EDIT - automatically generated. # All versions used to tested samples. -ALL_VERSIONS = ["2.7", "3.6", "3.7", "3.8"] +ALL_VERSIONS = ["2.7", "3.6", "3.7", "3.8", "3.9"] # Any default versions that should be ignored. IGNORED_VERSIONS = TEST_CONFIG['ignored_versions'] diff --git a/setup.py b/setup.py index a7881597..9bf1e02f 100644 --- a/setup.py +++ b/setup.py @@ -28,15 +28,16 @@ # 'Development Status :: 5 - Production/Stable' release_status = "Development Status :: 5 - Production/Stable" dependencies = [ - "google-api-core[grpc] >= 1.22.0, < 2.0.0dev", + "google-api-core[grpc] >= 1.22.2, < 2.0.0dev", "grpc-google-iam-v1 >= 0.12.3, < 0.13dev", "google-cloud-access-context-manager >= 0.1.2, < 0.2.0dev", "google-cloud-org-policy>=0.1.2, <0.2.1", "google-cloud-os-config >= 1.0.0, <2.0.0dev", - "proto-plus >= 0.4.0", - "libcst >= 0.2.5", + "proto-plus >= 1.10.0", ] +extras = {"libcst": "libcst >= 0.2.5"} + # Setup boilerplate below this line. package_root = os.path.abspath(os.path.dirname(__file__)) @@ -83,6 +84,7 @@ packages=packages, namespace_packages=namespaces, install_requires=dependencies, + extras_requires=extras, python_requires=">=3.6", scripts=[ "scripts/fixup_asset_v1_keywords.py", diff --git a/synth.metadata b/synth.metadata index 3364ddad..766f2998 100644 --- a/synth.metadata +++ b/synth.metadata @@ -3,30 +3,30 @@ { "git": { "name": ".", - "remote": "https://github.com/googleapis/python-asset.git", - "sha": "8a517bf0c4fc6f58dd6f56c87494c2ffd3bfe5e1" + "remote": "git@github.com:googleapis/python-asset.git", + "sha": "692651851404499c8e62fc2859b967b5558e7e0d" } }, { "git": { "name": "googleapis", "remote": "https://github.com/googleapis/googleapis.git", - "sha": "bfdb1df3876564228c43c3ea64edf5f90d10d92f", - "internalRef": "348500610" + "sha": "56fc6d43fed71188d7e18f3ca003544646c4ab35", + "internalRef": "366346972" } }, { "git": { "name": "synthtool", "remote": "https://github.com/googleapis/synthtool.git", - "sha": "41a4e56982620d3edcf110d76f4fcdfdec471ac8" + "sha": "ff39353f34a36e7643b86e97724e4027ab466dc6" } }, { "git": { "name": "synthtool", "remote": "https://github.com/googleapis/synthtool.git", - "sha": "41a4e56982620d3edcf110d76f4fcdfdec471ac8" + "sha": "ff39353f34a36e7643b86e97724e4027ab466dc6" } } ], @@ -76,170 +76,5 @@ "generator": "bazel" } } - ], - "generatedFiles": [ - ".flake8", - ".github/CONTRIBUTING.md", - ".github/ISSUE_TEMPLATE/bug_report.md", - ".github/ISSUE_TEMPLATE/feature_request.md", - ".github/ISSUE_TEMPLATE/support_request.md", - ".github/PULL_REQUEST_TEMPLATE.md", - ".github/release-please.yml", - ".github/snippet-bot.yml", - ".gitignore", - ".kokoro/build.sh", - ".kokoro/continuous/common.cfg", - ".kokoro/continuous/continuous.cfg", - ".kokoro/docker/docs/Dockerfile", - ".kokoro/docker/docs/fetch_gpg_keys.sh", - ".kokoro/docs/common.cfg", - ".kokoro/docs/docs-presubmit.cfg", - ".kokoro/docs/docs.cfg", - ".kokoro/populate-secrets.sh", - ".kokoro/presubmit/common.cfg", - ".kokoro/presubmit/presubmit.cfg", - ".kokoro/publish-docs.sh", - ".kokoro/release.sh", - ".kokoro/release/common.cfg", - ".kokoro/release/release.cfg", - ".kokoro/samples/lint/common.cfg", - ".kokoro/samples/lint/continuous.cfg", - ".kokoro/samples/lint/periodic.cfg", - ".kokoro/samples/lint/presubmit.cfg", - ".kokoro/samples/python3.6/common.cfg", - ".kokoro/samples/python3.6/continuous.cfg", - ".kokoro/samples/python3.6/periodic.cfg", - ".kokoro/samples/python3.6/presubmit.cfg", - ".kokoro/samples/python3.7/common.cfg", - ".kokoro/samples/python3.7/continuous.cfg", - ".kokoro/samples/python3.7/periodic.cfg", - ".kokoro/samples/python3.7/presubmit.cfg", - ".kokoro/samples/python3.8/common.cfg", - ".kokoro/samples/python3.8/continuous.cfg", - ".kokoro/samples/python3.8/periodic.cfg", - ".kokoro/samples/python3.8/presubmit.cfg", - ".kokoro/test-samples.sh", - ".kokoro/trampoline.sh", - ".kokoro/trampoline_v2.sh", - ".pre-commit-config.yaml", - ".trampolinerc", - "CODE_OF_CONDUCT.md", - "CONTRIBUTING.rst", - "LICENSE", - "MANIFEST.in", - "docs/_static/custom.css", - "docs/_templates/layout.html", - "docs/asset_v1/services.rst", - "docs/asset_v1/types.rst", - "docs/asset_v1p1beta1/services.rst", - "docs/asset_v1p1beta1/types.rst", - "docs/asset_v1p2beta1/services.rst", - "docs/asset_v1p2beta1/types.rst", - "docs/asset_v1p4beta1/services.rst", - "docs/asset_v1p4beta1/types.rst", - "docs/asset_v1p5beta1/services.rst", - "docs/asset_v1p5beta1/types.rst", - "docs/conf.py", - "docs/multiprocessing.rst", - "google/cloud/asset/__init__.py", - "google/cloud/asset/py.typed", - "google/cloud/asset_v1/__init__.py", - "google/cloud/asset_v1/py.typed", - "google/cloud/asset_v1/services/__init__.py", - "google/cloud/asset_v1/services/asset_service/__init__.py", - "google/cloud/asset_v1/services/asset_service/async_client.py", - "google/cloud/asset_v1/services/asset_service/client.py", - "google/cloud/asset_v1/services/asset_service/pagers.py", - "google/cloud/asset_v1/services/asset_service/transports/__init__.py", - "google/cloud/asset_v1/services/asset_service/transports/base.py", - "google/cloud/asset_v1/services/asset_service/transports/grpc.py", - "google/cloud/asset_v1/services/asset_service/transports/grpc_asyncio.py", - "google/cloud/asset_v1/types/__init__.py", - "google/cloud/asset_v1/types/asset_service.py", - "google/cloud/asset_v1/types/assets.py", - "google/cloud/asset_v1p1beta1/__init__.py", - "google/cloud/asset_v1p1beta1/py.typed", - "google/cloud/asset_v1p1beta1/services/__init__.py", - "google/cloud/asset_v1p1beta1/services/asset_service/__init__.py", - "google/cloud/asset_v1p1beta1/services/asset_service/async_client.py", - "google/cloud/asset_v1p1beta1/services/asset_service/client.py", - "google/cloud/asset_v1p1beta1/services/asset_service/pagers.py", - "google/cloud/asset_v1p1beta1/services/asset_service/transports/__init__.py", - "google/cloud/asset_v1p1beta1/services/asset_service/transports/base.py", - "google/cloud/asset_v1p1beta1/services/asset_service/transports/grpc.py", - "google/cloud/asset_v1p1beta1/services/asset_service/transports/grpc_asyncio.py", - "google/cloud/asset_v1p1beta1/types/__init__.py", - "google/cloud/asset_v1p1beta1/types/asset_service.py", - "google/cloud/asset_v1p1beta1/types/assets.py", - "google/cloud/asset_v1p2beta1/__init__.py", - "google/cloud/asset_v1p2beta1/py.typed", - "google/cloud/asset_v1p2beta1/services/__init__.py", - "google/cloud/asset_v1p2beta1/services/asset_service/__init__.py", - "google/cloud/asset_v1p2beta1/services/asset_service/async_client.py", - "google/cloud/asset_v1p2beta1/services/asset_service/client.py", - "google/cloud/asset_v1p2beta1/services/asset_service/transports/__init__.py", - "google/cloud/asset_v1p2beta1/services/asset_service/transports/base.py", - "google/cloud/asset_v1p2beta1/services/asset_service/transports/grpc.py", - "google/cloud/asset_v1p2beta1/services/asset_service/transports/grpc_asyncio.py", - "google/cloud/asset_v1p2beta1/types/__init__.py", - "google/cloud/asset_v1p2beta1/types/asset_service.py", - "google/cloud/asset_v1p2beta1/types/assets.py", - "google/cloud/asset_v1p4beta1/__init__.py", - "google/cloud/asset_v1p4beta1/py.typed", - "google/cloud/asset_v1p4beta1/services/__init__.py", - "google/cloud/asset_v1p4beta1/services/asset_service/__init__.py", - "google/cloud/asset_v1p4beta1/services/asset_service/async_client.py", - "google/cloud/asset_v1p4beta1/services/asset_service/client.py", - "google/cloud/asset_v1p4beta1/services/asset_service/transports/__init__.py", - "google/cloud/asset_v1p4beta1/services/asset_service/transports/base.py", - "google/cloud/asset_v1p4beta1/services/asset_service/transports/grpc.py", - "google/cloud/asset_v1p4beta1/services/asset_service/transports/grpc_asyncio.py", - "google/cloud/asset_v1p4beta1/types/__init__.py", - "google/cloud/asset_v1p4beta1/types/asset_service.py", - "google/cloud/asset_v1p4beta1/types/assets.py", - "google/cloud/asset_v1p5beta1/__init__.py", - "google/cloud/asset_v1p5beta1/py.typed", - "google/cloud/asset_v1p5beta1/services/__init__.py", - "google/cloud/asset_v1p5beta1/services/asset_service/__init__.py", - "google/cloud/asset_v1p5beta1/services/asset_service/async_client.py", - "google/cloud/asset_v1p5beta1/services/asset_service/client.py", - "google/cloud/asset_v1p5beta1/services/asset_service/pagers.py", - "google/cloud/asset_v1p5beta1/services/asset_service/transports/__init__.py", - "google/cloud/asset_v1p5beta1/services/asset_service/transports/base.py", - "google/cloud/asset_v1p5beta1/services/asset_service/transports/grpc.py", - "google/cloud/asset_v1p5beta1/services/asset_service/transports/grpc_asyncio.py", - "google/cloud/asset_v1p5beta1/types/__init__.py", - "google/cloud/asset_v1p5beta1/types/asset_service.py", - "google/cloud/asset_v1p5beta1/types/assets.py", - "mypy.ini", - "noxfile.py", - "renovate.json", - "samples/AUTHORING_GUIDE.md", - "samples/CONTRIBUTING.md", - "samples/snippets/noxfile.py", - "scripts/decrypt-secrets.sh", - "scripts/fixup_asset_v1_keywords.py", - "scripts/fixup_asset_v1p1beta1_keywords.py", - "scripts/fixup_asset_v1p2beta1_keywords.py", - "scripts/fixup_asset_v1p4beta1_keywords.py", - "scripts/fixup_asset_v1p5beta1_keywords.py", - "scripts/readme-gen/readme_gen.py", - "scripts/readme-gen/templates/README.tmpl.rst", - "scripts/readme-gen/templates/auth.tmpl.rst", - "scripts/readme-gen/templates/auth_api_key.tmpl.rst", - "scripts/readme-gen/templates/install_deps.tmpl.rst", - "scripts/readme-gen/templates/install_portaudio.tmpl.rst", - "setup.cfg", - "testing/.gitignore", - "tests/unit/gapic/asset_v1/__init__.py", - "tests/unit/gapic/asset_v1/test_asset_service.py", - "tests/unit/gapic/asset_v1p1beta1/__init__.py", - "tests/unit/gapic/asset_v1p1beta1/test_asset_service.py", - "tests/unit/gapic/asset_v1p2beta1/__init__.py", - "tests/unit/gapic/asset_v1p2beta1/test_asset_service.py", - "tests/unit/gapic/asset_v1p4beta1/__init__.py", - "tests/unit/gapic/asset_v1p4beta1/test_asset_service.py", - "tests/unit/gapic/asset_v1p5beta1/__init__.py", - "tests/unit/gapic/asset_v1p5beta1/test_asset_service.py" ] } \ No newline at end of file diff --git a/synth.py b/synth.py index 091a879c..10a4b93f 100644 --- a/synth.py +++ b/synth.py @@ -78,7 +78,7 @@ def parse_asset_path.*?@staticmethod""", templated_files = common.py_library( samples=True, # set to True only if there are samples microgenerator=True, - cov_level=99, + cov_level=98, ) s.move(templated_files, excludes=[".coveragerc"]) # microgenerator has a good .coveragerc file diff --git a/testing/constraints-3.6.txt b/testing/constraints-3.6.txt index 6517c409..206057ed 100644 --- a/testing/constraints-3.6.txt +++ b/testing/constraints-3.6.txt @@ -5,10 +5,10 @@ # # e.g., if setup.py has "foo >= 1.14.0, < 2.0.0dev", # Then this file should have foo==1.14.0 -google-api-core==1.22.0 +google-api-core==1.22.2 grpc-google-iam-v1==0.12.3 google-cloud-access-context-manager==0.1.2 google-cloud-org-policy==0.1.2 google-cloud-os-config==1.0.0 -proto-plus==0.4.0 -libcst==0.2.5 \ No newline at end of file +proto-plus==1.10.0 +libcst==0.2.5 diff --git a/tests/unit/gapic/asset_v1/__init__.py b/tests/unit/gapic/asset_v1/__init__.py index 8b137891..42ffdf2b 100644 --- a/tests/unit/gapic/asset_v1/__init__.py +++ b/tests/unit/gapic/asset_v1/__init__.py @@ -1 +1,16 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# diff --git a/tests/unit/gapic/asset_v1/test_asset_service.py b/tests/unit/gapic/asset_v1/test_asset_service.py index 69785f09..ed73b1f9 100644 --- a/tests/unit/gapic/asset_v1/test_asset_service.py +++ b/tests/unit/gapic/asset_v1/test_asset_service.py @@ -90,7 +90,22 @@ def test__get_default_mtls_endpoint(): assert AssetServiceClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi -@pytest.mark.parametrize("client_class", [AssetServiceClient, AssetServiceAsyncClient]) +@pytest.mark.parametrize("client_class", [AssetServiceClient, AssetServiceAsyncClient,]) +def test_asset_service_client_from_service_account_info(client_class): + creds = 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) + assert client.transport._credentials == creds + assert isinstance(client, client_class) + + assert client.transport._host == "cloudasset.googleapis.com:443" + + +@pytest.mark.parametrize("client_class", [AssetServiceClient, AssetServiceAsyncClient,]) def test_asset_service_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() with mock.patch.object( @@ -99,16 +114,21 @@ def test_asset_service_client_from_service_account_file(client_class): factory.return_value = creds client = client_class.from_service_account_file("dummy/file/path.json") assert client.transport._credentials == creds + assert isinstance(client, client_class) client = client_class.from_service_account_json("dummy/file/path.json") assert client.transport._credentials == creds + assert isinstance(client, client_class) assert client.transport._host == "cloudasset.googleapis.com:443" def test_asset_service_client_get_transport_class(): transport = AssetServiceClient.get_transport_class() - assert transport == transports.AssetServiceGrpcTransport + available_transports = [ + transports.AssetServiceGrpcTransport, + ] + assert transport in available_transports transport = AssetServiceClient.get_transport_class("grpc") assert transport == transports.AssetServiceGrpcTransport @@ -157,7 +177,7 @@ def test_asset_service_client_client_options( credentials_file=None, host="squid.clam.whelk", scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -173,7 +193,7 @@ def test_asset_service_client_client_options( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -189,7 +209,7 @@ def test_asset_service_client_client_options( credentials_file=None, host=client.DEFAULT_MTLS_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -217,7 +237,7 @@ def test_asset_service_client_client_options( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id="octopus", client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -266,29 +286,25 @@ def test_asset_service_client_mtls_env_auto( client_cert_source=client_cert_source_callback ) with mock.patch.object(transport_class, "__init__") as patched: - ssl_channel_creds = mock.Mock() - with mock.patch( - "grpc.ssl_channel_credentials", return_value=ssl_channel_creds - ): - patched.return_value = None - client = client_class(client_options=options) + patched.return_value = None + client = client_class(client_options=options) - if use_client_cert_env == "false": - expected_ssl_channel_creds = None - expected_host = client.DEFAULT_ENDPOINT - else: - expected_ssl_channel_creds = ssl_channel_creds - expected_host = client.DEFAULT_MTLS_ENDPOINT + 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, - ssl_channel_credentials=expected_ssl_channel_creds, - quota_project_id=None, - client_info=transports.base.DEFAULT_CLIENT_INFO, - ) + 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, + ) # Check the case ADC client cert is provided. Whether client cert is used depends on # GOOGLE_API_USE_CLIENT_CERTIFICATE value. @@ -297,66 +313,53 @@ def test_asset_service_client_mtls_env_auto( ): with mock.patch.object(transport_class, "__init__") as patched: with mock.patch( - "google.auth.transport.grpc.SslCredentials.__init__", return_value=None + "google.auth.transport.mtls.has_default_client_cert_source", + return_value=True, ): with mock.patch( - "google.auth.transport.grpc.SslCredentials.is_mtls", - new_callable=mock.PropertyMock, - ) as is_mtls_mock: - with mock.patch( - "google.auth.transport.grpc.SslCredentials.ssl_credentials", - new_callable=mock.PropertyMock, - ) as ssl_credentials_mock: - if use_client_cert_env == "false": - is_mtls_mock.return_value = False - ssl_credentials_mock.return_value = None - expected_host = client.DEFAULT_ENDPOINT - expected_ssl_channel_creds = None - else: - is_mtls_mock.return_value = True - ssl_credentials_mock.return_value = mock.Mock() - expected_host = client.DEFAULT_MTLS_ENDPOINT - expected_ssl_channel_creds = ( - ssl_credentials_mock.return_value - ) - - patched.return_value = None - client = client_class() - patched.assert_called_once_with( - credentials=None, - credentials_file=None, - host=expected_host, - scopes=None, - ssl_channel_credentials=expected_ssl_channel_creds, - quota_project_id=None, - client_info=transports.base.DEFAULT_CLIENT_INFO, - ) + "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 - # 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.grpc.SslCredentials.__init__", return_value=None - ): - with mock.patch( - "google.auth.transport.grpc.SslCredentials.is_mtls", - new_callable=mock.PropertyMock, - ) as is_mtls_mock: - is_mtls_mock.return_value = False patched.return_value = None client = client_class() patched.assert_called_once_with( credentials=None, credentials_file=None, - host=client.DEFAULT_ENDPOINT, + host=expected_host, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=expected_client_cert_source, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) + # 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() + 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, + ) + @pytest.mark.parametrize( "client_class,transport_class,transport_name", @@ -382,7 +385,7 @@ def test_asset_service_client_client_options_scopes( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=["1", "2"], - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -412,7 +415,7 @@ def test_asset_service_client_client_options_credentials_file( credentials_file="credentials.json", host=client.DEFAULT_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -429,7 +432,7 @@ def test_asset_service_client_client_options_from_dict(): credentials_file=None, host="squid.clam.whelk", scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -467,6 +470,22 @@ def test_export_assets_from_dict(): test_export_assets(request_type=dict) +def test_export_assets_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 = AssetServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.export_assets), "__call__") as call: + client.export_assets() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == asset_service.ExportAssetsRequest() + + @pytest.mark.asyncio async def test_export_assets_async( transport: str = "grpc_asyncio", request_type=asset_service.ExportAssetsRequest @@ -589,6 +608,24 @@ def test_batch_get_assets_history_from_dict(): test_batch_get_assets_history(request_type=dict) +def test_batch_get_assets_history_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 = AssetServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.batch_get_assets_history), "__call__" + ) as call: + client.batch_get_assets_history() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == asset_service.BatchGetAssetsHistoryRequest() + + @pytest.mark.asyncio async def test_batch_get_assets_history_async( transport: str = "grpc_asyncio", @@ -729,6 +766,22 @@ def test_create_feed_from_dict(): test_create_feed(request_type=dict) +def test_create_feed_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 = AssetServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.create_feed), "__call__") as call: + client.create_feed() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == asset_service.CreateFeedRequest() + + @pytest.mark.asyncio async def test_create_feed_async( transport: str = "grpc_asyncio", request_type=asset_service.CreateFeedRequest @@ -936,6 +989,22 @@ def test_get_feed_from_dict(): test_get_feed(request_type=dict) +def test_get_feed_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 = AssetServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_feed), "__call__") as call: + client.get_feed() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == asset_service.GetFeedRequest() + + @pytest.mark.asyncio async def test_get_feed_async( transport: str = "grpc_asyncio", request_type=asset_service.GetFeedRequest @@ -1132,6 +1201,22 @@ def test_list_feeds_from_dict(): test_list_feeds(request_type=dict) +def test_list_feeds_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 = AssetServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_feeds), "__call__") as call: + client.list_feeds() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == asset_service.ListFeedsRequest() + + @pytest.mark.asyncio async def test_list_feeds_async( transport: str = "grpc_asyncio", request_type=asset_service.ListFeedsRequest @@ -1332,6 +1417,22 @@ def test_update_feed_from_dict(): test_update_feed(request_type=dict) +def test_update_feed_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 = AssetServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.update_feed), "__call__") as call: + client.update_feed() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == asset_service.UpdateFeedRequest() + + @pytest.mark.asyncio async def test_update_feed_async( transport: str = "grpc_asyncio", request_type=asset_service.UpdateFeedRequest @@ -1529,6 +1630,22 @@ def test_delete_feed_from_dict(): test_delete_feed(request_type=dict) +def test_delete_feed_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 = AssetServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_feed), "__call__") as call: + client.delete_feed() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == asset_service.DeleteFeedRequest() + + @pytest.mark.asyncio async def test_delete_feed_async( transport: str = "grpc_asyncio", request_type=asset_service.DeleteFeedRequest @@ -1716,6 +1833,24 @@ def test_search_all_resources_from_dict(): test_search_all_resources(request_type=dict) +def test_search_all_resources_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 = AssetServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.search_all_resources), "__call__" + ) as call: + client.search_all_resources() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == asset_service.SearchAllResourcesRequest() + + @pytest.mark.asyncio async def test_search_all_resources_async( transport: str = "grpc_asyncio", @@ -2096,6 +2231,24 @@ def test_search_all_iam_policies_from_dict(): test_search_all_iam_policies(request_type=dict) +def test_search_all_iam_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 = AssetServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.search_all_iam_policies), "__call__" + ) as call: + client.search_all_iam_policies() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == asset_service.SearchAllIamPoliciesRequest() + + @pytest.mark.asyncio async def test_search_all_iam_policies_async( transport: str = "grpc_asyncio", @@ -2480,6 +2633,24 @@ def test_analyze_iam_policy_from_dict(): test_analyze_iam_policy(request_type=dict) +def test_analyze_iam_policy_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = AssetServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.analyze_iam_policy), "__call__" + ) as call: + client.analyze_iam_policy() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == asset_service.AnalyzeIamPolicyRequest() + + @pytest.mark.asyncio async def test_analyze_iam_policy_async( transport: str = "grpc_asyncio", request_type=asset_service.AnalyzeIamPolicyRequest @@ -2616,6 +2787,24 @@ def test_analyze_iam_policy_longrunning_from_dict(): test_analyze_iam_policy_longrunning(request_type=dict) +def test_analyze_iam_policy_longrunning_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 = AssetServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.analyze_iam_policy_longrunning), "__call__" + ) as call: + client.analyze_iam_policy_longrunning() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == asset_service.AnalyzeIamPolicyLongrunningRequest() + + @pytest.mark.asyncio async def test_analyze_iam_policy_longrunning_async( transport: str = "grpc_asyncio", @@ -2772,7 +2961,10 @@ def test_transport_get_channel(): @pytest.mark.parametrize( "transport_class", - [transports.AssetServiceGrpcTransport, transports.AssetServiceGrpcAsyncIOTransport], + [ + transports.AssetServiceGrpcTransport, + transports.AssetServiceGrpcAsyncIOTransport, + ], ) def test_transport_adc(transport_class): # Test default credentials are used if not provided. @@ -2887,6 +3079,48 @@ def test_asset_service_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [transports.AssetServiceGrpcTransport, transports.AssetServiceGrpcAsyncIOTransport], +) +def test_asset_service_grpc_transport_client_cert_source_for_mtls(transport_class): + cred = 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=("https://www.googleapis.com/auth/cloud-platform",), + ssl_credentials=mock_ssl_channel_creds, + quota_project_id=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + # Check if ssl_channel_credentials is not provided, then client_cert_source_for_mtls + # is used. + with mock.patch.object(transport_class, "create_channel", return_value=mock.Mock()): + with mock.patch("grpc.ssl_channel_credentials") as mock_ssl_cred: + transport_class( + credentials=cred, + client_cert_source_for_mtls=client_cert_source_callback, + ) + expected_cert, expected_key = client_cert_source_callback() + mock_ssl_cred.assert_called_once_with( + certificate_chain=expected_cert, private_key=expected_key + ) + + def test_asset_service_host_no_port(): client = AssetServiceClient( credentials=credentials.AnonymousCredentials(), @@ -2908,7 +3142,7 @@ def test_asset_service_host_with_port(): def test_asset_service_grpc_transport_channel(): - channel = grpc.insecure_channel("http://localhost/") + channel = grpc.secure_channel("http://localhost/", grpc.local_channel_credentials()) # Check that channel is used if provided. transport = transports.AssetServiceGrpcTransport( @@ -2920,7 +3154,7 @@ def test_asset_service_grpc_transport_channel(): def test_asset_service_grpc_asyncio_transport_channel(): - channel = aio.insecure_channel("http://localhost/") + channel = aio.secure_channel("http://localhost/", grpc.local_channel_credentials()) # Check that channel is used if provided. transport = transports.AssetServiceGrpcAsyncIOTransport( @@ -2931,6 +3165,8 @@ def test_asset_service_grpc_asyncio_transport_channel(): 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.AssetServiceGrpcTransport, transports.AssetServiceGrpcAsyncIOTransport], @@ -2940,7 +3176,7 @@ def test_asset_service_transport_channel_mtls_with_client_cert_source(transport_ "grpc.ssl_channel_credentials", autospec=True ) as grpc_ssl_channel_cred: with mock.patch.object( - transport_class, "create_channel", autospec=True + transport_class, "create_channel" ) as grpc_create_channel: mock_ssl_cred = mock.Mock() grpc_ssl_channel_cred.return_value = mock_ssl_cred @@ -2978,6 +3214,8 @@ def test_asset_service_transport_channel_mtls_with_client_cert_source(transport_ 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.AssetServiceGrpcTransport, transports.AssetServiceGrpcAsyncIOTransport], @@ -2990,7 +3228,7 @@ def test_asset_service_transport_channel_mtls_with_adc(transport_class): ssl_credentials=mock.PropertyMock(return_value=mock_ssl_cred), ): with mock.patch.object( - transport_class, "create_channel", autospec=True + transport_class, "create_channel" ) as grpc_create_channel: mock_grpc_channel = mock.Mock() grpc_create_channel.return_value = mock_grpc_channel diff --git a/tests/unit/gapic/asset_v1p1beta1/__init__.py b/tests/unit/gapic/asset_v1p1beta1/__init__.py index 8b137891..42ffdf2b 100644 --- a/tests/unit/gapic/asset_v1p1beta1/__init__.py +++ b/tests/unit/gapic/asset_v1p1beta1/__init__.py @@ -1 +1,16 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# diff --git a/tests/unit/gapic/asset_v1p1beta1/test_asset_service.py b/tests/unit/gapic/asset_v1p1beta1/test_asset_service.py index b818753e..c98df4a7 100644 --- a/tests/unit/gapic/asset_v1p1beta1/test_asset_service.py +++ b/tests/unit/gapic/asset_v1p1beta1/test_asset_service.py @@ -82,7 +82,22 @@ def test__get_default_mtls_endpoint(): assert AssetServiceClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi -@pytest.mark.parametrize("client_class", [AssetServiceClient, AssetServiceAsyncClient]) +@pytest.mark.parametrize("client_class", [AssetServiceClient, AssetServiceAsyncClient,]) +def test_asset_service_client_from_service_account_info(client_class): + creds = 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) + assert client.transport._credentials == creds + assert isinstance(client, client_class) + + assert client.transport._host == "cloudasset.googleapis.com:443" + + +@pytest.mark.parametrize("client_class", [AssetServiceClient, AssetServiceAsyncClient,]) def test_asset_service_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() with mock.patch.object( @@ -91,16 +106,21 @@ def test_asset_service_client_from_service_account_file(client_class): factory.return_value = creds client = client_class.from_service_account_file("dummy/file/path.json") assert client.transport._credentials == creds + assert isinstance(client, client_class) client = client_class.from_service_account_json("dummy/file/path.json") assert client.transport._credentials == creds + assert isinstance(client, client_class) assert client.transport._host == "cloudasset.googleapis.com:443" def test_asset_service_client_get_transport_class(): transport = AssetServiceClient.get_transport_class() - assert transport == transports.AssetServiceGrpcTransport + available_transports = [ + transports.AssetServiceGrpcTransport, + ] + assert transport in available_transports transport = AssetServiceClient.get_transport_class("grpc") assert transport == transports.AssetServiceGrpcTransport @@ -149,7 +169,7 @@ def test_asset_service_client_client_options( credentials_file=None, host="squid.clam.whelk", scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -165,7 +185,7 @@ def test_asset_service_client_client_options( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -181,7 +201,7 @@ def test_asset_service_client_client_options( credentials_file=None, host=client.DEFAULT_MTLS_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -209,7 +229,7 @@ def test_asset_service_client_client_options( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id="octopus", client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -258,29 +278,25 @@ def test_asset_service_client_mtls_env_auto( client_cert_source=client_cert_source_callback ) with mock.patch.object(transport_class, "__init__") as patched: - ssl_channel_creds = mock.Mock() - with mock.patch( - "grpc.ssl_channel_credentials", return_value=ssl_channel_creds - ): - patched.return_value = None - client = client_class(client_options=options) + patched.return_value = None + client = client_class(client_options=options) - if use_client_cert_env == "false": - expected_ssl_channel_creds = None - expected_host = client.DEFAULT_ENDPOINT - else: - expected_ssl_channel_creds = ssl_channel_creds - expected_host = client.DEFAULT_MTLS_ENDPOINT + 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, - ssl_channel_credentials=expected_ssl_channel_creds, - quota_project_id=None, - client_info=transports.base.DEFAULT_CLIENT_INFO, - ) + 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, + ) # Check the case ADC client cert is provided. Whether client cert is used depends on # GOOGLE_API_USE_CLIENT_CERTIFICATE value. @@ -289,66 +305,53 @@ def test_asset_service_client_mtls_env_auto( ): with mock.patch.object(transport_class, "__init__") as patched: with mock.patch( - "google.auth.transport.grpc.SslCredentials.__init__", return_value=None + "google.auth.transport.mtls.has_default_client_cert_source", + return_value=True, ): with mock.patch( - "google.auth.transport.grpc.SslCredentials.is_mtls", - new_callable=mock.PropertyMock, - ) as is_mtls_mock: - with mock.patch( - "google.auth.transport.grpc.SslCredentials.ssl_credentials", - new_callable=mock.PropertyMock, - ) as ssl_credentials_mock: - if use_client_cert_env == "false": - is_mtls_mock.return_value = False - ssl_credentials_mock.return_value = None - expected_host = client.DEFAULT_ENDPOINT - expected_ssl_channel_creds = None - else: - is_mtls_mock.return_value = True - ssl_credentials_mock.return_value = mock.Mock() - expected_host = client.DEFAULT_MTLS_ENDPOINT - expected_ssl_channel_creds = ( - ssl_credentials_mock.return_value - ) - - patched.return_value = None - client = client_class() - patched.assert_called_once_with( - credentials=None, - credentials_file=None, - host=expected_host, - scopes=None, - ssl_channel_credentials=expected_ssl_channel_creds, - quota_project_id=None, - client_info=transports.base.DEFAULT_CLIENT_INFO, - ) + "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 - # 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.grpc.SslCredentials.__init__", return_value=None - ): - with mock.patch( - "google.auth.transport.grpc.SslCredentials.is_mtls", - new_callable=mock.PropertyMock, - ) as is_mtls_mock: - is_mtls_mock.return_value = False patched.return_value = None client = client_class() patched.assert_called_once_with( credentials=None, credentials_file=None, - host=client.DEFAULT_ENDPOINT, + host=expected_host, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=expected_client_cert_source, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) + # 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() + 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, + ) + @pytest.mark.parametrize( "client_class,transport_class,transport_name", @@ -374,7 +377,7 @@ def test_asset_service_client_client_options_scopes( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=["1", "2"], - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -404,7 +407,7 @@ def test_asset_service_client_client_options_credentials_file( credentials_file="credentials.json", host=client.DEFAULT_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -421,7 +424,7 @@ def test_asset_service_client_client_options_from_dict(): credentials_file=None, host="squid.clam.whelk", scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -466,6 +469,24 @@ def test_search_all_resources_from_dict(): test_search_all_resources(request_type=dict) +def test_search_all_resources_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 = AssetServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.search_all_resources), "__call__" + ) as call: + client.search_all_resources() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == asset_service.SearchAllResourcesRequest() + + @pytest.mark.asyncio async def test_search_all_resources_async( transport: str = "grpc_asyncio", @@ -858,6 +879,24 @@ def test_search_all_iam_policies_from_dict(): test_search_all_iam_policies(request_type=dict) +def test_search_all_iam_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 = AssetServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.search_all_iam_policies), "__call__" + ) as call: + client.search_all_iam_policies() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == asset_service.SearchAllIamPoliciesRequest() + + @pytest.mark.asyncio async def test_search_all_iam_policies_async( transport: str = "grpc_asyncio", @@ -1261,7 +1300,10 @@ def test_transport_get_channel(): @pytest.mark.parametrize( "transport_class", - [transports.AssetServiceGrpcTransport, transports.AssetServiceGrpcAsyncIOTransport], + [ + transports.AssetServiceGrpcTransport, + transports.AssetServiceGrpcAsyncIOTransport, + ], ) def test_transport_adc(transport_class): # Test default credentials are used if not provided. @@ -1362,6 +1404,48 @@ def test_asset_service_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [transports.AssetServiceGrpcTransport, transports.AssetServiceGrpcAsyncIOTransport], +) +def test_asset_service_grpc_transport_client_cert_source_for_mtls(transport_class): + cred = 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=("https://www.googleapis.com/auth/cloud-platform",), + ssl_credentials=mock_ssl_channel_creds, + quota_project_id=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + # Check if ssl_channel_credentials is not provided, then client_cert_source_for_mtls + # is used. + with mock.patch.object(transport_class, "create_channel", return_value=mock.Mock()): + with mock.patch("grpc.ssl_channel_credentials") as mock_ssl_cred: + transport_class( + credentials=cred, + client_cert_source_for_mtls=client_cert_source_callback, + ) + expected_cert, expected_key = client_cert_source_callback() + mock_ssl_cred.assert_called_once_with( + certificate_chain=expected_cert, private_key=expected_key + ) + + def test_asset_service_host_no_port(): client = AssetServiceClient( credentials=credentials.AnonymousCredentials(), @@ -1383,7 +1467,7 @@ def test_asset_service_host_with_port(): def test_asset_service_grpc_transport_channel(): - channel = grpc.insecure_channel("http://localhost/") + channel = grpc.secure_channel("http://localhost/", grpc.local_channel_credentials()) # Check that channel is used if provided. transport = transports.AssetServiceGrpcTransport( @@ -1395,7 +1479,7 @@ def test_asset_service_grpc_transport_channel(): def test_asset_service_grpc_asyncio_transport_channel(): - channel = aio.insecure_channel("http://localhost/") + channel = aio.secure_channel("http://localhost/", grpc.local_channel_credentials()) # Check that channel is used if provided. transport = transports.AssetServiceGrpcAsyncIOTransport( @@ -1406,6 +1490,8 @@ def test_asset_service_grpc_asyncio_transport_channel(): 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.AssetServiceGrpcTransport, transports.AssetServiceGrpcAsyncIOTransport], @@ -1415,7 +1501,7 @@ def test_asset_service_transport_channel_mtls_with_client_cert_source(transport_ "grpc.ssl_channel_credentials", autospec=True ) as grpc_ssl_channel_cred: with mock.patch.object( - transport_class, "create_channel", autospec=True + transport_class, "create_channel" ) as grpc_create_channel: mock_ssl_cred = mock.Mock() grpc_ssl_channel_cred.return_value = mock_ssl_cred @@ -1453,6 +1539,8 @@ def test_asset_service_transport_channel_mtls_with_client_cert_source(transport_ 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.AssetServiceGrpcTransport, transports.AssetServiceGrpcAsyncIOTransport], @@ -1465,7 +1553,7 @@ def test_asset_service_transport_channel_mtls_with_adc(transport_class): ssl_credentials=mock.PropertyMock(return_value=mock_ssl_cred), ): with mock.patch.object( - transport_class, "create_channel", autospec=True + transport_class, "create_channel" ) as grpc_create_channel: mock_grpc_channel = mock.Mock() grpc_create_channel.return_value = mock_grpc_channel diff --git a/tests/unit/gapic/asset_v1p2beta1/__init__.py b/tests/unit/gapic/asset_v1p2beta1/__init__.py index 8b137891..42ffdf2b 100644 --- a/tests/unit/gapic/asset_v1p2beta1/__init__.py +++ b/tests/unit/gapic/asset_v1p2beta1/__init__.py @@ -1 +1,16 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# diff --git a/tests/unit/gapic/asset_v1p2beta1/test_asset_service.py b/tests/unit/gapic/asset_v1p2beta1/test_asset_service.py index 0bba0cd6..c787be79 100644 --- a/tests/unit/gapic/asset_v1p2beta1/test_asset_service.py +++ b/tests/unit/gapic/asset_v1p2beta1/test_asset_service.py @@ -81,7 +81,22 @@ def test__get_default_mtls_endpoint(): assert AssetServiceClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi -@pytest.mark.parametrize("client_class", [AssetServiceClient, AssetServiceAsyncClient]) +@pytest.mark.parametrize("client_class", [AssetServiceClient, AssetServiceAsyncClient,]) +def test_asset_service_client_from_service_account_info(client_class): + creds = 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) + assert client.transport._credentials == creds + assert isinstance(client, client_class) + + assert client.transport._host == "cloudasset.googleapis.com:443" + + +@pytest.mark.parametrize("client_class", [AssetServiceClient, AssetServiceAsyncClient,]) def test_asset_service_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() with mock.patch.object( @@ -90,16 +105,21 @@ def test_asset_service_client_from_service_account_file(client_class): factory.return_value = creds client = client_class.from_service_account_file("dummy/file/path.json") assert client.transport._credentials == creds + assert isinstance(client, client_class) client = client_class.from_service_account_json("dummy/file/path.json") assert client.transport._credentials == creds + assert isinstance(client, client_class) assert client.transport._host == "cloudasset.googleapis.com:443" def test_asset_service_client_get_transport_class(): transport = AssetServiceClient.get_transport_class() - assert transport == transports.AssetServiceGrpcTransport + available_transports = [ + transports.AssetServiceGrpcTransport, + ] + assert transport in available_transports transport = AssetServiceClient.get_transport_class("grpc") assert transport == transports.AssetServiceGrpcTransport @@ -148,7 +168,7 @@ def test_asset_service_client_client_options( credentials_file=None, host="squid.clam.whelk", scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -164,7 +184,7 @@ def test_asset_service_client_client_options( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -180,7 +200,7 @@ def test_asset_service_client_client_options( credentials_file=None, host=client.DEFAULT_MTLS_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -208,7 +228,7 @@ def test_asset_service_client_client_options( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id="octopus", client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -257,29 +277,25 @@ def test_asset_service_client_mtls_env_auto( client_cert_source=client_cert_source_callback ) with mock.patch.object(transport_class, "__init__") as patched: - ssl_channel_creds = mock.Mock() - with mock.patch( - "grpc.ssl_channel_credentials", return_value=ssl_channel_creds - ): - patched.return_value = None - client = client_class(client_options=options) + patched.return_value = None + client = client_class(client_options=options) - if use_client_cert_env == "false": - expected_ssl_channel_creds = None - expected_host = client.DEFAULT_ENDPOINT - else: - expected_ssl_channel_creds = ssl_channel_creds - expected_host = client.DEFAULT_MTLS_ENDPOINT + 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, - ssl_channel_credentials=expected_ssl_channel_creds, - quota_project_id=None, - client_info=transports.base.DEFAULT_CLIENT_INFO, - ) + 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, + ) # Check the case ADC client cert is provided. Whether client cert is used depends on # GOOGLE_API_USE_CLIENT_CERTIFICATE value. @@ -288,66 +304,53 @@ def test_asset_service_client_mtls_env_auto( ): with mock.patch.object(transport_class, "__init__") as patched: with mock.patch( - "google.auth.transport.grpc.SslCredentials.__init__", return_value=None + "google.auth.transport.mtls.has_default_client_cert_source", + return_value=True, ): with mock.patch( - "google.auth.transport.grpc.SslCredentials.is_mtls", - new_callable=mock.PropertyMock, - ) as is_mtls_mock: - with mock.patch( - "google.auth.transport.grpc.SslCredentials.ssl_credentials", - new_callable=mock.PropertyMock, - ) as ssl_credentials_mock: - if use_client_cert_env == "false": - is_mtls_mock.return_value = False - ssl_credentials_mock.return_value = None - expected_host = client.DEFAULT_ENDPOINT - expected_ssl_channel_creds = None - else: - is_mtls_mock.return_value = True - ssl_credentials_mock.return_value = mock.Mock() - expected_host = client.DEFAULT_MTLS_ENDPOINT - expected_ssl_channel_creds = ( - ssl_credentials_mock.return_value - ) - - patched.return_value = None - client = client_class() - patched.assert_called_once_with( - credentials=None, - credentials_file=None, - host=expected_host, - scopes=None, - ssl_channel_credentials=expected_ssl_channel_creds, - quota_project_id=None, - client_info=transports.base.DEFAULT_CLIENT_INFO, - ) + "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 - # 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.grpc.SslCredentials.__init__", return_value=None - ): - with mock.patch( - "google.auth.transport.grpc.SslCredentials.is_mtls", - new_callable=mock.PropertyMock, - ) as is_mtls_mock: - is_mtls_mock.return_value = False patched.return_value = None client = client_class() patched.assert_called_once_with( credentials=None, credentials_file=None, - host=client.DEFAULT_ENDPOINT, + host=expected_host, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=expected_client_cert_source, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) + # 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() + 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, + ) + @pytest.mark.parametrize( "client_class,transport_class,transport_name", @@ -373,7 +376,7 @@ def test_asset_service_client_client_options_scopes( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=["1", "2"], - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -403,7 +406,7 @@ def test_asset_service_client_client_options_credentials_file( credentials_file="credentials.json", host=client.DEFAULT_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -420,7 +423,7 @@ def test_asset_service_client_client_options_from_dict(): credentials_file=None, host="squid.clam.whelk", scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -472,6 +475,22 @@ def test_create_feed_from_dict(): test_create_feed(request_type=dict) +def test_create_feed_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 = AssetServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.create_feed), "__call__") as call: + client.create_feed() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == asset_service.CreateFeedRequest() + + @pytest.mark.asyncio async def test_create_feed_async( transport: str = "grpc_asyncio", request_type=asset_service.CreateFeedRequest @@ -679,6 +698,22 @@ def test_get_feed_from_dict(): test_get_feed(request_type=dict) +def test_get_feed_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 = AssetServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_feed), "__call__") as call: + client.get_feed() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == asset_service.GetFeedRequest() + + @pytest.mark.asyncio async def test_get_feed_async( transport: str = "grpc_asyncio", request_type=asset_service.GetFeedRequest @@ -875,6 +910,22 @@ def test_list_feeds_from_dict(): test_list_feeds(request_type=dict) +def test_list_feeds_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 = AssetServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_feeds), "__call__") as call: + client.list_feeds() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == asset_service.ListFeedsRequest() + + @pytest.mark.asyncio async def test_list_feeds_async( transport: str = "grpc_asyncio", request_type=asset_service.ListFeedsRequest @@ -1075,6 +1126,22 @@ def test_update_feed_from_dict(): test_update_feed(request_type=dict) +def test_update_feed_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 = AssetServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.update_feed), "__call__") as call: + client.update_feed() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == asset_service.UpdateFeedRequest() + + @pytest.mark.asyncio async def test_update_feed_async( transport: str = "grpc_asyncio", request_type=asset_service.UpdateFeedRequest @@ -1272,6 +1339,22 @@ def test_delete_feed_from_dict(): test_delete_feed(request_type=dict) +def test_delete_feed_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 = AssetServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_feed), "__call__") as call: + client.delete_feed() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == asset_service.DeleteFeedRequest() + + @pytest.mark.asyncio async def test_delete_feed_async( transport: str = "grpc_asyncio", request_type=asset_service.DeleteFeedRequest @@ -1476,7 +1559,10 @@ def test_transport_get_channel(): @pytest.mark.parametrize( "transport_class", - [transports.AssetServiceGrpcTransport, transports.AssetServiceGrpcAsyncIOTransport], + [ + transports.AssetServiceGrpcTransport, + transports.AssetServiceGrpcAsyncIOTransport, + ], ) def test_transport_adc(transport_class): # Test default credentials are used if not provided. @@ -1580,6 +1666,48 @@ def test_asset_service_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [transports.AssetServiceGrpcTransport, transports.AssetServiceGrpcAsyncIOTransport], +) +def test_asset_service_grpc_transport_client_cert_source_for_mtls(transport_class): + cred = 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=("https://www.googleapis.com/auth/cloud-platform",), + ssl_credentials=mock_ssl_channel_creds, + quota_project_id=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + # Check if ssl_channel_credentials is not provided, then client_cert_source_for_mtls + # is used. + with mock.patch.object(transport_class, "create_channel", return_value=mock.Mock()): + with mock.patch("grpc.ssl_channel_credentials") as mock_ssl_cred: + transport_class( + credentials=cred, + client_cert_source_for_mtls=client_cert_source_callback, + ) + expected_cert, expected_key = client_cert_source_callback() + mock_ssl_cred.assert_called_once_with( + certificate_chain=expected_cert, private_key=expected_key + ) + + def test_asset_service_host_no_port(): client = AssetServiceClient( credentials=credentials.AnonymousCredentials(), @@ -1601,7 +1729,7 @@ def test_asset_service_host_with_port(): def test_asset_service_grpc_transport_channel(): - channel = grpc.insecure_channel("http://localhost/") + channel = grpc.secure_channel("http://localhost/", grpc.local_channel_credentials()) # Check that channel is used if provided. transport = transports.AssetServiceGrpcTransport( @@ -1613,7 +1741,7 @@ def test_asset_service_grpc_transport_channel(): def test_asset_service_grpc_asyncio_transport_channel(): - channel = aio.insecure_channel("http://localhost/") + channel = aio.secure_channel("http://localhost/", grpc.local_channel_credentials()) # Check that channel is used if provided. transport = transports.AssetServiceGrpcAsyncIOTransport( @@ -1624,6 +1752,8 @@ def test_asset_service_grpc_asyncio_transport_channel(): 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.AssetServiceGrpcTransport, transports.AssetServiceGrpcAsyncIOTransport], @@ -1633,7 +1763,7 @@ def test_asset_service_transport_channel_mtls_with_client_cert_source(transport_ "grpc.ssl_channel_credentials", autospec=True ) as grpc_ssl_channel_cred: with mock.patch.object( - transport_class, "create_channel", autospec=True + transport_class, "create_channel" ) as grpc_create_channel: mock_ssl_cred = mock.Mock() grpc_ssl_channel_cred.return_value = mock_ssl_cred @@ -1671,6 +1801,8 @@ def test_asset_service_transport_channel_mtls_with_client_cert_source(transport_ 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.AssetServiceGrpcTransport, transports.AssetServiceGrpcAsyncIOTransport], @@ -1683,7 +1815,7 @@ def test_asset_service_transport_channel_mtls_with_adc(transport_class): ssl_credentials=mock.PropertyMock(return_value=mock_ssl_cred), ): with mock.patch.object( - transport_class, "create_channel", autospec=True + transport_class, "create_channel" ) as grpc_create_channel: mock_grpc_channel = mock.Mock() grpc_create_channel.return_value = mock_grpc_channel diff --git a/tests/unit/gapic/asset_v1p4beta1/__init__.py b/tests/unit/gapic/asset_v1p4beta1/__init__.py index 8b137891..42ffdf2b 100644 --- a/tests/unit/gapic/asset_v1p4beta1/__init__.py +++ b/tests/unit/gapic/asset_v1p4beta1/__init__.py @@ -1 +1,16 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# diff --git a/tests/unit/gapic/asset_v1p4beta1/test_asset_service.py b/tests/unit/gapic/asset_v1p4beta1/test_asset_service.py index abc1823f..a53b106c 100644 --- a/tests/unit/gapic/asset_v1p4beta1/test_asset_service.py +++ b/tests/unit/gapic/asset_v1p4beta1/test_asset_service.py @@ -86,7 +86,22 @@ def test__get_default_mtls_endpoint(): assert AssetServiceClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi -@pytest.mark.parametrize("client_class", [AssetServiceClient, AssetServiceAsyncClient]) +@pytest.mark.parametrize("client_class", [AssetServiceClient, AssetServiceAsyncClient,]) +def test_asset_service_client_from_service_account_info(client_class): + creds = 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) + assert client.transport._credentials == creds + assert isinstance(client, client_class) + + assert client.transport._host == "cloudasset.googleapis.com:443" + + +@pytest.mark.parametrize("client_class", [AssetServiceClient, AssetServiceAsyncClient,]) def test_asset_service_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() with mock.patch.object( @@ -95,16 +110,21 @@ def test_asset_service_client_from_service_account_file(client_class): factory.return_value = creds client = client_class.from_service_account_file("dummy/file/path.json") assert client.transport._credentials == creds + assert isinstance(client, client_class) client = client_class.from_service_account_json("dummy/file/path.json") assert client.transport._credentials == creds + assert isinstance(client, client_class) assert client.transport._host == "cloudasset.googleapis.com:443" def test_asset_service_client_get_transport_class(): transport = AssetServiceClient.get_transport_class() - assert transport == transports.AssetServiceGrpcTransport + available_transports = [ + transports.AssetServiceGrpcTransport, + ] + assert transport in available_transports transport = AssetServiceClient.get_transport_class("grpc") assert transport == transports.AssetServiceGrpcTransport @@ -153,7 +173,7 @@ def test_asset_service_client_client_options( credentials_file=None, host="squid.clam.whelk", scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -169,7 +189,7 @@ def test_asset_service_client_client_options( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -185,7 +205,7 @@ def test_asset_service_client_client_options( credentials_file=None, host=client.DEFAULT_MTLS_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -213,7 +233,7 @@ def test_asset_service_client_client_options( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id="octopus", client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -262,29 +282,25 @@ def test_asset_service_client_mtls_env_auto( client_cert_source=client_cert_source_callback ) with mock.patch.object(transport_class, "__init__") as patched: - ssl_channel_creds = mock.Mock() - with mock.patch( - "grpc.ssl_channel_credentials", return_value=ssl_channel_creds - ): - patched.return_value = None - client = client_class(client_options=options) + patched.return_value = None + client = client_class(client_options=options) - if use_client_cert_env == "false": - expected_ssl_channel_creds = None - expected_host = client.DEFAULT_ENDPOINT - else: - expected_ssl_channel_creds = ssl_channel_creds - expected_host = client.DEFAULT_MTLS_ENDPOINT + 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, - ssl_channel_credentials=expected_ssl_channel_creds, - quota_project_id=None, - client_info=transports.base.DEFAULT_CLIENT_INFO, - ) + 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, + ) # Check the case ADC client cert is provided. Whether client cert is used depends on # GOOGLE_API_USE_CLIENT_CERTIFICATE value. @@ -293,66 +309,53 @@ def test_asset_service_client_mtls_env_auto( ): with mock.patch.object(transport_class, "__init__") as patched: with mock.patch( - "google.auth.transport.grpc.SslCredentials.__init__", return_value=None + "google.auth.transport.mtls.has_default_client_cert_source", + return_value=True, ): with mock.patch( - "google.auth.transport.grpc.SslCredentials.is_mtls", - new_callable=mock.PropertyMock, - ) as is_mtls_mock: - with mock.patch( - "google.auth.transport.grpc.SslCredentials.ssl_credentials", - new_callable=mock.PropertyMock, - ) as ssl_credentials_mock: - if use_client_cert_env == "false": - is_mtls_mock.return_value = False - ssl_credentials_mock.return_value = None - expected_host = client.DEFAULT_ENDPOINT - expected_ssl_channel_creds = None - else: - is_mtls_mock.return_value = True - ssl_credentials_mock.return_value = mock.Mock() - expected_host = client.DEFAULT_MTLS_ENDPOINT - expected_ssl_channel_creds = ( - ssl_credentials_mock.return_value - ) - - patched.return_value = None - client = client_class() - patched.assert_called_once_with( - credentials=None, - credentials_file=None, - host=expected_host, - scopes=None, - ssl_channel_credentials=expected_ssl_channel_creds, - quota_project_id=None, - client_info=transports.base.DEFAULT_CLIENT_INFO, - ) + "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 - # 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.grpc.SslCredentials.__init__", return_value=None - ): - with mock.patch( - "google.auth.transport.grpc.SslCredentials.is_mtls", - new_callable=mock.PropertyMock, - ) as is_mtls_mock: - is_mtls_mock.return_value = False patched.return_value = None client = client_class() patched.assert_called_once_with( credentials=None, credentials_file=None, - host=client.DEFAULT_ENDPOINT, + host=expected_host, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=expected_client_cert_source, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) + # 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() + 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, + ) + @pytest.mark.parametrize( "client_class,transport_class,transport_name", @@ -378,7 +381,7 @@ def test_asset_service_client_client_options_scopes( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=["1", "2"], - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -408,7 +411,7 @@ def test_asset_service_client_client_options_credentials_file( credentials_file="credentials.json", host=client.DEFAULT_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -425,7 +428,7 @@ def test_asset_service_client_client_options_from_dict(): credentials_file=None, host="squid.clam.whelk", scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -468,6 +471,24 @@ def test_analyze_iam_policy_from_dict(): test_analyze_iam_policy(request_type=dict) +def test_analyze_iam_policy_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = AssetServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.analyze_iam_policy), "__call__" + ) as call: + client.analyze_iam_policy() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == asset_service.AnalyzeIamPolicyRequest() + + @pytest.mark.asyncio async def test_analyze_iam_policy_async( transport: str = "grpc_asyncio", request_type=asset_service.AnalyzeIamPolicyRequest @@ -603,6 +624,24 @@ def test_export_iam_policy_analysis_from_dict(): test_export_iam_policy_analysis(request_type=dict) +def test_export_iam_policy_analysis_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 = AssetServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.export_iam_policy_analysis), "__call__" + ) as call: + client.export_iam_policy_analysis() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == asset_service.ExportIamPolicyAnalysisRequest() + + @pytest.mark.asyncio async def test_export_iam_policy_analysis_async( transport: str = "grpc_asyncio", @@ -759,7 +798,10 @@ def test_transport_get_channel(): @pytest.mark.parametrize( "transport_class", - [transports.AssetServiceGrpcTransport, transports.AssetServiceGrpcAsyncIOTransport], + [ + transports.AssetServiceGrpcTransport, + transports.AssetServiceGrpcAsyncIOTransport, + ], ) def test_transport_adc(transport_class): # Test default credentials are used if not provided. @@ -865,6 +907,48 @@ def test_asset_service_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [transports.AssetServiceGrpcTransport, transports.AssetServiceGrpcAsyncIOTransport], +) +def test_asset_service_grpc_transport_client_cert_source_for_mtls(transport_class): + cred = 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=("https://www.googleapis.com/auth/cloud-platform",), + ssl_credentials=mock_ssl_channel_creds, + quota_project_id=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + # Check if ssl_channel_credentials is not provided, then client_cert_source_for_mtls + # is used. + with mock.patch.object(transport_class, "create_channel", return_value=mock.Mock()): + with mock.patch("grpc.ssl_channel_credentials") as mock_ssl_cred: + transport_class( + credentials=cred, + client_cert_source_for_mtls=client_cert_source_callback, + ) + expected_cert, expected_key = client_cert_source_callback() + mock_ssl_cred.assert_called_once_with( + certificate_chain=expected_cert, private_key=expected_key + ) + + def test_asset_service_host_no_port(): client = AssetServiceClient( credentials=credentials.AnonymousCredentials(), @@ -886,7 +970,7 @@ def test_asset_service_host_with_port(): def test_asset_service_grpc_transport_channel(): - channel = grpc.insecure_channel("http://localhost/") + channel = grpc.secure_channel("http://localhost/", grpc.local_channel_credentials()) # Check that channel is used if provided. transport = transports.AssetServiceGrpcTransport( @@ -898,7 +982,7 @@ def test_asset_service_grpc_transport_channel(): def test_asset_service_grpc_asyncio_transport_channel(): - channel = aio.insecure_channel("http://localhost/") + channel = aio.secure_channel("http://localhost/", grpc.local_channel_credentials()) # Check that channel is used if provided. transport = transports.AssetServiceGrpcAsyncIOTransport( @@ -909,6 +993,8 @@ def test_asset_service_grpc_asyncio_transport_channel(): 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.AssetServiceGrpcTransport, transports.AssetServiceGrpcAsyncIOTransport], @@ -918,7 +1004,7 @@ def test_asset_service_transport_channel_mtls_with_client_cert_source(transport_ "grpc.ssl_channel_credentials", autospec=True ) as grpc_ssl_channel_cred: with mock.patch.object( - transport_class, "create_channel", autospec=True + transport_class, "create_channel" ) as grpc_create_channel: mock_ssl_cred = mock.Mock() grpc_ssl_channel_cred.return_value = mock_ssl_cred @@ -956,6 +1042,8 @@ def test_asset_service_transport_channel_mtls_with_client_cert_source(transport_ 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.AssetServiceGrpcTransport, transports.AssetServiceGrpcAsyncIOTransport], @@ -968,7 +1056,7 @@ def test_asset_service_transport_channel_mtls_with_adc(transport_class): ssl_credentials=mock.PropertyMock(return_value=mock_ssl_cred), ): with mock.patch.object( - transport_class, "create_channel", autospec=True + transport_class, "create_channel" ) as grpc_create_channel: mock_grpc_channel = mock.Mock() grpc_create_channel.return_value = mock_grpc_channel diff --git a/tests/unit/gapic/asset_v1p5beta1/__init__.py b/tests/unit/gapic/asset_v1p5beta1/__init__.py index 8b137891..42ffdf2b 100644 --- a/tests/unit/gapic/asset_v1p5beta1/__init__.py +++ b/tests/unit/gapic/asset_v1p5beta1/__init__.py @@ -1 +1,16 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# diff --git a/tests/unit/gapic/asset_v1p5beta1/test_asset_service.py b/tests/unit/gapic/asset_v1p5beta1/test_asset_service.py index 37d63e8e..8d56a60f 100644 --- a/tests/unit/gapic/asset_v1p5beta1/test_asset_service.py +++ b/tests/unit/gapic/asset_v1p5beta1/test_asset_service.py @@ -83,7 +83,22 @@ def test__get_default_mtls_endpoint(): assert AssetServiceClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi -@pytest.mark.parametrize("client_class", [AssetServiceClient, AssetServiceAsyncClient]) +@pytest.mark.parametrize("client_class", [AssetServiceClient, AssetServiceAsyncClient,]) +def test_asset_service_client_from_service_account_info(client_class): + creds = 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) + assert client.transport._credentials == creds + assert isinstance(client, client_class) + + assert client.transport._host == "cloudasset.googleapis.com:443" + + +@pytest.mark.parametrize("client_class", [AssetServiceClient, AssetServiceAsyncClient,]) def test_asset_service_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() with mock.patch.object( @@ -92,16 +107,21 @@ def test_asset_service_client_from_service_account_file(client_class): factory.return_value = creds client = client_class.from_service_account_file("dummy/file/path.json") assert client.transport._credentials == creds + assert isinstance(client, client_class) client = client_class.from_service_account_json("dummy/file/path.json") assert client.transport._credentials == creds + assert isinstance(client, client_class) assert client.transport._host == "cloudasset.googleapis.com:443" def test_asset_service_client_get_transport_class(): transport = AssetServiceClient.get_transport_class() - assert transport == transports.AssetServiceGrpcTransport + available_transports = [ + transports.AssetServiceGrpcTransport, + ] + assert transport in available_transports transport = AssetServiceClient.get_transport_class("grpc") assert transport == transports.AssetServiceGrpcTransport @@ -150,7 +170,7 @@ def test_asset_service_client_client_options( credentials_file=None, host="squid.clam.whelk", scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -166,7 +186,7 @@ def test_asset_service_client_client_options( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -182,7 +202,7 @@ def test_asset_service_client_client_options( credentials_file=None, host=client.DEFAULT_MTLS_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -210,7 +230,7 @@ def test_asset_service_client_client_options( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id="octopus", client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -259,29 +279,25 @@ def test_asset_service_client_mtls_env_auto( client_cert_source=client_cert_source_callback ) with mock.patch.object(transport_class, "__init__") as patched: - ssl_channel_creds = mock.Mock() - with mock.patch( - "grpc.ssl_channel_credentials", return_value=ssl_channel_creds - ): - patched.return_value = None - client = client_class(client_options=options) + patched.return_value = None + client = client_class(client_options=options) - if use_client_cert_env == "false": - expected_ssl_channel_creds = None - expected_host = client.DEFAULT_ENDPOINT - else: - expected_ssl_channel_creds = ssl_channel_creds - expected_host = client.DEFAULT_MTLS_ENDPOINT + 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, - ssl_channel_credentials=expected_ssl_channel_creds, - quota_project_id=None, - client_info=transports.base.DEFAULT_CLIENT_INFO, - ) + 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, + ) # Check the case ADC client cert is provided. Whether client cert is used depends on # GOOGLE_API_USE_CLIENT_CERTIFICATE value. @@ -290,66 +306,53 @@ def test_asset_service_client_mtls_env_auto( ): with mock.patch.object(transport_class, "__init__") as patched: with mock.patch( - "google.auth.transport.grpc.SslCredentials.__init__", return_value=None + "google.auth.transport.mtls.has_default_client_cert_source", + return_value=True, ): with mock.patch( - "google.auth.transport.grpc.SslCredentials.is_mtls", - new_callable=mock.PropertyMock, - ) as is_mtls_mock: - with mock.patch( - "google.auth.transport.grpc.SslCredentials.ssl_credentials", - new_callable=mock.PropertyMock, - ) as ssl_credentials_mock: - if use_client_cert_env == "false": - is_mtls_mock.return_value = False - ssl_credentials_mock.return_value = None - expected_host = client.DEFAULT_ENDPOINT - expected_ssl_channel_creds = None - else: - is_mtls_mock.return_value = True - ssl_credentials_mock.return_value = mock.Mock() - expected_host = client.DEFAULT_MTLS_ENDPOINT - expected_ssl_channel_creds = ( - ssl_credentials_mock.return_value - ) - - patched.return_value = None - client = client_class() - patched.assert_called_once_with( - credentials=None, - credentials_file=None, - host=expected_host, - scopes=None, - ssl_channel_credentials=expected_ssl_channel_creds, - quota_project_id=None, - client_info=transports.base.DEFAULT_CLIENT_INFO, - ) + "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 - # 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.grpc.SslCredentials.__init__", return_value=None - ): - with mock.patch( - "google.auth.transport.grpc.SslCredentials.is_mtls", - new_callable=mock.PropertyMock, - ) as is_mtls_mock: - is_mtls_mock.return_value = False patched.return_value = None client = client_class() patched.assert_called_once_with( credentials=None, credentials_file=None, - host=client.DEFAULT_ENDPOINT, + host=expected_host, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=expected_client_cert_source, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) + # 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() + 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, + ) + @pytest.mark.parametrize( "client_class,transport_class,transport_name", @@ -375,7 +378,7 @@ def test_asset_service_client_client_options_scopes( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=["1", "2"], - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -405,7 +408,7 @@ def test_asset_service_client_client_options_credentials_file( credentials_file="credentials.json", host=client.DEFAULT_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -422,7 +425,7 @@ def test_asset_service_client_client_options_from_dict(): credentials_file=None, host="squid.clam.whelk", scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -465,6 +468,22 @@ def test_list_assets_from_dict(): test_list_assets(request_type=dict) +def test_list_assets_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 = AssetServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_assets), "__call__") as call: + client.list_assets() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == asset_service.ListAssetsRequest() + + @pytest.mark.asyncio async def test_list_assets_async( transport: str = "grpc_asyncio", request_type=asset_service.ListAssetsRequest @@ -724,7 +743,10 @@ def test_transport_get_channel(): @pytest.mark.parametrize( "transport_class", - [transports.AssetServiceGrpcTransport, transports.AssetServiceGrpcAsyncIOTransport], + [ + transports.AssetServiceGrpcTransport, + transports.AssetServiceGrpcAsyncIOTransport, + ], ) def test_transport_adc(transport_class): # Test default credentials are used if not provided. @@ -822,6 +844,48 @@ def test_asset_service_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [transports.AssetServiceGrpcTransport, transports.AssetServiceGrpcAsyncIOTransport], +) +def test_asset_service_grpc_transport_client_cert_source_for_mtls(transport_class): + cred = 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=("https://www.googleapis.com/auth/cloud-platform",), + ssl_credentials=mock_ssl_channel_creds, + quota_project_id=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + # Check if ssl_channel_credentials is not provided, then client_cert_source_for_mtls + # is used. + with mock.patch.object(transport_class, "create_channel", return_value=mock.Mock()): + with mock.patch("grpc.ssl_channel_credentials") as mock_ssl_cred: + transport_class( + credentials=cred, + client_cert_source_for_mtls=client_cert_source_callback, + ) + expected_cert, expected_key = client_cert_source_callback() + mock_ssl_cred.assert_called_once_with( + certificate_chain=expected_cert, private_key=expected_key + ) + + def test_asset_service_host_no_port(): client = AssetServiceClient( credentials=credentials.AnonymousCredentials(), @@ -843,7 +907,7 @@ def test_asset_service_host_with_port(): def test_asset_service_grpc_transport_channel(): - channel = grpc.insecure_channel("http://localhost/") + channel = grpc.secure_channel("http://localhost/", grpc.local_channel_credentials()) # Check that channel is used if provided. transport = transports.AssetServiceGrpcTransport( @@ -855,7 +919,7 @@ def test_asset_service_grpc_transport_channel(): def test_asset_service_grpc_asyncio_transport_channel(): - channel = aio.insecure_channel("http://localhost/") + channel = aio.secure_channel("http://localhost/", grpc.local_channel_credentials()) # Check that channel is used if provided. transport = transports.AssetServiceGrpcAsyncIOTransport( @@ -866,6 +930,8 @@ def test_asset_service_grpc_asyncio_transport_channel(): 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.AssetServiceGrpcTransport, transports.AssetServiceGrpcAsyncIOTransport], @@ -875,7 +941,7 @@ def test_asset_service_transport_channel_mtls_with_client_cert_source(transport_ "grpc.ssl_channel_credentials", autospec=True ) as grpc_ssl_channel_cred: with mock.patch.object( - transport_class, "create_channel", autospec=True + transport_class, "create_channel" ) as grpc_create_channel: mock_ssl_cred = mock.Mock() grpc_ssl_channel_cred.return_value = mock_ssl_cred @@ -913,6 +979,8 @@ def test_asset_service_transport_channel_mtls_with_client_cert_source(transport_ 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.AssetServiceGrpcTransport, transports.AssetServiceGrpcAsyncIOTransport], @@ -925,7 +993,7 @@ def test_asset_service_transport_channel_mtls_with_adc(transport_class): ssl_credentials=mock.PropertyMock(return_value=mock_ssl_cred), ): with mock.patch.object( - transport_class, "create_channel", autospec=True + transport_class, "create_channel" ) as grpc_create_channel: mock_grpc_channel = mock.Mock() grpc_create_channel.return_value = mock_grpc_channel