From 1e9e2c0dba40a439727644d623b30ad5f63a0602 Mon Sep 17 00:00:00 2001 From: Yoshi Automation Bot Date: Tue, 23 Mar 2021 14:22:37 -0700 Subject: [PATCH] feat: add `from_service_account_info` (#55) * chore: exclude `.nox` directories from linting The samples tests create `.nox` directories with all dependencies installed. These directories should be excluded from linting. I've tested this change locally, and it significantly speeds up linting on my machine. Source-Author: Tim Swast Source-Date: Tue Dec 22 13:04:04 2020 -0600 Source-Repo: googleapis/synthtool Source-Sha: 373861061648b5fe5e0ac4f8a38b32d639ee93e4 Source-Link: https://github.com/googleapis/synthtool/commit/373861061648b5fe5e0ac4f8a38b32d639ee93e4 * chore: upgrade gapic-generator-python to 0.39.1 feat: add 'from_service_account_info' factory to clients fix: fix sphinx identifiers PiperOrigin-RevId: 350246057 Source-Author: Google APIs Source-Date: Tue Jan 5 16:44:11 2021 -0800 Source-Repo: googleapis/googleapis Source-Sha: 520682435235d9c503983a360a2090025aa47cd1 Source-Link: https://github.com/googleapis/googleapis/commit/520682435235d9c503983a360a2090025aa47cd1 * chore: update Go generator, rules_go, and protobuf PiperOrigin-RevId: 352816749 Source-Author: Google APIs Source-Date: Wed Jan 20 10:06:23 2021 -0800 Source-Repo: googleapis/googleapis Source-Sha: ceaaf31b3d13badab7cf9d3b570f5639db5593d9 Source-Link: https://github.com/googleapis/googleapis/commit/ceaaf31b3d13badab7cf9d3b570f5639db5593d9 * chore: upgrade gapic-generator-python to 0.40.5 PiperOrigin-RevId: 354996675 Source-Author: Google APIs Source-Date: Mon Feb 1 12:11:49 2021 -0800 Source-Repo: googleapis/googleapis Source-Sha: 20712b8fe95001b312f62c6c5f33e3e3ec92cfaf Source-Link: https://github.com/googleapis/googleapis/commit/20712b8fe95001b312f62c6c5f33e3e3ec92cfaf * chore: update gapic-generator-python PiperOrigin-RevId: 355923884 Source-Author: Google APIs Source-Date: Fri Feb 5 14:04:52 2021 -0800 Source-Repo: googleapis/googleapis Source-Sha: 5e3dacee19405529b841b53797df799c2383536c Source-Link: https://github.com/googleapis/googleapis/commit/5e3dacee19405529b841b53797df799c2383536c * chore: update gapic-generator-python to 0.40.11 PiperOrigin-RevId: 359562873 Source-Author: Google APIs Source-Date: Thu Feb 25 10:52:32 2021 -0800 Source-Repo: googleapis/googleapis Source-Sha: 07932bb995e7dc91b43620ea8402c6668c7d102c Source-Link: https://github.com/googleapis/googleapis/commit/07932bb995e7dc91b43620ea8402c6668c7d102c * chore: upgrade gapic-generator-python to 0.42.2 PiperOrigin-RevId: 361662015 Source-Author: Google APIs Source-Date: Mon Mar 8 14:47:18 2021 -0800 Source-Repo: googleapis/googleapis Source-Sha: 28a591963253d52ce3a25a918cafbdd9928de8cf Source-Link: https://github.com/googleapis/googleapis/commit/28a591963253d52ce3a25a918cafbdd9928de8cf * chore(bazel): update go-genproto override chore(bazel): comment rules_go update blocker PiperOrigin-RevId: 362170887 Source-Author: Google APIs Source-Date: Wed Mar 10 16:39:08 2021 -0800 Source-Repo: googleapis/googleapis Source-Sha: 3efec25aa7e225dac913be6d759cacfe7898fa8c Source-Link: https://github.com/googleapis/googleapis/commit/3efec25aa7e225dac913be6d759cacfe7898fa8c * chore: regenerate Co-authored-by: Bu Sun Kim --- .coveragerc | 32 +- .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 +----- .trampolinerc | 1 + CONTRIBUTING.rst | 22 +- LICENSE | 7 +- MANIFEST.in | 4 +- docs/_static/custom.css | 7 +- docs/webrisk_v1/services.rst | 6 +- docs/webrisk_v1/types.rst | 1 + docs/webrisk_v1/web_risk_service.rst | 6 + docs/webrisk_v1beta1/services.rst | 6 +- docs/webrisk_v1beta1/types.rst | 1 + .../web_risk_service_v1_beta1.rst | 6 + .../services/web_risk_service/async_client.py | 69 ++++- .../services/web_risk_service/client.py | 93 +++--- .../web_risk_service/transports/base.py | 21 +- .../web_risk_service/transports/grpc.py | 112 +++---- .../transports/grpc_asyncio.py | 120 ++++---- google/cloud/webrisk_v1/types/__init__.py | 32 +- google/cloud/webrisk_v1/types/webrisk.py | 44 +-- .../web_risk_service_v1_beta1/async_client.py | 60 +++- .../web_risk_service_v1_beta1/client.py | 82 +++-- .../transports/base.py | 21 +- .../transports/grpc.py | 112 +++---- .../transports/grpc_asyncio.py | 120 ++++---- .../cloud/webrisk_v1beta1/types/__init__.py | 24 +- google/cloud/webrisk_v1beta1/types/webrisk.py | 42 +-- noxfile.py | 59 +++- renovate.json | 3 +- synth.metadata | 118 +------- tests/unit/gapic/webrisk_v1/__init__.py | 15 + .../gapic/webrisk_v1/test_web_risk_service.py | 284 +++++++++++++----- tests/unit/gapic/webrisk_v1beta1/__init__.py | 15 + .../test_web_risk_service_v1_beta1.py | 268 ++++++++++++----- webrisk-v1-py.tar.gz | 0 44 files changed, 1265 insertions(+), 863 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/webrisk_v1/web_risk_service.rst create mode 100644 docs/webrisk_v1beta1/web_risk_service_v1_beta1.rst delete mode 100644 webrisk-v1-py.tar.gz diff --git a/.coveragerc b/.coveragerc index 984d4c8..4430304 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1,36 +1,18 @@ -# -*- 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/webrisk/__init__.py exclude_lines = # Re-enable the standard pragma pragma: NO COVER # Ignore debug-only repr def __repr__ - # Ignore abstract methods - raise NotImplementedError -omit = - */gapic/*.py - */proto/*.py - */core/*.py - */site-packages/*.py - google/cloud/webrisk/__init__.py + # Ignore pkg_resources exceptions. + # This is added at the module level as a safeguard for if someone + # generates the code and tries to run it without pip installing. This + # makes it virtually impossible to test properly. + except pkg_resources.DistributionNotFound diff --git a/.github/header-checker-lint.yml b/.github/header-checker-lint.yml new file mode 100644 index 0000000..fc281c0 --- /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 b9daa52..b4243ce 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 31252e9..e0ce712 100755 --- a/.kokoro/build.sh +++ b/.kokoro/build.sh @@ -15,7 +15,11 @@ set -eo pipefail -cd github/python-webrisk +if [[ -z "${PROJECT_ROOT:-}" ]]; then + PROJECT_ROOT="github/python-webrisk" +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 1118107..299c58c 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-webrisk/.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 0000000..f9cfcd3 --- /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 0000000..f9cfcd3 --- /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 0000000..f9cfcd3 --- /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 0000000..e6534ca --- /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-webrisk + +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 0000000..cf5de74 --- /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 83e79cb..0820f12 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-webrisk # 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/.trampolinerc b/.trampolinerc index 995ee29..383b6ec 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 44e96d1..782c0d2 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/LICENSE b/LICENSE index a8ee855..d645695 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,7 @@ - Apache License + + Apache License Version 2.0, January 2004 - https://www.apache.org/licenses/ + http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION @@ -192,7 +193,7 @@ you may not use this file except in compliance with the License. You may obtain a copy of the License at - https://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, diff --git a/MANIFEST.in b/MANIFEST.in index e9e29d1..e783f4c 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/docs/_static/custom.css b/docs/_static/custom.css index 0abaf22..bcd37bb 100644 --- a/docs/_static/custom.css +++ b/docs/_static/custom.css @@ -1,4 +1,9 @@ div#python2-eol { border-color: red; border-width: medium; -} \ No newline at end of file +} + +/* Ensure minimum width for 'Parameters' / 'Returns' column */ +dl.field-list > dt { + min-width: 100px +} diff --git a/docs/webrisk_v1/services.rst b/docs/webrisk_v1/services.rst index e11c0e7..8b02d33 100644 --- a/docs/webrisk_v1/services.rst +++ b/docs/webrisk_v1/services.rst @@ -1,6 +1,6 @@ Services for Google Cloud Webrisk v1 API ======================================== +.. toctree:: + :maxdepth: 2 -.. automodule:: google.cloud.webrisk_v1.services.web_risk_service - :members: - :inherited-members: + web_risk_service diff --git a/docs/webrisk_v1/types.rst b/docs/webrisk_v1/types.rst index d5b56e6..8d742a7 100644 --- a/docs/webrisk_v1/types.rst +++ b/docs/webrisk_v1/types.rst @@ -3,4 +3,5 @@ Types for Google Cloud Webrisk v1 API .. automodule:: google.cloud.webrisk_v1.types :members: + :undoc-members: :show-inheritance: diff --git a/docs/webrisk_v1/web_risk_service.rst b/docs/webrisk_v1/web_risk_service.rst new file mode 100644 index 0000000..e67920a --- /dev/null +++ b/docs/webrisk_v1/web_risk_service.rst @@ -0,0 +1,6 @@ +WebRiskService +-------------------------------- + +.. automodule:: google.cloud.webrisk_v1.services.web_risk_service + :members: + :inherited-members: diff --git a/docs/webrisk_v1beta1/services.rst b/docs/webrisk_v1beta1/services.rst index a658fbc..19a06a3 100644 --- a/docs/webrisk_v1beta1/services.rst +++ b/docs/webrisk_v1beta1/services.rst @@ -1,6 +1,6 @@ Services for Google Cloud Webrisk v1beta1 API ============================================= +.. toctree:: + :maxdepth: 2 -.. automodule:: google.cloud.webrisk_v1beta1.services.web_risk_service_v1_beta1 - :members: - :inherited-members: + web_risk_service_v1_beta1 diff --git a/docs/webrisk_v1beta1/types.rst b/docs/webrisk_v1beta1/types.rst index d6aefb6..440fe29 100644 --- a/docs/webrisk_v1beta1/types.rst +++ b/docs/webrisk_v1beta1/types.rst @@ -3,4 +3,5 @@ Types for Google Cloud Webrisk v1beta1 API .. automodule:: google.cloud.webrisk_v1beta1.types :members: + :undoc-members: :show-inheritance: diff --git a/docs/webrisk_v1beta1/web_risk_service_v1_beta1.rst b/docs/webrisk_v1beta1/web_risk_service_v1_beta1.rst new file mode 100644 index 0000000..aea23da --- /dev/null +++ b/docs/webrisk_v1beta1/web_risk_service_v1_beta1.rst @@ -0,0 +1,6 @@ +WebRiskServiceV1Beta1 +--------------------------------------- + +.. automodule:: google.cloud.webrisk_v1beta1.services.web_risk_service_v1_beta1 + :members: + :inherited-members: diff --git a/google/cloud/webrisk_v1/services/web_risk_service/async_client.py b/google/cloud/webrisk_v1/services/web_risk_service/async_client.py index 8747552..f92fda2 100644 --- a/google/cloud/webrisk_v1/services/web_risk_service/async_client.py +++ b/google/cloud/webrisk_v1/services/web_risk_service/async_client.py @@ -75,7 +75,36 @@ class WebRiskServiceAsyncClient: WebRiskServiceClient.parse_common_location_path ) - from_service_account_file = WebRiskServiceClient.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: + WebRiskServiceAsyncClient: The constructed client. + """ + return WebRiskServiceClient.from_service_account_info.__func__(WebRiskServiceAsyncClient, 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: + WebRiskServiceAsyncClient: The constructed client. + """ + return WebRiskServiceClient.from_service_account_file.__func__(WebRiskServiceAsyncClient, filename, *args, **kwargs) # type: ignore + from_service_account_json = from_service_account_file @property @@ -160,12 +189,13 @@ async def compute_threat_list_diff( once for each list. Args: - request (:class:`~.webrisk.ComputeThreatListDiffRequest`): + request (:class:`google.cloud.webrisk_v1.types.ComputeThreatListDiffRequest`): The request object. Describes an API diff request. - threat_type (:class:`~.webrisk.ThreatType`): + threat_type (:class:`google.cloud.webrisk_v1.types.ThreatType`): Required. The threat list to update. Only a single ThreatType should be specified. + This corresponds to the ``threat_type`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -179,12 +209,14 @@ async def compute_threat_list_diff( ComputeThreatListDiff), this may be left empty and a full database snapshot will be returned. + This corresponds to the ``version_token`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - constraints (:class:`~.webrisk.ComputeThreatListDiffRequest.Constraints`): + constraints (:class:`google.cloud.webrisk_v1.types.ComputeThreatListDiffRequest.Constraints`): Required. The constraints associated with this request. + This corresponds to the ``constraints`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -196,7 +228,7 @@ async def compute_threat_list_diff( sent along with the request as metadata. Returns: - ~.webrisk.ComputeThreatListDiffResponse: + google.cloud.webrisk_v1.types.ComputeThreatListDiffResponse: """ # Create or coerce a protobuf request object. @@ -232,6 +264,7 @@ async def compute_threat_list_diff( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=600.0, ), default_timeout=600.0, client_info=DEFAULT_CLIENT_INFO, @@ -261,19 +294,21 @@ async def search_uris( response will be returned. Args: - request (:class:`~.webrisk.SearchUrisRequest`): + request (:class:`google.cloud.webrisk_v1.types.SearchUrisRequest`): The request object. Request to check URI entries against threatLists. uri (:class:`str`): Required. The URI to be checked for matches. + This corresponds to the ``uri`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - threat_types (:class:`Sequence[~.webrisk.ThreatType]`): + threat_types (:class:`Sequence[google.cloud.webrisk_v1.types.ThreatType]`): Required. The ThreatLists to search in. Multiple ThreatLists may be specified. + This corresponds to the ``threat_types`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -285,7 +320,7 @@ async def search_uris( sent along with the request as metadata. Returns: - ~.webrisk.SearchUrisResponse: + google.cloud.webrisk_v1.types.SearchUrisResponse: """ # Create or coerce a protobuf request object. @@ -320,6 +355,7 @@ async def search_uris( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=600.0, ), default_timeout=600.0, client_info=DEFAULT_CLIENT_INFO, @@ -349,7 +385,7 @@ async def search_hashes( match of a threat. Args: - request (:class:`~.webrisk.SearchHashesRequest`): + request (:class:`google.cloud.webrisk_v1.types.SearchHashesRequest`): The request object. Request to return full hashes matched by the provided hash prefixes. hash_prefix (:class:`bytes`): @@ -357,13 +393,15 @@ async def search_hashes( significant 4-32 bytes of a SHA256 hash. For JSON requests, this field is base64-encoded. + This corresponds to the ``hash_prefix`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - threat_types (:class:`Sequence[~.webrisk.ThreatType]`): + threat_types (:class:`Sequence[google.cloud.webrisk_v1.types.ThreatType]`): Required. The ThreatLists to search in. Multiple ThreatLists may be specified. + This corresponds to the ``threat_types`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -375,7 +413,7 @@ async def search_hashes( sent along with the request as metadata. Returns: - ~.webrisk.SearchHashesResponse: + google.cloud.webrisk_v1.types.SearchHashesResponse: """ # Create or coerce a protobuf request object. @@ -410,6 +448,7 @@ async def search_hashes( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=600.0, ), default_timeout=600.0, client_info=DEFAULT_CLIENT_INFO, @@ -441,20 +480,22 @@ async def create_submission( visibility can use this method. Args: - request (:class:`~.webrisk.CreateSubmissionRequest`): + request (:class:`google.cloud.webrisk_v1.types.CreateSubmissionRequest`): The request object. Request to send a potentially phishy URI to WebRisk. parent (:class:`str`): Required. The name of the project that is making the submission. This string is in the format "projects/{project_number}". + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - submission (:class:`~.webrisk.Submission`): + submission (:class:`google.cloud.webrisk_v1.types.Submission`): Required. The submission that contains the content of the phishing report. + This corresponds to the ``submission`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -466,7 +507,7 @@ async def create_submission( sent along with the request as metadata. Returns: - ~.webrisk.Submission: + google.cloud.webrisk_v1.types.Submission: Wraps a URI that might be displaying phishing content. diff --git a/google/cloud/webrisk_v1/services/web_risk_service/client.py b/google/cloud/webrisk_v1/services/web_risk_service/client.py index d5793d7..aa59210 100644 --- a/google/cloud/webrisk_v1/services/web_risk_service/client.py +++ b/google/cloud/webrisk_v1/services/web_risk_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: + WebRiskServiceClient: 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. + WebRiskServiceClient: The constructed client. """ credentials = service_account.Credentials.from_service_account_file(filename) kwargs["credentials"] = credentials @@ -216,10 +232,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, ~.WebRiskServiceTransport]): The + transport (Union[str, WebRiskServiceTransport]): 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 @@ -255,21 +271,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: @@ -312,7 +324,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, ) @@ -338,16 +350,17 @@ def compute_threat_list_diff( once for each list. Args: - request (:class:`~.webrisk.ComputeThreatListDiffRequest`): + request (google.cloud.webrisk_v1.types.ComputeThreatListDiffRequest): The request object. Describes an API diff request. - threat_type (:class:`~.webrisk.ThreatType`): + threat_type (google.cloud.webrisk_v1.types.ThreatType): Required. The threat list to update. Only a single ThreatType should be specified. + This corresponds to the ``threat_type`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - version_token (:class:`bytes`): + version_token (bytes): The current version token of the client for the requested list (the client version that was received from @@ -357,12 +370,14 @@ def compute_threat_list_diff( ComputeThreatListDiff), this may be left empty and a full database snapshot will be returned. + This corresponds to the ``version_token`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - constraints (:class:`~.webrisk.ComputeThreatListDiffRequest.Constraints`): + constraints (google.cloud.webrisk_v1.types.ComputeThreatListDiffRequest.Constraints): Required. The constraints associated with this request. + This corresponds to the ``constraints`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -374,7 +389,7 @@ def compute_threat_list_diff( sent along with the request as metadata. Returns: - ~.webrisk.ComputeThreatListDiffResponse: + google.cloud.webrisk_v1.types.ComputeThreatListDiffResponse: """ # Create or coerce a protobuf request object. @@ -432,19 +447,21 @@ def search_uris( response will be returned. Args: - request (:class:`~.webrisk.SearchUrisRequest`): + request (google.cloud.webrisk_v1.types.SearchUrisRequest): The request object. Request to check URI entries against threatLists. - uri (:class:`str`): + uri (str): Required. The URI to be checked for matches. + This corresponds to the ``uri`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - threat_types (:class:`Sequence[~.webrisk.ThreatType]`): + threat_types (Sequence[google.cloud.webrisk_v1.types.ThreatType]): Required. The ThreatLists to search in. Multiple ThreatLists may be specified. + This corresponds to the ``threat_types`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -456,7 +473,7 @@ def search_uris( sent along with the request as metadata. Returns: - ~.webrisk.SearchUrisResponse: + google.cloud.webrisk_v1.types.SearchUrisResponse: """ # Create or coerce a protobuf request object. @@ -481,9 +498,8 @@ def search_uris( if uri is not None: request.uri = uri - - if threat_types: - request.threat_types.extend(threat_types) + if threat_types is not None: + request.threat_types = threat_types # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. @@ -513,21 +529,23 @@ def search_hashes( match of a threat. Args: - request (:class:`~.webrisk.SearchHashesRequest`): + request (google.cloud.webrisk_v1.types.SearchHashesRequest): The request object. Request to return full hashes matched by the provided hash prefixes. - hash_prefix (:class:`bytes`): + hash_prefix (bytes): A hash prefix, consisting of the most significant 4-32 bytes of a SHA256 hash. For JSON requests, this field is base64-encoded. + This corresponds to the ``hash_prefix`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - threat_types (:class:`Sequence[~.webrisk.ThreatType]`): + threat_types (Sequence[google.cloud.webrisk_v1.types.ThreatType]): Required. The ThreatLists to search in. Multiple ThreatLists may be specified. + This corresponds to the ``threat_types`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -539,7 +557,7 @@ def search_hashes( sent along with the request as metadata. Returns: - ~.webrisk.SearchHashesResponse: + google.cloud.webrisk_v1.types.SearchHashesResponse: """ # Create or coerce a protobuf request object. @@ -564,9 +582,8 @@ def search_hashes( if hash_prefix is not None: request.hash_prefix = hash_prefix - - if threat_types: - request.threat_types.extend(threat_types) + if threat_types is not None: + request.threat_types = threat_types # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. @@ -598,20 +615,22 @@ def create_submission( visibility can use this method. Args: - request (:class:`~.webrisk.CreateSubmissionRequest`): + request (google.cloud.webrisk_v1.types.CreateSubmissionRequest): The request object. Request to send a potentially phishy URI to WebRisk. - parent (:class:`str`): + parent (str): Required. The name of the project that is making the submission. This string is in the format "projects/{project_number}". + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - submission (:class:`~.webrisk.Submission`): + submission (google.cloud.webrisk_v1.types.Submission): Required. The submission that contains the content of the phishing report. + This corresponds to the ``submission`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -623,7 +642,7 @@ def create_submission( sent along with the request as metadata. Returns: - ~.webrisk.Submission: + google.cloud.webrisk_v1.types.Submission: Wraps a URI that might be displaying phishing content. diff --git a/google/cloud/webrisk_v1/services/web_risk_service/transports/base.py b/google/cloud/webrisk_v1/services/web_risk_service/transports/base.py index 317ae12..537f9ac 100644 --- a/google/cloud/webrisk_v1/services/web_risk_service/transports/base.py +++ b/google/cloud/webrisk_v1/services/web_risk_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=600.0, ), default_timeout=600.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=600.0, ), default_timeout=600.0, client_info=client_info, @@ -139,6 +141,7 @@ def _prep_wrapped_messages(self, client_info): predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=600.0, ), default_timeout=600.0, client_info=client_info, diff --git a/google/cloud/webrisk_v1/services/web_risk_service/transports/grpc.py b/google/cloud/webrisk_v1/services/web_risk_service/transports/grpc.py index 536093a..203a66d 100644 --- a/google/cloud/webrisk_v1/services/web_risk_service/transports/grpc.py +++ b/google/cloud/webrisk_v1/services/web_risk_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/webrisk_v1/services/web_risk_service/transports/grpc_asyncio.py b/google/cloud/webrisk_v1/services/web_risk_service/transports/grpc_asyncio.py index 1f0b4ed..ade4db1 100644 --- a/google/cloud/webrisk_v1/services/web_risk_service/transports/grpc_asyncio.py +++ b/google/cloud/webrisk_v1/services/web_risk_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/webrisk_v1/types/__init__.py b/google/cloud/webrisk_v1/types/__init__.py index 7333db4..fcb4f1f 100644 --- a/google/cloud/webrisk_v1/types/__init__.py +++ b/google/cloud/webrisk_v1/types/__init__.py @@ -18,35 +18,35 @@ from .webrisk import ( ComputeThreatListDiffRequest, ComputeThreatListDiffResponse, - SearchUrisRequest, - SearchUrisResponse, + CreateSubmissionRequest, + RawHashes, + RawIndices, + RiceDeltaEncoding, SearchHashesRequest, SearchHashesResponse, + SearchUrisRequest, + SearchUrisResponse, + Submission, ThreatEntryAdditions, ThreatEntryRemovals, - RawIndices, - RawHashes, - RiceDeltaEncoding, - Submission, - CreateSubmissionRequest, - ThreatType, CompressionType, + ThreatType, ) __all__ = ( "ComputeThreatListDiffRequest", "ComputeThreatListDiffResponse", - "SearchUrisRequest", - "SearchUrisResponse", + "CreateSubmissionRequest", + "RawHashes", + "RawIndices", + "RiceDeltaEncoding", "SearchHashesRequest", "SearchHashesResponse", + "SearchUrisRequest", + "SearchUrisResponse", + "Submission", "ThreatEntryAdditions", "ThreatEntryRemovals", - "RawIndices", - "RawHashes", - "RiceDeltaEncoding", - "Submission", - "CreateSubmissionRequest", - "ThreatType", "CompressionType", + "ThreatType", ) diff --git a/google/cloud/webrisk_v1/types/webrisk.py b/google/cloud/webrisk_v1/types/webrisk.py index bdc7628..5efe7c3 100644 --- a/google/cloud/webrisk_v1/types/webrisk.py +++ b/google/cloud/webrisk_v1/types/webrisk.py @@ -64,7 +64,7 @@ class ComputeThreatListDiffRequest(proto.Message): r"""Describes an API diff request. Attributes: - threat_type (~.webrisk.ThreatType): + threat_type (google.cloud.webrisk_v1.types.ThreatType): Required. The threat list to update. Only a single ThreatType should be specified. version_token (bytes): @@ -75,7 +75,7 @@ class ComputeThreatListDiffRequest(proto.Message): the first time calling ComputeThreatListDiff), this may be left empty and a full database snapshot will be returned. - constraints (~.webrisk.ComputeThreatListDiffRequest.Constraints): + constraints (google.cloud.webrisk_v1.types.ComputeThreatListDiffRequest.Constraints): Required. The constraints associated with this request. """ @@ -94,7 +94,7 @@ class Constraints(proto.Message): willing to have in the local database. This should be a power of 2 between 2\ **10 and 2**\ 20. If zero, no database size limit is set. - supported_compressions (Sequence[~.webrisk.CompressionType]): + supported_compressions (Sequence[google.cloud.webrisk_v1.types.CompressionType]): The compression types supported by the client. """ @@ -118,14 +118,14 @@ class ComputeThreatListDiffResponse(proto.Message): r""" Attributes: - response_type (~.webrisk.ComputeThreatListDiffResponse.ResponseType): + response_type (google.cloud.webrisk_v1.types.ComputeThreatListDiffResponse.ResponseType): The type of response. This may indicate that an action must be taken by the client when the response is received. - additions (~.webrisk.ThreatEntryAdditions): + additions (google.cloud.webrisk_v1.types.ThreatEntryAdditions): A set of entries to add to a local threat type's list. - removals (~.webrisk.ThreatEntryRemovals): + removals (google.cloud.webrisk_v1.types.ThreatEntryRemovals): A set of entries to remove from a local threat type's list. This field may be empty. new_version_token (bytes): @@ -133,14 +133,14 @@ class ComputeThreatListDiffResponse(proto.Message): by the client and passed into the next call of ComputeThreatListDiff as 'version_token'. A separate version token should be stored and used for each threatList. - checksum (~.webrisk.ComputeThreatListDiffResponse.Checksum): + checksum (google.cloud.webrisk_v1.types.ComputeThreatListDiffResponse.Checksum): The expected SHA256 hash of the client state; that is, of the sorted list of all hashes present in the database after applying the provided diff. If the client state doesn't match the expected state, the client must discard this diff and retry later. - recommended_next_diff (~.timestamp.Timestamp): + recommended_next_diff (google.protobuf.timestamp_pb2.Timestamp): The soonest the client should wait before issuing any diff request. Querying sooner is unlikely to produce a meaningful diff. Waiting @@ -188,7 +188,7 @@ class SearchUrisRequest(proto.Message): Attributes: uri (str): Required. The URI to be checked for matches. - threat_types (Sequence[~.webrisk.ThreatType]): + threat_types (Sequence[google.cloud.webrisk_v1.types.ThreatType]): Required. The ThreatLists to search in. Multiple ThreatLists may be specified. """ @@ -202,7 +202,7 @@ class SearchUrisResponse(proto.Message): r""" Attributes: - threat (~.webrisk.SearchUrisResponse.ThreatUri): + threat (google.cloud.webrisk_v1.types.SearchUrisResponse.ThreatUri): The threat list matches. This may be empty if the URI is on no list. """ @@ -211,9 +211,9 @@ class ThreatUri(proto.Message): r"""Contains threat information on a matching uri. Attributes: - threat_types (Sequence[~.webrisk.ThreatType]): + threat_types (Sequence[google.cloud.webrisk_v1.types.ThreatType]): The ThreatList this threat belongs to. - expire_time (~.timestamp.Timestamp): + expire_time (google.protobuf.timestamp_pb2.Timestamp): The cache lifetime for the returned match. Clients must not cache this response past this timestamp to avoid false positives. @@ -235,7 +235,7 @@ class SearchHashesRequest(proto.Message): A hash prefix, consisting of the most significant 4-32 bytes of a SHA256 hash. For JSON requests, this field is base64-encoded. - threat_types (Sequence[~.webrisk.ThreatType]): + threat_types (Sequence[google.cloud.webrisk_v1.types.ThreatType]): Required. The ThreatLists to search in. Multiple ThreatLists may be specified. """ @@ -249,10 +249,10 @@ class SearchHashesResponse(proto.Message): r""" Attributes: - threats (Sequence[~.webrisk.SearchHashesResponse.ThreatHash]): + threats (Sequence[google.cloud.webrisk_v1.types.SearchHashesResponse.ThreatHash]): The full hashes that matched the requested prefixes. The hash will be populated in the key. - negative_expire_time (~.timestamp.Timestamp): + negative_expire_time (google.protobuf.timestamp_pb2.Timestamp): For requested entities that did not match the threat list, how long to cache the response until. @@ -262,14 +262,14 @@ class ThreatHash(proto.Message): r"""Contains threat information on a matching hash. Attributes: - threat_types (Sequence[~.webrisk.ThreatType]): + threat_types (Sequence[google.cloud.webrisk_v1.types.ThreatType]): The ThreatList this threat belongs to. This must contain at least one entry. hash_ (bytes): A 32 byte SHA256 hash. This field is in binary format. For JSON requests, hashes are base64-encoded. - expire_time (~.timestamp.Timestamp): + expire_time (google.protobuf.timestamp_pb2.Timestamp): The cache lifetime for the returned match. Clients must not cache this response past this timestamp to avoid false positives. @@ -294,11 +294,11 @@ class ThreatEntryAdditions(proto.Message): response. Attributes: - raw_hashes (Sequence[~.webrisk.RawHashes]): + raw_hashes (Sequence[google.cloud.webrisk_v1.types.RawHashes]): The raw SHA256-formatted entries. Repeated to allow returning sets of hashes with different prefix sizes. - rice_hashes (~.webrisk.RiceDeltaEncoding): + rice_hashes (google.cloud.webrisk_v1.types.RiceDeltaEncoding): The encoded 4-byte prefixes of SHA256-formatted entries, using a Golomb-Rice encoding. The hashes are converted to uint32, sorted in ascending order, then delta encoded and @@ -314,9 +314,9 @@ class ThreatEntryRemovals(proto.Message): r"""Contains the set of entries to remove from a local database. Attributes: - raw_indices (~.webrisk.RawIndices): + raw_indices (google.cloud.webrisk_v1.types.RawIndices): The raw removal indices for a local list. - rice_indices (~.webrisk.RiceDeltaEncoding): + rice_indices (google.cloud.webrisk_v1.types.RiceDeltaEncoding): The encoded local, lexicographically-sorted list indices, using a Golomb-Rice encoding. Used for sending compressed removal indices. The removal indices (uint32) are sorted in @@ -422,7 +422,7 @@ class CreateSubmissionRequest(proto.Message): Required. The name of the project that is making the submission. This string is in the format "projects/{project_number}". - submission (~.webrisk.Submission): + submission (google.cloud.webrisk_v1.types.Submission): Required. The submission that contains the content of the phishing report. """ diff --git a/google/cloud/webrisk_v1beta1/services/web_risk_service_v1_beta1/async_client.py b/google/cloud/webrisk_v1beta1/services/web_risk_service_v1_beta1/async_client.py index 3804db5..3c5072e 100644 --- a/google/cloud/webrisk_v1beta1/services/web_risk_service_v1_beta1/async_client.py +++ b/google/cloud/webrisk_v1beta1/services/web_risk_service_v1_beta1/async_client.py @@ -77,7 +77,36 @@ class WebRiskServiceV1Beta1AsyncClient: WebRiskServiceV1Beta1Client.parse_common_location_path ) - from_service_account_file = WebRiskServiceV1Beta1Client.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: + WebRiskServiceV1Beta1AsyncClient: The constructed client. + """ + return WebRiskServiceV1Beta1Client.from_service_account_info.__func__(WebRiskServiceV1Beta1AsyncClient, 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: + WebRiskServiceV1Beta1AsyncClient: The constructed client. + """ + return WebRiskServiceV1Beta1Client.from_service_account_file.__func__(WebRiskServiceV1Beta1AsyncClient, filename, *args, **kwargs) # type: ignore + from_service_account_json = from_service_account_file @property @@ -156,9 +185,9 @@ async def compute_threat_list_diff( r"""Gets the most recent threat list diffs. Args: - request (:class:`~.webrisk.ComputeThreatListDiffRequest`): + request (:class:`google.cloud.webrisk_v1beta1.types.ComputeThreatListDiffRequest`): The request object. Describes an API diff request. - threat_type (:class:`~.webrisk.ThreatType`): + threat_type (:class:`google.cloud.webrisk_v1beta1.types.ThreatType`): The ThreatList to update. This corresponds to the ``threat_type`` field on the ``request`` instance; if ``request`` is provided, this @@ -168,12 +197,14 @@ async def compute_threat_list_diff( client for the requested list (the client version that was received from the last successful diff). + This corresponds to the ``version_token`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - constraints (:class:`~.webrisk.ComputeThreatListDiffRequest.Constraints`): + constraints (:class:`google.cloud.webrisk_v1beta1.types.ComputeThreatListDiffRequest.Constraints`): Required. The constraints associated with this request. + This corresponds to the ``constraints`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -185,7 +216,7 @@ async def compute_threat_list_diff( sent along with the request as metadata. Returns: - ~.webrisk.ComputeThreatListDiffResponse: + google.cloud.webrisk_v1beta1.types.ComputeThreatListDiffResponse: """ # Create or coerce a protobuf request object. @@ -221,6 +252,7 @@ async def compute_threat_list_diff( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=600.0, ), default_timeout=600.0, client_info=DEFAULT_CLIENT_INFO, @@ -246,18 +278,20 @@ async def search_uris( given threatList. Args: - request (:class:`~.webrisk.SearchUrisRequest`): + request (:class:`google.cloud.webrisk_v1beta1.types.SearchUrisRequest`): The request object. Request to check URI entries against threatLists. uri (:class:`str`): Required. The URI to be checked for matches. + This corresponds to the ``uri`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - threat_types (:class:`Sequence[~.webrisk.ThreatType]`): + threat_types (:class:`Sequence[google.cloud.webrisk_v1beta1.types.ThreatType]`): Required. The ThreatLists to search in. + This corresponds to the ``threat_types`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -269,7 +303,7 @@ async def search_uris( sent along with the request as metadata. Returns: - ~.webrisk.SearchUrisResponse: + google.cloud.webrisk_v1beta1.types.SearchUrisResponse: """ # Create or coerce a protobuf request object. @@ -304,6 +338,7 @@ async def search_uris( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=600.0, ), default_timeout=600.0, client_info=DEFAULT_CLIENT_INFO, @@ -333,7 +368,7 @@ async def search_hashes( match of a threat. Args: - request (:class:`~.webrisk.SearchHashesRequest`): + request (:class:`google.cloud.webrisk_v1beta1.types.SearchHashesRequest`): The request object. Request to return full hashes matched by the provided hash prefixes. hash_prefix (:class:`bytes`): @@ -341,12 +376,14 @@ async def search_hashes( significant 4-32 bytes of a SHA256 hash. For JSON requests, this field is base64-encoded. + This corresponds to the ``hash_prefix`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - threat_types (:class:`Sequence[~.webrisk.ThreatType]`): + threat_types (:class:`Sequence[google.cloud.webrisk_v1beta1.types.ThreatType]`): Required. The ThreatLists to search in. + This corresponds to the ``threat_types`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -358,7 +395,7 @@ async def search_hashes( sent along with the request as metadata. Returns: - ~.webrisk.SearchHashesResponse: + google.cloud.webrisk_v1beta1.types.SearchHashesResponse: """ # Create or coerce a protobuf request object. @@ -393,6 +430,7 @@ async def search_hashes( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=600.0, ), default_timeout=600.0, client_info=DEFAULT_CLIENT_INFO, diff --git a/google/cloud/webrisk_v1beta1/services/web_risk_service_v1_beta1/client.py b/google/cloud/webrisk_v1beta1/services/web_risk_service_v1_beta1/client.py index d3acddd..36b5b8a 100644 --- a/google/cloud/webrisk_v1beta1/services/web_risk_service_v1_beta1/client.py +++ b/google/cloud/webrisk_v1beta1/services/web_risk_service_v1_beta1/client.py @@ -114,6 +114,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: + WebRiskServiceV1Beta1Client: 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 @@ -126,7 +142,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. + WebRiskServiceV1Beta1Client: 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, ~.WebRiskServiceV1Beta1Transport]): The + transport (Union[str, WebRiskServiceV1Beta1Transport]): 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, ) @@ -333,24 +345,26 @@ def compute_threat_list_diff( r"""Gets the most recent threat list diffs. Args: - request (:class:`~.webrisk.ComputeThreatListDiffRequest`): + request (google.cloud.webrisk_v1beta1.types.ComputeThreatListDiffRequest): The request object. Describes an API diff request. - threat_type (:class:`~.webrisk.ThreatType`): + threat_type (google.cloud.webrisk_v1beta1.types.ThreatType): The ThreatList to update. This corresponds to the ``threat_type`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - version_token (:class:`bytes`): + version_token (bytes): The current version token of the client for the requested list (the client version that was received from the last successful diff). + This corresponds to the ``version_token`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - constraints (:class:`~.webrisk.ComputeThreatListDiffRequest.Constraints`): + constraints (google.cloud.webrisk_v1beta1.types.ComputeThreatListDiffRequest.Constraints): Required. The constraints associated with this request. + This corresponds to the ``constraints`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -362,7 +376,7 @@ def compute_threat_list_diff( sent along with the request as metadata. Returns: - ~.webrisk.ComputeThreatListDiffResponse: + google.cloud.webrisk_v1beta1.types.ComputeThreatListDiffResponse: """ # Create or coerce a protobuf request object. @@ -416,18 +430,20 @@ def search_uris( given threatList. Args: - request (:class:`~.webrisk.SearchUrisRequest`): + request (google.cloud.webrisk_v1beta1.types.SearchUrisRequest): The request object. Request to check URI entries against threatLists. - uri (:class:`str`): + uri (str): Required. The URI to be checked for matches. + This corresponds to the ``uri`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - threat_types (:class:`Sequence[~.webrisk.ThreatType]`): + threat_types (Sequence[google.cloud.webrisk_v1beta1.types.ThreatType]): Required. The ThreatLists to search in. + This corresponds to the ``threat_types`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -439,7 +455,7 @@ def search_uris( sent along with the request as metadata. Returns: - ~.webrisk.SearchUrisResponse: + google.cloud.webrisk_v1beta1.types.SearchUrisResponse: """ # Create or coerce a protobuf request object. @@ -464,9 +480,8 @@ def search_uris( if uri is not None: request.uri = uri - - if threat_types: - request.threat_types.extend(threat_types) + if threat_types is not None: + request.threat_types = threat_types # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. @@ -496,20 +511,22 @@ def search_hashes( match of a threat. Args: - request (:class:`~.webrisk.SearchHashesRequest`): + request (google.cloud.webrisk_v1beta1.types.SearchHashesRequest): The request object. Request to return full hashes matched by the provided hash prefixes. - hash_prefix (:class:`bytes`): + hash_prefix (bytes): A hash prefix, consisting of the most significant 4-32 bytes of a SHA256 hash. For JSON requests, this field is base64-encoded. + This corresponds to the ``hash_prefix`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - threat_types (:class:`Sequence[~.webrisk.ThreatType]`): + threat_types (Sequence[google.cloud.webrisk_v1beta1.types.ThreatType]): Required. The ThreatLists to search in. + This corresponds to the ``threat_types`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -521,7 +538,7 @@ def search_hashes( sent along with the request as metadata. Returns: - ~.webrisk.SearchHashesResponse: + google.cloud.webrisk_v1beta1.types.SearchHashesResponse: """ # Create or coerce a protobuf request object. @@ -546,9 +563,8 @@ def search_hashes( if hash_prefix is not None: request.hash_prefix = hash_prefix - - if threat_types: - request.threat_types.extend(threat_types) + if threat_types is not None: + request.threat_types = threat_types # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. diff --git a/google/cloud/webrisk_v1beta1/services/web_risk_service_v1_beta1/transports/base.py b/google/cloud/webrisk_v1beta1/services/web_risk_service_v1_beta1/transports/base.py index d26cc02..e35f546 100644 --- a/google/cloud/webrisk_v1beta1/services/web_risk_service_v1_beta1/transports/base.py +++ b/google/cloud/webrisk_v1beta1/services/web_risk_service_v1_beta1/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=600.0, ), default_timeout=600.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=600.0, ), default_timeout=600.0, client_info=client_info, @@ -139,6 +141,7 @@ def _prep_wrapped_messages(self, client_info): predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=600.0, ), default_timeout=600.0, client_info=client_info, diff --git a/google/cloud/webrisk_v1beta1/services/web_risk_service_v1_beta1/transports/grpc.py b/google/cloud/webrisk_v1beta1/services/web_risk_service_v1_beta1/transports/grpc.py index e225633..3fc4e39 100644 --- a/google/cloud/webrisk_v1beta1/services/web_risk_service_v1_beta1/transports/grpc.py +++ b/google/cloud/webrisk_v1beta1/services/web_risk_service_v1_beta1/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/webrisk_v1beta1/services/web_risk_service_v1_beta1/transports/grpc_asyncio.py b/google/cloud/webrisk_v1beta1/services/web_risk_service_v1_beta1/transports/grpc_asyncio.py index 7d94c10..292ffd7 100644 --- a/google/cloud/webrisk_v1beta1/services/web_risk_service_v1_beta1/transports/grpc_asyncio.py +++ b/google/cloud/webrisk_v1beta1/services/web_risk_service_v1_beta1/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/webrisk_v1beta1/types/__init__.py b/google/cloud/webrisk_v1beta1/types/__init__.py index 3453411..81db104 100644 --- a/google/cloud/webrisk_v1beta1/types/__init__.py +++ b/google/cloud/webrisk_v1beta1/types/__init__.py @@ -18,31 +18,31 @@ from .webrisk import ( ComputeThreatListDiffRequest, ComputeThreatListDiffResponse, - SearchUrisRequest, - SearchUrisResponse, + RawHashes, + RawIndices, + RiceDeltaEncoding, SearchHashesRequest, SearchHashesResponse, + SearchUrisRequest, + SearchUrisResponse, ThreatEntryAdditions, ThreatEntryRemovals, - RawIndices, - RawHashes, - RiceDeltaEncoding, - ThreatType, CompressionType, + ThreatType, ) __all__ = ( "ComputeThreatListDiffRequest", "ComputeThreatListDiffResponse", - "SearchUrisRequest", - "SearchUrisResponse", + "RawHashes", + "RawIndices", + "RiceDeltaEncoding", "SearchHashesRequest", "SearchHashesResponse", + "SearchUrisRequest", + "SearchUrisResponse", "ThreatEntryAdditions", "ThreatEntryRemovals", - "RawIndices", - "RawHashes", - "RiceDeltaEncoding", - "ThreatType", "CompressionType", + "ThreatType", ) diff --git a/google/cloud/webrisk_v1beta1/types/webrisk.py b/google/cloud/webrisk_v1beta1/types/webrisk.py index 711cd90..9ad74b2 100644 --- a/google/cloud/webrisk_v1beta1/types/webrisk.py +++ b/google/cloud/webrisk_v1beta1/types/webrisk.py @@ -62,13 +62,13 @@ class ComputeThreatListDiffRequest(proto.Message): r"""Describes an API diff request. Attributes: - threat_type (~.webrisk.ThreatType): + threat_type (google.cloud.webrisk_v1beta1.types.ThreatType): The ThreatList to update. version_token (bytes): The current version token of the client for the requested list (the client version that was received from the last successful diff). - constraints (~.webrisk.ComputeThreatListDiffRequest.Constraints): + constraints (google.cloud.webrisk_v1beta1.types.ComputeThreatListDiffRequest.Constraints): Required. The constraints associated with this request. """ @@ -87,7 +87,7 @@ class Constraints(proto.Message): willing to have in the local database. This should be a power of 2 between 2\ **10 and 2**\ 20. If zero, no database size limit is set. - supported_compressions (Sequence[~.webrisk.CompressionType]): + supported_compressions (Sequence[google.cloud.webrisk_v1beta1.types.CompressionType]): The compression types supported by the client. """ @@ -111,26 +111,26 @@ class ComputeThreatListDiffResponse(proto.Message): r""" Attributes: - response_type (~.webrisk.ComputeThreatListDiffResponse.ResponseType): + response_type (google.cloud.webrisk_v1beta1.types.ComputeThreatListDiffResponse.ResponseType): The type of response. This may indicate that an action must be taken by the client when the response is received. - additions (~.webrisk.ThreatEntryAdditions): + additions (google.cloud.webrisk_v1beta1.types.ThreatEntryAdditions): A set of entries to add to a local threat type's list. - removals (~.webrisk.ThreatEntryRemovals): + removals (google.cloud.webrisk_v1beta1.types.ThreatEntryRemovals): A set of entries to remove from a local threat type's list. This field may be empty. new_version_token (bytes): The new opaque client version token. - checksum (~.webrisk.ComputeThreatListDiffResponse.Checksum): + checksum (google.cloud.webrisk_v1beta1.types.ComputeThreatListDiffResponse.Checksum): The expected SHA256 hash of the client state; that is, of the sorted list of all hashes present in the database after applying the provided diff. If the client state doesn't match the expected state, the client must disregard this diff and retry later. - recommended_next_diff (~.timestamp.Timestamp): + recommended_next_diff (google.protobuf.timestamp_pb2.Timestamp): The soonest the client should wait before issuing any diff request. Querying sooner is unlikely to produce a meaningful diff. Waiting @@ -178,7 +178,7 @@ class SearchUrisRequest(proto.Message): Attributes: uri (str): Required. The URI to be checked for matches. - threat_types (Sequence[~.webrisk.ThreatType]): + threat_types (Sequence[google.cloud.webrisk_v1beta1.types.ThreatType]): Required. The ThreatLists to search in. """ @@ -191,7 +191,7 @@ class SearchUrisResponse(proto.Message): r""" Attributes: - threat (~.webrisk.SearchUrisResponse.ThreatUri): + threat (google.cloud.webrisk_v1beta1.types.SearchUrisResponse.ThreatUri): The threat list matches. This may be empty if the URI is on no list. """ @@ -200,9 +200,9 @@ class ThreatUri(proto.Message): r"""Contains threat information on a matching uri. Attributes: - threat_types (Sequence[~.webrisk.ThreatType]): + threat_types (Sequence[google.cloud.webrisk_v1beta1.types.ThreatType]): The ThreatList this threat belongs to. - expire_time (~.timestamp.Timestamp): + expire_time (google.protobuf.timestamp_pb2.Timestamp): The cache lifetime for the returned match. Clients must not cache this response past this timestamp to avoid false positives. @@ -224,7 +224,7 @@ class SearchHashesRequest(proto.Message): A hash prefix, consisting of the most significant 4-32 bytes of a SHA256 hash. For JSON requests, this field is base64-encoded. - threat_types (Sequence[~.webrisk.ThreatType]): + threat_types (Sequence[google.cloud.webrisk_v1beta1.types.ThreatType]): Required. The ThreatLists to search in. """ @@ -237,10 +237,10 @@ class SearchHashesResponse(proto.Message): r""" Attributes: - threats (Sequence[~.webrisk.SearchHashesResponse.ThreatHash]): + threats (Sequence[google.cloud.webrisk_v1beta1.types.SearchHashesResponse.ThreatHash]): The full hashes that matched the requested prefixes. The hash will be populated in the key. - negative_expire_time (~.timestamp.Timestamp): + negative_expire_time (google.protobuf.timestamp_pb2.Timestamp): For requested entities that did not match the threat list, how long to cache the response until. @@ -250,14 +250,14 @@ class ThreatHash(proto.Message): r"""Contains threat information on a matching hash. Attributes: - threat_types (Sequence[~.webrisk.ThreatType]): + threat_types (Sequence[google.cloud.webrisk_v1beta1.types.ThreatType]): The ThreatList this threat belongs to. This must contain at least one entry. hash_ (bytes): A 32 byte SHA256 hash. This field is in binary format. For JSON requests, hashes are base64-encoded. - expire_time (~.timestamp.Timestamp): + expire_time (google.protobuf.timestamp_pb2.Timestamp): The cache lifetime for the returned match. Clients must not cache this response past this timestamp to avoid false positives. @@ -282,11 +282,11 @@ class ThreatEntryAdditions(proto.Message): response. Attributes: - raw_hashes (Sequence[~.webrisk.RawHashes]): + raw_hashes (Sequence[google.cloud.webrisk_v1beta1.types.RawHashes]): The raw SHA256-formatted entries. Repeated to allow returning sets of hashes with different prefix sizes. - rice_hashes (~.webrisk.RiceDeltaEncoding): + rice_hashes (google.cloud.webrisk_v1beta1.types.RiceDeltaEncoding): The encoded 4-byte prefixes of SHA256-formatted entries, using a Golomb-Rice encoding. The hashes are converted to uint32, sorted in ascending order, then delta encoded and @@ -302,9 +302,9 @@ class ThreatEntryRemovals(proto.Message): r"""Contains the set of entries to remove from a local database. Attributes: - raw_indices (~.webrisk.RawIndices): + raw_indices (google.cloud.webrisk_v1beta1.types.RawIndices): The raw removal indices for a local list. - rice_indices (~.webrisk.RiceDeltaEncoding): + rice_indices (google.cloud.webrisk_v1beta1.types.RiceDeltaEncoding): The encoded local, lexicographically-sorted list indices, using a Golomb-Rice encoding. Used for sending compressed removal indices. The removal indices (uint32) are sorted in diff --git a/noxfile.py b/noxfile.py index a4884a0..ae8392b 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) @@ -152,7 +189,7 @@ def docs(session): """Build the docs for this library.""" session.install("-e", ".") - session.install("sphinx<3.0.0", "alabaster", "recommonmark") + session.install("sphinx", "alabaster", "recommonmark") shutil.rmtree(os.path.join("docs", "_build"), ignore_errors=True) session.run( diff --git a/renovate.json b/renovate.json index 4fa9493..f08bc22 100644 --- a/renovate.json +++ b/renovate.json @@ -1,5 +1,6 @@ { "extends": [ "config:base", ":preserveSemverRanges" - ] + ], + "ignorePaths": [".pre-commit-config.yaml"] } diff --git a/synth.metadata b/synth.metadata index 8e42f91..a3f478d 100644 --- a/synth.metadata +++ b/synth.metadata @@ -3,23 +3,23 @@ { "git": { "name": ".", - "remote": "https://github.com/googleapis/python-webrisk.git", - "sha": "4cda399cc9aa320949c63ed057059914ab97c8f6" + "remote": "git@github.com:googleapis/python-webrisk", + "sha": "cd5286dae6be33d3eddec16b20d93b2e716e0cfc" } }, { "git": { "name": "googleapis", "remote": "https://github.com/googleapis/googleapis.git", - "sha": "57fc4a8a94a5bd015a83fb0f0a1707f62254b2cd", - "internalRef": "348813319" + "sha": "a1af63efb82f54428ab35ea76869d9cd57ca52b8", + "internalRef": "364635275" } }, { "git": { "name": "synthtool", "remote": "https://github.com/googleapis/synthtool.git", - "sha": "373861061648b5fe5e0ac4f8a38b32d639ee93e4" + "sha": "86ed43d4f56e6404d068e62e497029018879c771" } } ], @@ -42,113 +42,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/conf.py", - "docs/multiprocessing.rst", - "docs/webrisk_v1/services.rst", - "docs/webrisk_v1/types.rst", - "docs/webrisk_v1beta1/services.rst", - "docs/webrisk_v1beta1/types.rst", - "google/cloud/webrisk/__init__.py", - "google/cloud/webrisk/py.typed", - "google/cloud/webrisk_v1/__init__.py", - "google/cloud/webrisk_v1/proto/webrisk.proto", - "google/cloud/webrisk_v1/py.typed", - "google/cloud/webrisk_v1/services/__init__.py", - "google/cloud/webrisk_v1/services/web_risk_service/__init__.py", - "google/cloud/webrisk_v1/services/web_risk_service/async_client.py", - "google/cloud/webrisk_v1/services/web_risk_service/client.py", - "google/cloud/webrisk_v1/services/web_risk_service/transports/__init__.py", - "google/cloud/webrisk_v1/services/web_risk_service/transports/base.py", - "google/cloud/webrisk_v1/services/web_risk_service/transports/grpc.py", - "google/cloud/webrisk_v1/services/web_risk_service/transports/grpc_asyncio.py", - "google/cloud/webrisk_v1/types/__init__.py", - "google/cloud/webrisk_v1/types/webrisk.py", - "google/cloud/webrisk_v1beta1/__init__.py", - "google/cloud/webrisk_v1beta1/proto/webrisk.proto", - "google/cloud/webrisk_v1beta1/py.typed", - "google/cloud/webrisk_v1beta1/services/__init__.py", - "google/cloud/webrisk_v1beta1/services/web_risk_service_v1_beta1/__init__.py", - "google/cloud/webrisk_v1beta1/services/web_risk_service_v1_beta1/async_client.py", - "google/cloud/webrisk_v1beta1/services/web_risk_service_v1_beta1/client.py", - "google/cloud/webrisk_v1beta1/services/web_risk_service_v1_beta1/transports/__init__.py", - "google/cloud/webrisk_v1beta1/services/web_risk_service_v1_beta1/transports/base.py", - "google/cloud/webrisk_v1beta1/services/web_risk_service_v1_beta1/transports/grpc.py", - "google/cloud/webrisk_v1beta1/services/web_risk_service_v1_beta1/transports/grpc_asyncio.py", - "google/cloud/webrisk_v1beta1/types/__init__.py", - "google/cloud/webrisk_v1beta1/types/webrisk.py", - "mypy.ini", - "noxfile.py", - "renovate.json", - "samples/AUTHORING_GUIDE.md", - "samples/CONTRIBUTING.md", - "scripts/decrypt-secrets.sh", - "scripts/fixup_webrisk_v1_keywords.py", - "scripts/fixup_webrisk_v1beta1_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/webrisk_v1/__init__.py", - "tests/unit/gapic/webrisk_v1/test_web_risk_service.py", - "tests/unit/gapic/webrisk_v1beta1/__init__.py", - "tests/unit/gapic/webrisk_v1beta1/test_web_risk_service_v1_beta1.py", - "webrisk-v1-py.tar.gz" ] } \ No newline at end of file diff --git a/tests/unit/gapic/webrisk_v1/__init__.py b/tests/unit/gapic/webrisk_v1/__init__.py index 8b13789..42ffdf2 100644 --- a/tests/unit/gapic/webrisk_v1/__init__.py +++ b/tests/unit/gapic/webrisk_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/webrisk_v1/test_web_risk_service.py b/tests/unit/gapic/webrisk_v1/test_web_risk_service.py index 1120b73..6a7bcdf 100644 --- a/tests/unit/gapic/webrisk_v1/test_web_risk_service.py +++ b/tests/unit/gapic/webrisk_v1/test_web_risk_service.py @@ -85,7 +85,24 @@ def test__get_default_mtls_endpoint(): @pytest.mark.parametrize( - "client_class", [WebRiskServiceClient, WebRiskServiceAsyncClient] + "client_class", [WebRiskServiceClient, WebRiskServiceAsyncClient,] +) +def test_web_risk_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 == "webrisk.googleapis.com:443" + + +@pytest.mark.parametrize( + "client_class", [WebRiskServiceClient, WebRiskServiceAsyncClient,] ) def test_web_risk_service_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() @@ -95,16 +112,21 @@ def test_web_risk_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 == "webrisk.googleapis.com:443" def test_web_risk_service_client_get_transport_class(): transport = WebRiskServiceClient.get_transport_class() - assert transport == transports.WebRiskServiceGrpcTransport + available_transports = [ + transports.WebRiskServiceGrpcTransport, + ] + assert transport in available_transports transport = WebRiskServiceClient.get_transport_class("grpc") assert transport == transports.WebRiskServiceGrpcTransport @@ -155,7 +177,7 @@ def test_web_risk_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, ) @@ -171,7 +193,7 @@ def test_web_risk_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, ) @@ -187,7 +209,7 @@ def test_web_risk_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, ) @@ -215,7 +237,7 @@ def test_web_risk_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 +288,25 @@ def test_web_risk_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 +315,53 @@ def test_web_risk_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 +387,7 @@ def test_web_risk_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 +417,7 @@ def test_web_risk_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, ) @@ -431,7 +436,7 @@ def test_web_risk_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, ) @@ -482,6 +487,24 @@ def test_compute_threat_list_diff_from_dict(): test_compute_threat_list_diff(request_type=dict) +def test_compute_threat_list_diff_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 = WebRiskServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.compute_threat_list_diff), "__call__" + ) as call: + client.compute_threat_list_diff() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == webrisk.ComputeThreatListDiffRequest() + + @pytest.mark.asyncio async def test_compute_threat_list_diff_async( transport: str = "grpc_asyncio", request_type=webrisk.ComputeThreatListDiffRequest @@ -666,6 +689,22 @@ def test_search_uris_from_dict(): test_search_uris(request_type=dict) +def test_search_uris_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 = WebRiskServiceClient( + 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_uris), "__call__") as call: + client.search_uris() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == webrisk.SearchUrisRequest() + + @pytest.mark.asyncio async def test_search_uris_async( transport: str = "grpc_asyncio", request_type=webrisk.SearchUrisRequest @@ -814,6 +853,22 @@ def test_search_hashes_from_dict(): test_search_hashes(request_type=dict) +def test_search_hashes_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 = WebRiskServiceClient( + 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_hashes), "__call__") as call: + client.search_hashes() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == webrisk.SearchHashesRequest() + + @pytest.mark.asyncio async def test_search_hashes_async( transport: str = "grpc_asyncio", request_type=webrisk.SearchHashesRequest @@ -966,6 +1021,24 @@ def test_create_submission_from_dict(): test_create_submission(request_type=dict) +def test_create_submission_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 = WebRiskServiceClient( + 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_submission), "__call__" + ) as call: + client.create_submission() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == webrisk.CreateSubmissionRequest() + + @pytest.mark.asyncio async def test_create_submission_async( transport: str = "grpc_asyncio", request_type=webrisk.CreateSubmissionRequest @@ -1302,6 +1375,51 @@ def test_web_risk_service_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [ + transports.WebRiskServiceGrpcTransport, + transports.WebRiskServiceGrpcAsyncIOTransport, + ], +) +def test_web_risk_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_web_risk_service_host_no_port(): client = WebRiskServiceClient( credentials=credentials.AnonymousCredentials(), @@ -1323,7 +1441,7 @@ def test_web_risk_service_host_with_port(): def test_web_risk_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.WebRiskServiceGrpcTransport( @@ -1335,7 +1453,7 @@ def test_web_risk_service_grpc_transport_channel(): def test_web_risk_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.WebRiskServiceGrpcAsyncIOTransport( @@ -1346,6 +1464,8 @@ def test_web_risk_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", [ @@ -1360,7 +1480,7 @@ def test_web_risk_service_transport_channel_mtls_with_client_cert_source( "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 @@ -1398,6 +1518,8 @@ def test_web_risk_service_transport_channel_mtls_with_client_cert_source( 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", [ @@ -1413,7 +1535,7 @@ def test_web_risk_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/webrisk_v1beta1/__init__.py b/tests/unit/gapic/webrisk_v1beta1/__init__.py index 8b13789..42ffdf2 100644 --- a/tests/unit/gapic/webrisk_v1beta1/__init__.py +++ b/tests/unit/gapic/webrisk_v1beta1/__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/webrisk_v1beta1/test_web_risk_service_v1_beta1.py b/tests/unit/gapic/webrisk_v1beta1/test_web_risk_service_v1_beta1.py index 8c90db9..3d57d0f 100644 --- a/tests/unit/gapic/webrisk_v1beta1/test_web_risk_service_v1_beta1.py +++ b/tests/unit/gapic/webrisk_v1beta1/test_web_risk_service_v1_beta1.py @@ -90,7 +90,24 @@ def test__get_default_mtls_endpoint(): @pytest.mark.parametrize( - "client_class", [WebRiskServiceV1Beta1Client, WebRiskServiceV1Beta1AsyncClient] + "client_class", [WebRiskServiceV1Beta1Client, WebRiskServiceV1Beta1AsyncClient,] +) +def test_web_risk_service_v1_beta1_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 == "webrisk.googleapis.com:443" + + +@pytest.mark.parametrize( + "client_class", [WebRiskServiceV1Beta1Client, WebRiskServiceV1Beta1AsyncClient,] ) def test_web_risk_service_v1_beta1_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() @@ -100,16 +117,21 @@ def test_web_risk_service_v1_beta1_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 == "webrisk.googleapis.com:443" def test_web_risk_service_v1_beta1_client_get_transport_class(): transport = WebRiskServiceV1Beta1Client.get_transport_class() - assert transport == transports.WebRiskServiceV1Beta1GrpcTransport + available_transports = [ + transports.WebRiskServiceV1Beta1GrpcTransport, + ] + assert transport in available_transports transport = WebRiskServiceV1Beta1Client.get_transport_class("grpc") assert transport == transports.WebRiskServiceV1Beta1GrpcTransport @@ -164,7 +186,7 @@ def test_web_risk_service_v1_beta1_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, ) @@ -180,7 +202,7 @@ def test_web_risk_service_v1_beta1_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, ) @@ -196,7 +218,7 @@ def test_web_risk_service_v1_beta1_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, ) @@ -224,7 +246,7 @@ def test_web_risk_service_v1_beta1_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, ) @@ -285,29 +307,25 @@ def test_web_risk_service_v1_beta1_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. @@ -316,66 +334,53 @@ def test_web_risk_service_v1_beta1_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", @@ -405,7 +410,7 @@ def test_web_risk_service_v1_beta1_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, ) @@ -439,7 +444,7 @@ def test_web_risk_service_v1_beta1_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, ) @@ -458,7 +463,7 @@ def test_web_risk_service_v1_beta1_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, ) @@ -509,6 +514,24 @@ def test_compute_threat_list_diff_from_dict(): test_compute_threat_list_diff(request_type=dict) +def test_compute_threat_list_diff_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 = WebRiskServiceV1Beta1Client( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.compute_threat_list_diff), "__call__" + ) as call: + client.compute_threat_list_diff() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == webrisk.ComputeThreatListDiffRequest() + + @pytest.mark.asyncio async def test_compute_threat_list_diff_async( transport: str = "grpc_asyncio", request_type=webrisk.ComputeThreatListDiffRequest @@ -701,6 +724,22 @@ def test_search_uris_from_dict(): test_search_uris(request_type=dict) +def test_search_uris_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 = WebRiskServiceV1Beta1Client( + 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_uris), "__call__") as call: + client.search_uris() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == webrisk.SearchUrisRequest() + + @pytest.mark.asyncio async def test_search_uris_async( transport: str = "grpc_asyncio", request_type=webrisk.SearchUrisRequest @@ -857,6 +896,22 @@ def test_search_hashes_from_dict(): test_search_hashes(request_type=dict) +def test_search_hashes_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 = WebRiskServiceV1Beta1Client( + 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_hashes), "__call__") as call: + client.search_hashes() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == webrisk.SearchHashesRequest() + + @pytest.mark.asyncio async def test_search_hashes_async( transport: str = "grpc_asyncio", request_type=webrisk.SearchHashesRequest @@ -1143,6 +1198,53 @@ def test_web_risk_service_v1_beta1_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [ + transports.WebRiskServiceV1Beta1GrpcTransport, + transports.WebRiskServiceV1Beta1GrpcAsyncIOTransport, + ], +) +def test_web_risk_service_v1_beta1_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_web_risk_service_v1_beta1_host_no_port(): client = WebRiskServiceV1Beta1Client( credentials=credentials.AnonymousCredentials(), @@ -1164,7 +1266,7 @@ def test_web_risk_service_v1_beta1_host_with_port(): def test_web_risk_service_v1_beta1_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.WebRiskServiceV1Beta1GrpcTransport( @@ -1176,7 +1278,7 @@ def test_web_risk_service_v1_beta1_grpc_transport_channel(): def test_web_risk_service_v1_beta1_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.WebRiskServiceV1Beta1GrpcAsyncIOTransport( @@ -1187,6 +1289,8 @@ def test_web_risk_service_v1_beta1_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", [ @@ -1201,7 +1305,7 @@ def test_web_risk_service_v1_beta1_transport_channel_mtls_with_client_cert_sourc "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 @@ -1239,6 +1343,8 @@ def test_web_risk_service_v1_beta1_transport_channel_mtls_with_client_cert_sourc 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", [ @@ -1254,7 +1360,7 @@ def test_web_risk_service_v1_beta1_transport_channel_mtls_with_adc(transport_cla 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/webrisk-v1-py.tar.gz b/webrisk-v1-py.tar.gz deleted file mode 100644 index e69de29..0000000