diff --git a/.coveragerc b/.coveragerc index dd39c854..8a9e352c 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1,35 +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/talent/__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 \ No newline at end of file + # 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 00000000..fc281c05 --- /dev/null +++ b/.github/header-checker-lint.yml @@ -0,0 +1,15 @@ +{"allowedCopyrightHolders": ["Google LLC"], + "allowedLicenses": ["Apache-2.0", "MIT", "BSD-3"], + "ignoreFiles": ["**/requirements.txt", "**/requirements-test.txt"], + "sourceFileExtensions": [ + "ts", + "js", + "java", + "sh", + "Dockerfile", + "yaml", + "py", + "html", + "txt" + ] +} \ No newline at end of file diff --git a/.gitignore b/.gitignore index b9daa52f..b4243ced 100644 --- a/.gitignore +++ b/.gitignore @@ -50,8 +50,10 @@ docs.metadata # Virtual environment env/ + +# Test logs coverage.xml -sponge_log.xml +*sponge_log.xml # System test environment variables. system_tests/local_test_setup diff --git a/.kokoro/build.sh b/.kokoro/build.sh index 291a09e9..6e491f98 100755 --- a/.kokoro/build.sh +++ b/.kokoro/build.sh @@ -15,7 +15,11 @@ set -eo pipefail -cd github/python-talent +if [[ -z "${PROJECT_ROOT:-}" ]]; then + PROJECT_ROOT="github/python-talent" +fi + +cd "${PROJECT_ROOT}" # Disable buffering, so that the logs stream through. export PYTHONUNBUFFERED=1 @@ -30,16 +34,26 @@ export GOOGLE_APPLICATION_CREDENTIALS=${KOKORO_GFILE_DIR}/service-account.json export PROJECT_ID=$(cat "${KOKORO_GFILE_DIR}/project-id.json") # Remove old nox -python3.6 -m pip uninstall --yes --quiet nox-automation +python3 -m pip uninstall --yes --quiet nox-automation # Install nox -python3.6 -m pip install --upgrade --quiet nox -python3.6 -m nox --version +python3 -m pip install --upgrade --quiet nox +python3 -m nox --version + +# If this is a continuous build, send the test log to the FlakyBot. +# See https://github.com/googleapis/repo-automation-bots/tree/master/packages/flakybot. +if [[ $KOKORO_BUILD_ARTIFACTS_SUBDIR = *"continuous"* ]]; then + cleanup() { + chmod +x $KOKORO_GFILE_DIR/linux_amd64/flakybot + $KOKORO_GFILE_DIR/linux_amd64/flakybot + } + trap cleanup EXIT HUP +fi # If NOX_SESSION is set, it only runs the specified session, # otherwise run all the sessions. if [[ -n "${NOX_SESSION:-}" ]]; then - python3.6 -m nox -s "${NOX_SESSION:-}" + python3 -m nox -s ${NOX_SESSION:-} else - python3.6 -m nox + python3 -m nox fi diff --git a/.kokoro/docs/docs-presubmit.cfg b/.kokoro/docs/docs-presubmit.cfg index 11181078..d5bb31d6 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-talent/.kokoro/build.sh" +} + +# Only run this nox session. +env_vars: { + key: "NOX_SESSION" + value: "docs docfx" +} diff --git a/.kokoro/samples/python3.6/periodic-head.cfg b/.kokoro/samples/python3.6/periodic-head.cfg new file mode 100644 index 00000000..f9cfcd33 --- /dev/null +++ b/.kokoro/samples/python3.6/periodic-head.cfg @@ -0,0 +1,11 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +env_vars: { + key: "INSTALL_LIBRARY_FROM_SOURCE" + value: "True" +} + +env_vars: { + key: "TRAMPOLINE_BUILD_FILE" + value: "github/python-pubsub/.kokoro/test-samples-against-head.sh" +} diff --git a/.kokoro/samples/python3.7/periodic-head.cfg b/.kokoro/samples/python3.7/periodic-head.cfg new file mode 100644 index 00000000..f9cfcd33 --- /dev/null +++ b/.kokoro/samples/python3.7/periodic-head.cfg @@ -0,0 +1,11 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +env_vars: { + key: "INSTALL_LIBRARY_FROM_SOURCE" + value: "True" +} + +env_vars: { + key: "TRAMPOLINE_BUILD_FILE" + value: "github/python-pubsub/.kokoro/test-samples-against-head.sh" +} diff --git a/.kokoro/samples/python3.8/periodic-head.cfg b/.kokoro/samples/python3.8/periodic-head.cfg new file mode 100644 index 00000000..f9cfcd33 --- /dev/null +++ b/.kokoro/samples/python3.8/periodic-head.cfg @@ -0,0 +1,11 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +env_vars: { + key: "INSTALL_LIBRARY_FROM_SOURCE" + value: "True" +} + +env_vars: { + key: "TRAMPOLINE_BUILD_FILE" + value: "github/python-pubsub/.kokoro/test-samples-against-head.sh" +} diff --git a/.kokoro/test-samples-against-head.sh b/.kokoro/test-samples-against-head.sh new file mode 100755 index 00000000..ecd01578 --- /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-talent + +exec .kokoro/test-samples-impl.sh diff --git a/.kokoro/test-samples-impl.sh b/.kokoro/test-samples-impl.sh new file mode 100755 index 00000000..cf5de74c --- /dev/null +++ b/.kokoro/test-samples-impl.sh @@ -0,0 +1,102 @@ +#!/bin/bash +# Copyright 2021 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +# `-e` enables the script to automatically fail when a command fails +# `-o pipefail` sets the exit code to the rightmost comment to exit with a non-zero +set -eo pipefail +# Enables `**` to include files nested inside sub-folders +shopt -s globstar + +# Exit early if samples directory doesn't exist +if [ ! -d "./samples" ]; then + echo "No tests run. `./samples` not found" + exit 0 +fi + +# Disable buffering, so that the logs stream through. +export PYTHONUNBUFFERED=1 + +# Debug: show build environment +env | grep KOKORO + +# Install nox +python3.6 -m pip install --upgrade --quiet nox + +# Use secrets acessor service account to get secrets +if [[ -f "${KOKORO_GFILE_DIR}/secrets_viewer_service_account.json" ]]; then + gcloud auth activate-service-account \ + --key-file="${KOKORO_GFILE_DIR}/secrets_viewer_service_account.json" \ + --project="cloud-devrel-kokoro-resources" +fi + +# This script will create 3 files: +# - testing/test-env.sh +# - testing/service-account.json +# - testing/client-secrets.json +./scripts/decrypt-secrets.sh + +source ./testing/test-env.sh +export GOOGLE_APPLICATION_CREDENTIALS=$(pwd)/testing/service-account.json + +# For cloud-run session, we activate the service account for gcloud sdk. +gcloud auth activate-service-account \ + --key-file "${GOOGLE_APPLICATION_CREDENTIALS}" + +export GOOGLE_CLIENT_SECRETS=$(pwd)/testing/client-secrets.json + +echo -e "\n******************** TESTING PROJECTS ********************" + +# Switch to 'fail at end' to allow all tests to complete before exiting. +set +e +# Use RTN to return a non-zero value if the test fails. +RTN=0 +ROOT=$(pwd) +# Find all requirements.txt in the samples directory (may break on whitespace). +for file in samples/**/requirements.txt; do + cd "$ROOT" + # Navigate to the project folder. + file=$(dirname "$file") + cd "$file" + + echo "------------------------------------------------------------" + echo "- testing $file" + echo "------------------------------------------------------------" + + # Use nox to execute the tests for the project. + python3.6 -m nox -s "$RUN_TESTS_SESSION" + EXIT=$? + + # If this is a periodic build, send the test log to the FlakyBot. + # See https://github.com/googleapis/repo-automation-bots/tree/master/packages/flakybot. + if [[ $KOKORO_BUILD_ARTIFACTS_SUBDIR = *"periodic"* ]]; then + chmod +x $KOKORO_GFILE_DIR/linux_amd64/flakybot + $KOKORO_GFILE_DIR/linux_amd64/flakybot + fi + + if [[ $EXIT -ne 0 ]]; then + RTN=1 + echo -e "\n Testing failed: Nox returned a non-zero exit code. \n" + else + echo -e "\n Testing completed.\n" + fi + +done +cd "$ROOT" + +# Workaround for Kokoro permissions issue: delete secrets +rm testing/{test-env.sh,client-secrets.json,service-account.json} + +exit "$RTN" diff --git a/.kokoro/test-samples.sh b/.kokoro/test-samples.sh index 71fab05d..09ba8e25 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-talent # Run periodic samples tests at latest release if [[ $KOKORO_BUILD_ARTIFACTS_SUBDIR = *"periodic"* ]]; then + # preserving the test runner implementation. + cp .kokoro/test-samples-impl.sh "${TMPDIR}/test-samples-impl.sh" + echo "--- IMPORTANT IMPORTANT IMPORTANT ---" + echo "Now we rewind the repo back to the latest release..." LATEST_RELEASE=$(git describe --abbrev=0 --tags) git checkout $LATEST_RELEASE -fi - -# Exit early if samples directory doesn't exist -if [ ! -d "./samples" ]; then - echo "No tests run. `./samples` not found" - exit 0 -fi - -# Disable buffering, so that the logs stream through. -export PYTHONUNBUFFERED=1 - -# Debug: show build environment -env | grep KOKORO - -# Install nox -python3.6 -m pip install --upgrade --quiet nox - -# Use secrets acessor service account to get secrets -if [[ -f "${KOKORO_GFILE_DIR}/secrets_viewer_service_account.json" ]]; then - gcloud auth activate-service-account \ - --key-file="${KOKORO_GFILE_DIR}/secrets_viewer_service_account.json" \ - --project="cloud-devrel-kokoro-resources" -fi - -# This script will create 3 files: -# - testing/test-env.sh -# - testing/service-account.json -# - testing/client-secrets.json -./scripts/decrypt-secrets.sh - -source ./testing/test-env.sh -export GOOGLE_APPLICATION_CREDENTIALS=$(pwd)/testing/service-account.json - -# For cloud-run session, we activate the service account for gcloud sdk. -gcloud auth activate-service-account \ - --key-file "${GOOGLE_APPLICATION_CREDENTIALS}" - -export GOOGLE_CLIENT_SECRETS=$(pwd)/testing/client-secrets.json - -echo -e "\n******************** TESTING PROJECTS ********************" - -# Switch to 'fail at end' to allow all tests to complete before exiting. -set +e -# Use RTN to return a non-zero value if the test fails. -RTN=0 -ROOT=$(pwd) -# Find all requirements.txt in the samples directory (may break on whitespace). -for file in samples/**/requirements.txt; do - cd "$ROOT" - # Navigate to the project folder. - file=$(dirname "$file") - cd "$file" - - echo "------------------------------------------------------------" - echo "- testing $file" - echo "------------------------------------------------------------" - - # Use nox to execute the tests for the project. - python3.6 -m nox -s "$RUN_TESTS_SESSION" - EXIT=$? - - # If this is a periodic build, send the test log to the FlakyBot. - # See https://github.com/googleapis/repo-automation-bots/tree/master/packages/flakybot. - if [[ $KOKORO_BUILD_ARTIFACTS_SUBDIR = *"periodic"* ]]; then - chmod +x $KOKORO_GFILE_DIR/linux_amd64/flakybot - $KOKORO_GFILE_DIR/linux_amd64/flakybot + echo "The current head is: " + echo $(git rev-parse --verify HEAD) + echo "--- IMPORTANT IMPORTANT IMPORTANT ---" + # move back the test runner implementation if there's no file. + if [ ! -f .kokoro/test-samples-impl.sh ]; then + cp "${TMPDIR}/test-samples-impl.sh" .kokoro/test-samples-impl.sh fi +fi - if [[ $EXIT -ne 0 ]]; then - RTN=1 - echo -e "\n Testing failed: Nox returned a non-zero exit code. \n" - else - echo -e "\n Testing completed.\n" - fi - -done -cd "$ROOT" - -# Workaround for Kokoro permissions issue: delete secrets -rm testing/{test-env.sh,client-secrets.json,service-account.json} - -exit "$RTN" +exec .kokoro/test-samples-impl.sh diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a9024b15..32302e48 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -12,6 +12,6 @@ repos: hooks: - id: black - repo: https://gitlab.com/pycqa/flake8 - rev: 3.8.4 + rev: 3.9.0 hooks: - id: flake8 diff --git a/.trampolinerc b/.trampolinerc index 995ee291..383b6ec8 100644 --- a/.trampolinerc +++ b/.trampolinerc @@ -24,6 +24,7 @@ required_envvars+=( pass_down_envvars+=( "STAGING_BUCKET" "V2_STAGING_BUCKET" + "NOX_SESSION" ) # Prevent unintentional override on the default image. diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 12046067..89f4d56d 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -70,9 +70,14 @@ We use `nox `__ to instrument our tests. - To test your changes, run unit tests with ``nox``:: $ nox -s unit-2.7 - $ nox -s unit-3.7 + $ nox -s unit-3.8 $ ... +- Args to pytest can be passed through the nox command separated by a `--`. For + example, to run a single test:: + + $ nox -s unit-3.8 -- -k + .. note:: The unit tests and system tests are described in the @@ -93,8 +98,12 @@ On Debian/Ubuntu:: ************ Coding Style ************ +- We use the automatic code formatter ``black``. You can run it using + the nox session ``blacken``. This will eliminate many lint errors. Run via:: + + $ nox -s blacken -- PEP8 compliance, with exceptions defined in the linter configuration. +- PEP8 compliance is required, with exceptions defined in the linter configuration. If you have ``nox`` installed, you can test that you have not introduced any non-compliant code via:: @@ -133,13 +142,18 @@ Running System Tests - To run system tests, you can execute:: - $ nox -s system-3.7 + # Run all system tests + $ nox -s system-3.8 $ nox -s system-2.7 + # Run a single system test + $ nox -s system-3.8 -- -k + + .. note:: System tests are only configured to run under Python 2.7 and - Python 3.7. For expediency, we do not run them in older versions + Python 3.8. For expediency, we do not run them in older versions of Python 3. This alone will not run the tests. You'll need to change some local diff --git a/MANIFEST.in b/MANIFEST.in index e9e29d12..e783f4c6 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -16,10 +16,10 @@ # Generated by synthtool. DO NOT EDIT! include README.rst LICENSE -recursive-include google *.json *.proto +recursive-include google *.json *.proto py.typed recursive-include tests * global-exclude *.py[co] global-exclude __pycache__ # Exclude scripts for samples readmegen -prune scripts/readme-gen \ No newline at end of file +prune scripts/readme-gen diff --git a/UPGRADING.md b/UPGRADING.md index 9a5a84b4..60dcddc5 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -13,9 +13,9 @@ The 1.0.0 release requires Python 3.6+. > **WARNING**: Breaking change Methods expect request objects. We provide a script that will convert most common use cases. -* Install the library +* Install the library with `libcst.` ```py -python3 -m pip install google-cloud-talent +python3 -m pip install google-cloud-talent[libcst] ``` * The scripts `fixup_talent_v4beta1_keywords.py` shipped with the library. It expects @@ -155,4 +155,4 @@ request = talent_v4.SearchJobsRequest( ) for response_item in client.search_jobs(request=request).matching_jobs: # ... -``` \ No newline at end of file +``` diff --git a/docs/talent_v4/company_service.rst b/docs/talent_v4/company_service.rst new file mode 100644 index 00000000..f850f370 --- /dev/null +++ b/docs/talent_v4/company_service.rst @@ -0,0 +1,11 @@ +CompanyService +-------------------------------- + +.. automodule:: google.cloud.talent_v4.services.company_service + :members: + :inherited-members: + + +.. automodule:: google.cloud.talent_v4.services.company_service.pagers + :members: + :inherited-members: diff --git a/docs/talent_v4/completion.rst b/docs/talent_v4/completion.rst new file mode 100644 index 00000000..3044c5a8 --- /dev/null +++ b/docs/talent_v4/completion.rst @@ -0,0 +1,6 @@ +Completion +---------------------------- + +.. automodule:: google.cloud.talent_v4.services.completion + :members: + :inherited-members: diff --git a/docs/talent_v4/event_service.rst b/docs/talent_v4/event_service.rst new file mode 100644 index 00000000..1c90bae1 --- /dev/null +++ b/docs/talent_v4/event_service.rst @@ -0,0 +1,6 @@ +EventService +------------------------------ + +.. automodule:: google.cloud.talent_v4.services.event_service + :members: + :inherited-members: diff --git a/docs/talent_v4/job_service.rst b/docs/talent_v4/job_service.rst new file mode 100644 index 00000000..28d73f01 --- /dev/null +++ b/docs/talent_v4/job_service.rst @@ -0,0 +1,11 @@ +JobService +---------------------------- + +.. automodule:: google.cloud.talent_v4.services.job_service + :members: + :inherited-members: + + +.. automodule:: google.cloud.talent_v4.services.job_service.pagers + :members: + :inherited-members: diff --git a/docs/talent_v4/services.rst b/docs/talent_v4/services.rst index 5efed8a2..b2eb192c 100644 --- a/docs/talent_v4/services.rst +++ b/docs/talent_v4/services.rst @@ -1,18 +1,10 @@ Services for Google Cloud Talent v4 API ======================================= +.. toctree:: + :maxdepth: 2 -.. automodule:: google.cloud.talent_v4.services.company_service - :members: - :inherited-members: -.. automodule:: google.cloud.talent_v4.services.completion - :members: - :inherited-members: -.. automodule:: google.cloud.talent_v4.services.event_service - :members: - :inherited-members: -.. automodule:: google.cloud.talent_v4.services.job_service - :members: - :inherited-members: -.. automodule:: google.cloud.talent_v4.services.tenant_service - :members: - :inherited-members: + company_service + completion + event_service + job_service + tenant_service diff --git a/docs/talent_v4/tenant_service.rst b/docs/talent_v4/tenant_service.rst new file mode 100644 index 00000000..d38c6bcd --- /dev/null +++ b/docs/talent_v4/tenant_service.rst @@ -0,0 +1,11 @@ +TenantService +------------------------------- + +.. automodule:: google.cloud.talent_v4.services.tenant_service + :members: + :inherited-members: + + +.. automodule:: google.cloud.talent_v4.services.tenant_service.pagers + :members: + :inherited-members: diff --git a/docs/talent_v4/types.rst b/docs/talent_v4/types.rst index 559524b9..9c08edc9 100644 --- a/docs/talent_v4/types.rst +++ b/docs/talent_v4/types.rst @@ -3,4 +3,5 @@ Types for Google Cloud Talent v4 API .. automodule:: google.cloud.talent_v4.types :members: + :undoc-members: :show-inheritance: diff --git a/docs/talent_v4beta1/application_service.rst b/docs/talent_v4beta1/application_service.rst new file mode 100644 index 00000000..6539e8fd --- /dev/null +++ b/docs/talent_v4beta1/application_service.rst @@ -0,0 +1,11 @@ +ApplicationService +------------------------------------ + +.. automodule:: google.cloud.talent_v4beta1.services.application_service + :members: + :inherited-members: + + +.. automodule:: google.cloud.talent_v4beta1.services.application_service.pagers + :members: + :inherited-members: diff --git a/docs/talent_v4beta1/company_service.rst b/docs/talent_v4beta1/company_service.rst new file mode 100644 index 00000000..e2050c75 --- /dev/null +++ b/docs/talent_v4beta1/company_service.rst @@ -0,0 +1,11 @@ +CompanyService +-------------------------------- + +.. automodule:: google.cloud.talent_v4beta1.services.company_service + :members: + :inherited-members: + + +.. automodule:: google.cloud.talent_v4beta1.services.company_service.pagers + :members: + :inherited-members: diff --git a/docs/talent_v4beta1/completion.rst b/docs/talent_v4beta1/completion.rst new file mode 100644 index 00000000..764a23f3 --- /dev/null +++ b/docs/talent_v4beta1/completion.rst @@ -0,0 +1,6 @@ +Completion +---------------------------- + +.. automodule:: google.cloud.talent_v4beta1.services.completion + :members: + :inherited-members: diff --git a/docs/talent_v4beta1/event_service.rst b/docs/talent_v4beta1/event_service.rst new file mode 100644 index 00000000..8e489d4c --- /dev/null +++ b/docs/talent_v4beta1/event_service.rst @@ -0,0 +1,6 @@ +EventService +------------------------------ + +.. automodule:: google.cloud.talent_v4beta1.services.event_service + :members: + :inherited-members: diff --git a/docs/talent_v4beta1/job_service.rst b/docs/talent_v4beta1/job_service.rst new file mode 100644 index 00000000..a78f4f32 --- /dev/null +++ b/docs/talent_v4beta1/job_service.rst @@ -0,0 +1,11 @@ +JobService +---------------------------- + +.. automodule:: google.cloud.talent_v4beta1.services.job_service + :members: + :inherited-members: + + +.. automodule:: google.cloud.talent_v4beta1.services.job_service.pagers + :members: + :inherited-members: diff --git a/docs/talent_v4beta1/profile_service.rst b/docs/talent_v4beta1/profile_service.rst new file mode 100644 index 00000000..e558ed06 --- /dev/null +++ b/docs/talent_v4beta1/profile_service.rst @@ -0,0 +1,11 @@ +ProfileService +-------------------------------- + +.. automodule:: google.cloud.talent_v4beta1.services.profile_service + :members: + :inherited-members: + + +.. automodule:: google.cloud.talent_v4beta1.services.profile_service.pagers + :members: + :inherited-members: diff --git a/docs/talent_v4beta1/services.rst b/docs/talent_v4beta1/services.rst index babbaa4e..019f928f 100644 --- a/docs/talent_v4beta1/services.rst +++ b/docs/talent_v4beta1/services.rst @@ -1,24 +1,12 @@ Services for Google Cloud Talent v4beta1 API ============================================ +.. toctree:: + :maxdepth: 2 -.. automodule:: google.cloud.talent_v4beta1.services.application_service - :members: - :inherited-members: -.. automodule:: google.cloud.talent_v4beta1.services.company_service - :members: - :inherited-members: -.. automodule:: google.cloud.talent_v4beta1.services.completion - :members: - :inherited-members: -.. automodule:: google.cloud.talent_v4beta1.services.event_service - :members: - :inherited-members: -.. automodule:: google.cloud.talent_v4beta1.services.job_service - :members: - :inherited-members: -.. automodule:: google.cloud.talent_v4beta1.services.profile_service - :members: - :inherited-members: -.. automodule:: google.cloud.talent_v4beta1.services.tenant_service - :members: - :inherited-members: + application_service + company_service + completion + event_service + job_service + profile_service + tenant_service diff --git a/docs/talent_v4beta1/tenant_service.rst b/docs/talent_v4beta1/tenant_service.rst new file mode 100644 index 00000000..4de1dcfe --- /dev/null +++ b/docs/talent_v4beta1/tenant_service.rst @@ -0,0 +1,11 @@ +TenantService +------------------------------- + +.. automodule:: google.cloud.talent_v4beta1.services.tenant_service + :members: + :inherited-members: + + +.. automodule:: google.cloud.talent_v4beta1.services.tenant_service.pagers + :members: + :inherited-members: diff --git a/docs/talent_v4beta1/types.rst b/docs/talent_v4beta1/types.rst index 170f4b18..e6abbcac 100644 --- a/docs/talent_v4beta1/types.rst +++ b/docs/talent_v4beta1/types.rst @@ -3,4 +3,5 @@ Types for Google Cloud Talent v4beta1 API .. automodule:: google.cloud.talent_v4beta1.types :members: + :undoc-members: :show-inheritance: diff --git a/google/cloud/talent_v4/__init__.py b/google/cloud/talent_v4/__init__.py index 1d4b845e..b193e4de 100644 --- a/google/cloud/talent_v4/__init__.py +++ b/google/cloud/talent_v4/__init__.py @@ -127,6 +127,7 @@ "JobLevel", "JobQuery", "JobResult", + "JobServiceClient", "JobView", "ListCompaniesRequest", "ListCompaniesResponse", @@ -143,11 +144,10 @@ "SearchJobsResponse", "SpellingCorrection", "Tenant", - "TenantServiceClient", "TimestampRange", "UpdateCompanyRequest", "UpdateJobRequest", "UpdateTenantRequest", "Visibility", - "JobServiceClient", + "TenantServiceClient", ) diff --git a/google/cloud/talent_v4/services/company_service/async_client.py b/google/cloud/talent_v4/services/company_service/async_client.py index dc84e1fd..dbb65fa2 100644 --- a/google/cloud/talent_v4/services/company_service/async_client.py +++ b/google/cloud/talent_v4/services/company_service/async_client.py @@ -84,7 +84,36 @@ class CompanyServiceAsyncClient: CompanyServiceClient.parse_common_location_path ) - from_service_account_file = CompanyServiceClient.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: + CompanyServiceAsyncClient: The constructed client. + """ + return CompanyServiceClient.from_service_account_info.__func__(CompanyServiceAsyncClient, 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: + CompanyServiceAsyncClient: The constructed client. + """ + return CompanyServiceClient.from_service_account_file.__func__(CompanyServiceAsyncClient, filename, *args, **kwargs) # type: ignore + from_service_account_json = from_service_account_file @property @@ -161,7 +190,7 @@ async def create_company( r"""Creates a new company entity. Args: - request (:class:`~.company_service.CreateCompanyRequest`): + request (:class:`google.cloud.talent_v4.types.CreateCompanyRequest`): The request object. The Request of the CreateCompany method. parent (:class:`str`): @@ -171,10 +200,11 @@ async def create_company( The format is "projects/{project_id}/tenants/{tenant_id}", for example, "projects/foo/tenants/bar". + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - company (:class:`~.gct_company.Company`): + company (:class:`google.cloud.talent_v4.types.Company`): Required. The company to be created. This corresponds to the ``company`` field on the ``request`` instance; if ``request`` is provided, this @@ -187,7 +217,7 @@ async def create_company( sent along with the request as metadata. Returns: - ~.gct_company.Company: + google.cloud.talent_v4.types.Company: A Company resource represents a company in the service. A company is the entity that owns job postings, that is, @@ -248,7 +278,7 @@ async def get_company( r"""Retrieves specified company. Args: - request (:class:`~.company_service.GetCompanyRequest`): + request (:class:`google.cloud.talent_v4.types.GetCompanyRequest`): The request object. Request for getting a company by name. name (:class:`str`): @@ -259,6 +289,7 @@ async def get_company( "projects/{project_id}/tenants/{tenant_id}/companies/{company_id}", for example, "projects/api-test-project/tenants/foo/companies/bar". + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -270,7 +301,7 @@ async def get_company( sent along with the request as metadata. Returns: - ~.company.Company: + google.cloud.talent_v4.types.Company: A Company resource represents a company in the service. A company is the entity that owns job postings, that is, @@ -308,6 +339,7 @@ async def get_company( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=DEFAULT_CLIENT_INFO, @@ -338,17 +370,18 @@ async def update_company( r"""Updates specified company. Args: - request (:class:`~.company_service.UpdateCompanyRequest`): + request (:class:`google.cloud.talent_v4.types.UpdateCompanyRequest`): The request object. Request for updating a specified company. - company (:class:`~.gct_company.Company`): + company (:class:`google.cloud.talent_v4.types.Company`): Required. The company resource to replace the current resource in the system. + This corresponds to the ``company`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - update_mask (:class:`~.field_mask.FieldMask`): + update_mask (:class:`google.protobuf.field_mask_pb2.FieldMask`): Strongly recommended for the best service experience. If @@ -360,6 +393,7 @@ async def update_company( A field mask to specify the company fields to be updated. Only top level fields of [Company][google.cloud.talent.v4.Company] are supported. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -371,7 +405,7 @@ async def update_company( sent along with the request as metadata. Returns: - ~.gct_company.Company: + google.cloud.talent_v4.types.Company: A Company resource represents a company in the service. A company is the entity that owns job postings, that is, @@ -436,7 +470,7 @@ async def delete_company( it. Args: - request (:class:`~.company_service.DeleteCompanyRequest`): + request (:class:`google.cloud.talent_v4.types.DeleteCompanyRequest`): The request object. Request to delete a company. name (:class:`str`): Required. The resource name of the company to be @@ -445,6 +479,7 @@ async def delete_company( The format is "projects/{project_id}/tenants/{tenant_id}/companies/{company_id}", for example, "projects/foo/tenants/bar/companies/baz". + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -484,6 +519,7 @@ async def delete_company( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=DEFAULT_CLIENT_INFO, @@ -512,7 +548,7 @@ async def list_companies( r"""Lists all companies associated with the project. Args: - request (:class:`~.company_service.ListCompaniesRequest`): + request (:class:`google.cloud.talent_v4.types.ListCompaniesRequest`): The request object. List companies for which the client has ACL visibility. parent (:class:`str`): @@ -522,6 +558,7 @@ async def list_companies( The format is "projects/{project_id}/tenants/{tenant_id}", for example, "projects/foo/tenants/bar". + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -533,7 +570,7 @@ async def list_companies( sent along with the request as metadata. Returns: - ~.pagers.ListCompaniesAsyncPager: + google.cloud.talent_v4.services.company_service.pagers.ListCompaniesAsyncPager: The List companies response object. Iterating over this object will yield results and resolve additional pages @@ -569,6 +606,7 @@ async def list_companies( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=DEFAULT_CLIENT_INFO, diff --git a/google/cloud/talent_v4/services/company_service/client.py b/google/cloud/talent_v4/services/company_service/client.py index 7b32d9b6..10f6d998 100644 --- a/google/cloud/talent_v4/services/company_service/client.py +++ b/google/cloud/talent_v4/services/company_service/client.py @@ -116,6 +116,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: + CompanyServiceClient: 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 @@ -128,7 +144,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. + CompanyServiceClient: The constructed client. """ credentials = service_account.Credentials.from_service_account_file(filename) kwargs["credentials"] = credentials @@ -249,10 +265,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, ~.CompanyServiceTransport]): The + transport (Union[str, CompanyServiceTransport]): 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 @@ -288,21 +304,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: @@ -345,7 +357,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, ) @@ -363,20 +375,21 @@ def create_company( r"""Creates a new company entity. Args: - request (:class:`~.company_service.CreateCompanyRequest`): + request (google.cloud.talent_v4.types.CreateCompanyRequest): The request object. The Request of the CreateCompany method. - parent (:class:`str`): + parent (str): Required. Resource name of the tenant under which the company is created. The format is "projects/{project_id}/tenants/{tenant_id}", for example, "projects/foo/tenants/bar". + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - company (:class:`~.gct_company.Company`): + company (google.cloud.talent_v4.types.Company): Required. The company to be created. This corresponds to the ``company`` field on the ``request`` instance; if ``request`` is provided, this @@ -389,7 +402,7 @@ def create_company( sent along with the request as metadata. Returns: - ~.gct_company.Company: + google.cloud.talent_v4.types.Company: A Company resource represents a company in the service. A company is the entity that owns job postings, that is, @@ -451,10 +464,10 @@ def get_company( r"""Retrieves specified company. Args: - request (:class:`~.company_service.GetCompanyRequest`): + request (google.cloud.talent_v4.types.GetCompanyRequest): The request object. Request for getting a company by name. - name (:class:`str`): + name (str): Required. The resource name of the company to be retrieved. @@ -462,6 +475,7 @@ def get_company( "projects/{project_id}/tenants/{tenant_id}/companies/{company_id}", for example, "projects/api-test-project/tenants/foo/companies/bar". + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -473,7 +487,7 @@ def get_company( sent along with the request as metadata. Returns: - ~.company.Company: + google.cloud.talent_v4.types.Company: A Company resource represents a company in the service. A company is the entity that owns job postings, that is, @@ -534,17 +548,18 @@ def update_company( r"""Updates specified company. Args: - request (:class:`~.company_service.UpdateCompanyRequest`): + request (google.cloud.talent_v4.types.UpdateCompanyRequest): The request object. Request for updating a specified company. - company (:class:`~.gct_company.Company`): + company (google.cloud.talent_v4.types.Company): Required. The company resource to replace the current resource in the system. + This corresponds to the ``company`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - update_mask (:class:`~.field_mask.FieldMask`): + update_mask (google.protobuf.field_mask_pb2.FieldMask): Strongly recommended for the best service experience. If @@ -556,6 +571,7 @@ def update_company( A field mask to specify the company fields to be updated. Only top level fields of [Company][google.cloud.talent.v4.Company] are supported. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -567,7 +583,7 @@ def update_company( sent along with the request as metadata. Returns: - ~.gct_company.Company: + google.cloud.talent_v4.types.Company: A Company resource represents a company in the service. A company is the entity that owns job postings, that is, @@ -633,15 +649,16 @@ def delete_company( it. Args: - request (:class:`~.company_service.DeleteCompanyRequest`): + request (google.cloud.talent_v4.types.DeleteCompanyRequest): The request object. Request to delete a company. - name (:class:`str`): + name (str): Required. The resource name of the company to be deleted. The format is "projects/{project_id}/tenants/{tenant_id}/companies/{company_id}", for example, "projects/foo/tenants/bar/companies/baz". + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -702,16 +719,17 @@ def list_companies( r"""Lists all companies associated with the project. Args: - request (:class:`~.company_service.ListCompaniesRequest`): + request (google.cloud.talent_v4.types.ListCompaniesRequest): The request object. List companies for which the client has ACL visibility. - parent (:class:`str`): + parent (str): Required. Resource name of the tenant under which the company is created. The format is "projects/{project_id}/tenants/{tenant_id}", for example, "projects/foo/tenants/bar". + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -723,7 +741,7 @@ def list_companies( sent along with the request as metadata. Returns: - ~.pagers.ListCompaniesPager: + google.cloud.talent_v4.services.company_service.pagers.ListCompaniesPager: The List companies response object. Iterating over this object will yield results and resolve additional pages diff --git a/google/cloud/talent_v4/services/company_service/pagers.py b/google/cloud/talent_v4/services/company_service/pagers.py index 992c4b53..beac2a8b 100644 --- a/google/cloud/talent_v4/services/company_service/pagers.py +++ b/google/cloud/talent_v4/services/company_service/pagers.py @@ -15,7 +15,16 @@ # limitations under the License. # -from typing import Any, AsyncIterable, Awaitable, Callable, Iterable, Sequence, Tuple +from typing import ( + Any, + AsyncIterable, + Awaitable, + Callable, + Iterable, + Sequence, + Tuple, + Optional, +) from google.cloud.talent_v4.types import company from google.cloud.talent_v4.types import company_service @@ -25,7 +34,7 @@ class ListCompaniesPager: """A pager for iterating through ``list_companies`` requests. This class thinly wraps an initial - :class:`~.company_service.ListCompaniesResponse` object, and + :class:`google.cloud.talent_v4.types.ListCompaniesResponse` object, and provides an ``__iter__`` method to iterate through its ``companies`` field. @@ -34,7 +43,7 @@ class ListCompaniesPager: through the ``companies`` field on the corresponding responses. - All the usual :class:`~.company_service.ListCompaniesResponse` + All the usual :class:`google.cloud.talent_v4.types.ListCompaniesResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -52,9 +61,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.company_service.ListCompaniesRequest`): + request (google.cloud.talent_v4.types.ListCompaniesRequest): The initial request object. - response (:class:`~.company_service.ListCompaniesResponse`): + response (google.cloud.talent_v4.types.ListCompaniesResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -87,7 +96,7 @@ class ListCompaniesAsyncPager: """A pager for iterating through ``list_companies`` requests. This class thinly wraps an initial - :class:`~.company_service.ListCompaniesResponse` object, and + :class:`google.cloud.talent_v4.types.ListCompaniesResponse` object, and provides an ``__aiter__`` method to iterate through its ``companies`` field. @@ -96,7 +105,7 @@ class ListCompaniesAsyncPager: through the ``companies`` field on the corresponding responses. - All the usual :class:`~.company_service.ListCompaniesResponse` + All the usual :class:`google.cloud.talent_v4.types.ListCompaniesResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -114,9 +123,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.company_service.ListCompaniesRequest`): + request (google.cloud.talent_v4.types.ListCompaniesRequest): The initial request object. - response (:class:`~.company_service.ListCompaniesResponse`): + response (google.cloud.talent_v4.types.ListCompaniesResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. diff --git a/google/cloud/talent_v4/services/company_service/transports/base.py b/google/cloud/talent_v4/services/company_service/transports/base.py index 587ed0c6..ccaaff88 100644 --- a/google/cloud/talent_v4/services/company_service/transports/base.py +++ b/google/cloud/talent_v4/services/company_service/transports/base.py @@ -73,10 +73,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. @@ -84,6 +84,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: @@ -93,20 +96,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 = { @@ -122,6 +122,7 @@ def _prep_wrapped_messages(self, client_info): predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=client_info, @@ -138,6 +139,7 @@ def _prep_wrapped_messages(self, client_info): predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=client_info, @@ -151,6 +153,7 @@ def _prep_wrapped_messages(self, client_info): predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=client_info, diff --git a/google/cloud/talent_v4/services/company_service/transports/grpc.py b/google/cloud/talent_v4/services/company_service/transports/grpc.py index 09068973..fe1e7dd2 100644 --- a/google/cloud/talent_v4/services/company_service/transports/grpc.py +++ b/google/cloud/talent_v4/services/company_service/transports/grpc.py @@ -61,6 +61,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: @@ -91,6 +92,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): @@ -105,72 +110,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), @@ -178,17 +171,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( @@ -202,7 +186,7 @@ def create_channel( ) -> grpc.Channel: """Create and return a gRPC channel object. Args: - address (Optional[str]): The host for the channel to use. + host (Optional[str]): The host for the channel to use. credentials (Optional[~.Credentials]): The authorization credentials to attach to requests. These credentials identify this application to the service. If diff --git a/google/cloud/talent_v4/services/company_service/transports/grpc_asyncio.py b/google/cloud/talent_v4/services/company_service/transports/grpc_asyncio.py index fbf3fa4a..0643fff5 100644 --- a/google/cloud/talent_v4/services/company_service/transports/grpc_asyncio.py +++ b/google/cloud/talent_v4/services/company_service/transports/grpc_asyncio.py @@ -65,7 +65,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 @@ -105,6 +105,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: @@ -136,12 +137,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: @@ -150,72 +155,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), @@ -223,17 +216,8 @@ def __init__( ], ) - # Run the base constructor. - super().__init__( - host=host, - credentials=credentials, - credentials_file=credentials_file, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - client_info=client_info, - ) - - self._stubs = {} + # 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/talent_v4/services/completion/async_client.py b/google/cloud/talent_v4/services/completion/async_client.py index 2c91e861..16c1c698 100644 --- a/google/cloud/talent_v4/services/completion/async_client.py +++ b/google/cloud/talent_v4/services/completion/async_client.py @@ -72,7 +72,36 @@ class CompletionAsyncClient: CompletionClient.parse_common_location_path ) - from_service_account_file = CompletionClient.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: + CompletionAsyncClient: The constructed client. + """ + return CompletionClient.from_service_account_info.__func__(CompletionAsyncClient, 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: + CompletionAsyncClient: The constructed client. + """ + return CompletionClient.from_service_account_file.__func__(CompletionAsyncClient, filename, *args, **kwargs) # type: ignore + from_service_account_json = from_service_account_file @property @@ -149,7 +178,7 @@ async def complete_query( complete search box. Args: - request (:class:`~.completion_service.CompleteQueryRequest`): + request (:class:`google.cloud.talent_v4.types.CompleteQueryRequest`): The request object. Auto-complete parameters. retry (google.api_core.retry.Retry): Designation of what errors, if any, @@ -159,7 +188,7 @@ async def complete_query( sent along with the request as metadata. Returns: - ~.completion_service.CompleteQueryResponse: + google.cloud.talent_v4.types.CompleteQueryResponse: Response of auto-complete query. """ # Create or coerce a protobuf request object. @@ -177,6 +206,7 @@ async def complete_query( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=DEFAULT_CLIENT_INFO, diff --git a/google/cloud/talent_v4/services/completion/client.py b/google/cloud/talent_v4/services/completion/client.py index 3d3b0589..6eacd4ca 100644 --- a/google/cloud/talent_v4/services/completion/client.py +++ b/google/cloud/talent_v4/services/completion/client.py @@ -108,6 +108,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: + CompletionClient: 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 @@ -120,7 +136,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. + CompletionClient: The constructed client. """ credentials = service_account.Credentials.from_service_account_file(filename) kwargs["credentials"] = credentials @@ -241,10 +257,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, ~.CompletionTransport]): The + transport (Union[str, CompletionTransport]): 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 @@ -280,21 +296,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: @@ -337,7 +349,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, ) @@ -355,7 +367,7 @@ def complete_query( complete search box. Args: - request (:class:`~.completion_service.CompleteQueryRequest`): + request (google.cloud.talent_v4.types.CompleteQueryRequest): The request object. Auto-complete parameters. retry (google.api_core.retry.Retry): Designation of what errors, if any, @@ -365,7 +377,7 @@ def complete_query( sent along with the request as metadata. Returns: - ~.completion_service.CompleteQueryResponse: + google.cloud.talent_v4.types.CompleteQueryResponse: Response of auto-complete query. """ # Create or coerce a protobuf request object. diff --git a/google/cloud/talent_v4/services/completion/transports/base.py b/google/cloud/talent_v4/services/completion/transports/base.py index efb1e327..e8fdb64a 100644 --- a/google/cloud/talent_v4/services/completion/transports/base.py +++ b/google/cloud/talent_v4/services/completion/transports/base.py @@ -70,10 +70,10 @@ def __init__( scope (Optional[Sequence[str]]): A list of scopes. quota_project_id (Optional[str]): An optional project to use for billing and quota. - client_info (google.api_core.gapic_v1.client_info.ClientInfo): - The client info used to send a user-agent string along with - API requests. If ``None``, then default info will be used. - Generally, you only need to set this if you're developing + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing your own client library. """ # Save the hostname. Default to port 443 (HTTPS) if none is specified. @@ -81,6 +81,9 @@ def __init__( host += ":443" self._host = host + # Save the scopes. + self._scopes = scopes or self.AUTH_SCOPES + # If no credentials are provided, then determine the appropriate # defaults. if credentials and credentials_file: @@ -90,20 +93,17 @@ def __init__( if credentials_file is not None: credentials, _ = auth.load_credentials_from_file( - credentials_file, scopes=scopes, quota_project_id=quota_project_id + credentials_file, scopes=self._scopes, quota_project_id=quota_project_id ) elif credentials is None: credentials, _ = auth.default( - scopes=scopes, quota_project_id=quota_project_id + scopes=self._scopes, quota_project_id=quota_project_id ) # Save the credentials. self._credentials = credentials - # Lifted into its own function so it can be stubbed out during tests. - self._prep_wrapped_messages(client_info) - def _prep_wrapped_messages(self, client_info): # Precompute the wrapped methods. self._wrapped_methods = { @@ -116,6 +116,7 @@ def _prep_wrapped_messages(self, client_info): predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=client_info, diff --git a/google/cloud/talent_v4/services/completion/transports/grpc.py b/google/cloud/talent_v4/services/completion/transports/grpc.py index 08fe29d3..7732a1dc 100644 --- a/google/cloud/talent_v4/services/completion/transports/grpc.py +++ b/google/cloud/talent_v4/services/completion/transports/grpc.py @@ -57,6 +57,7 @@ def __init__( api_mtls_endpoint: str = None, client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, quota_project_id: Optional[str] = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: @@ -87,6 +88,10 @@ def __init__( ``api_mtls_endpoint`` is None. ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials for grpc channel. It is ignored if ``channel`` is provided. + client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]): + A callback to provide client certificate bytes and private key bytes, + both in PEM format. It is used to configure mutual TLS channel. It is + ignored if ``channel`` or ``ssl_channel_credentials`` is provided. quota_project_id (Optional[str]): An optional project to use for billing and quota. client_info (google.api_core.gapic_v1.client_info.ClientInfo): @@ -101,72 +106,60 @@ def __init__( google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` and ``credentials_file`` are passed. """ + self._grpc_channel = None self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} + + if api_mtls_endpoint: + warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning) + if client_cert_source: + warnings.warn("client_cert_source is deprecated", DeprecationWarning) if channel: - # Sanity check: Ensure that channel and credentials are not both - # provided. + # Ignore credentials if a channel was passed. credentials = False - # If a channel was explicitly provided, set it. self._grpc_channel = channel self._ssl_channel_credentials = None - elif api_mtls_endpoint: - warnings.warn( - "api_mtls_endpoint and client_cert_source are deprecated", - DeprecationWarning, - ) - - host = ( - api_mtls_endpoint - if ":" in api_mtls_endpoint - else api_mtls_endpoint + ":443" - ) - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) + else: + if api_mtls_endpoint: + host = api_mtls_endpoint + + # Create SSL credentials with client_cert_source or application + # default SSL credentials. + if client_cert_source: + cert, key = client_cert_source() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + else: + self._ssl_channel_credentials = SslCredentials().ssl_credentials - # Create SSL credentials with client_cert_source or application - # default SSL credentials. - if client_cert_source: - cert, key = client_cert_source() - ssl_credentials = grpc.ssl_channel_credentials( - certificate_chain=cert, private_key=key - ) else: - ssl_credentials = SslCredentials().ssl_credentials - - # create a new channel. The provided one is ignored. - self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, - credentials_file=credentials_file, - ssl_credentials=ssl_credentials, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - options=[ - ("grpc.max_send_message_length", -1), - ("grpc.max_receive_message_length", -1), - ], - ) - self._ssl_channel_credentials = ssl_credentials - else: - host = host if ":" in host else host + ":443" + if client_cert_source_for_mtls and not ssl_channel_credentials: + cert, key = client_cert_source_for_mtls() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) + # The base transport sets the host, credentials and scopes + super().__init__( + host=host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + client_info=client_info, + ) - # create a new channel. The provided one is ignored. + if not self._grpc_channel: self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, + self._host, + credentials=self._credentials, credentials_file=credentials_file, - ssl_credentials=ssl_channel_credentials, - scopes=scopes or self.AUTH_SCOPES, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, quota_project_id=quota_project_id, options=[ ("grpc.max_send_message_length", -1), @@ -174,17 +167,8 @@ def __init__( ], ) - self._stubs = {} # type: Dict[str, Callable] - - # Run the base constructor. - super().__init__( - host=host, - credentials=credentials, - credentials_file=credentials_file, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - client_info=client_info, - ) + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) @classmethod def create_channel( @@ -198,7 +182,7 @@ def create_channel( ) -> grpc.Channel: """Create and return a gRPC channel object. Args: - address (Optional[str]): The host for the channel to use. + host (Optional[str]): The host for the channel to use. credentials (Optional[~.Credentials]): The authorization credentials to attach to requests. These credentials identify this application to the service. If diff --git a/google/cloud/talent_v4/services/completion/transports/grpc_asyncio.py b/google/cloud/talent_v4/services/completion/transports/grpc_asyncio.py index d5a0ef57..d23bd831 100644 --- a/google/cloud/talent_v4/services/completion/transports/grpc_asyncio.py +++ b/google/cloud/talent_v4/services/completion/transports/grpc_asyncio.py @@ -61,7 +61,7 @@ def create_channel( ) -> aio.Channel: """Create and return a gRPC AsyncIO channel object. Args: - address (Optional[str]): The host for the channel to use. + host (Optional[str]): The host for the channel to use. credentials (Optional[~.Credentials]): The authorization credentials to attach to requests. These credentials identify this application to the service. If @@ -101,6 +101,7 @@ def __init__( api_mtls_endpoint: str = None, client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, quota_project_id=None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: @@ -132,12 +133,16 @@ def __init__( ``api_mtls_endpoint`` is None. ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials for grpc channel. It is ignored if ``channel`` is provided. + client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]): + A callback to provide client certificate bytes and private key bytes, + both in PEM format. It is used to configure mutual TLS channel. It is + ignored if ``channel`` or ``ssl_channel_credentials`` is provided. quota_project_id (Optional[str]): An optional project to use for billing and quota. - client_info (google.api_core.gapic_v1.client_info.ClientInfo): - The client info used to send a user-agent string along with - API requests. If ``None``, then default info will be used. - Generally, you only need to set this if you're developing + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing your own client library. Raises: @@ -146,72 +151,60 @@ def __init__( google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` and ``credentials_file`` are passed. """ + self._grpc_channel = None self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} + + if api_mtls_endpoint: + warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning) + if client_cert_source: + warnings.warn("client_cert_source is deprecated", DeprecationWarning) if channel: - # Sanity check: Ensure that channel and credentials are not both - # provided. + # Ignore credentials if a channel was passed. credentials = False - # If a channel was explicitly provided, set it. self._grpc_channel = channel self._ssl_channel_credentials = None - elif api_mtls_endpoint: - warnings.warn( - "api_mtls_endpoint and client_cert_source are deprecated", - DeprecationWarning, - ) - - host = ( - api_mtls_endpoint - if ":" in api_mtls_endpoint - else api_mtls_endpoint + ":443" - ) - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) + else: + if api_mtls_endpoint: + host = api_mtls_endpoint + + # Create SSL credentials with client_cert_source or application + # default SSL credentials. + if client_cert_source: + cert, key = client_cert_source() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + else: + self._ssl_channel_credentials = SslCredentials().ssl_credentials - # Create SSL credentials with client_cert_source or application - # default SSL credentials. - if client_cert_source: - cert, key = client_cert_source() - ssl_credentials = grpc.ssl_channel_credentials( - certificate_chain=cert, private_key=key - ) else: - ssl_credentials = SslCredentials().ssl_credentials - - # create a new channel. The provided one is ignored. - self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, - credentials_file=credentials_file, - ssl_credentials=ssl_credentials, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - options=[ - ("grpc.max_send_message_length", -1), - ("grpc.max_receive_message_length", -1), - ], - ) - self._ssl_channel_credentials = ssl_credentials - else: - host = host if ":" in host else host + ":443" + if client_cert_source_for_mtls and not ssl_channel_credentials: + cert, key = client_cert_source_for_mtls() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) + # The base transport sets the host, credentials and scopes + super().__init__( + host=host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + client_info=client_info, + ) - # create a new channel. The provided one is ignored. + if not self._grpc_channel: self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, + self._host, + credentials=self._credentials, credentials_file=credentials_file, - ssl_credentials=ssl_channel_credentials, - scopes=scopes or self.AUTH_SCOPES, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, quota_project_id=quota_project_id, options=[ ("grpc.max_send_message_length", -1), @@ -219,17 +212,8 @@ def __init__( ], ) - # Run the base constructor. - super().__init__( - host=host, - credentials=credentials, - credentials_file=credentials_file, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - client_info=client_info, - ) - - self._stubs = {} + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) @property def grpc_channel(self) -> aio.Channel: diff --git a/google/cloud/talent_v4/services/event_service/async_client.py b/google/cloud/talent_v4/services/event_service/async_client.py index 8a6a6e41..c6237025 100644 --- a/google/cloud/talent_v4/services/event_service/async_client.py +++ b/google/cloud/talent_v4/services/event_service/async_client.py @@ -73,7 +73,36 @@ class EventServiceAsyncClient: EventServiceClient.parse_common_location_path ) - from_service_account_file = EventServiceClient.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: + EventServiceAsyncClient: The constructed client. + """ + return EventServiceClient.from_service_account_info.__func__(EventServiceAsyncClient, 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: + EventServiceAsyncClient: The constructed client. + """ + return EventServiceClient.from_service_account_file.__func__(EventServiceAsyncClient, filename, *args, **kwargs) # type: ignore + from_service_account_json = from_service_account_file @property @@ -156,7 +185,7 @@ async def create_client_event( about self service tools. Args: - request (:class:`~.event_service.CreateClientEventRequest`): + request (:class:`google.cloud.talent_v4.types.CreateClientEventRequest`): The request object. The report event request. parent (:class:`str`): Required. Resource name of the tenant under which the @@ -165,13 +194,15 @@ async def create_client_event( The format is "projects/{project_id}/tenants/{tenant_id}", for example, "projects/foo/tenants/bar". + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - client_event (:class:`~.event.ClientEvent`): + client_event (:class:`google.cloud.talent_v4.types.ClientEvent`): Required. Events issued when end user interacts with customer's application that uses Cloud Talent Solution. + This corresponds to the ``client_event`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -183,7 +214,7 @@ async def create_client_event( sent along with the request as metadata. Returns: - ~.event.ClientEvent: + google.cloud.talent_v4.types.ClientEvent: An event issued when an end user interacts with the application that implements Cloud Talent Solution. diff --git a/google/cloud/talent_v4/services/event_service/client.py b/google/cloud/talent_v4/services/event_service/client.py index 06f1fd4f..9cae6703 100644 --- a/google/cloud/talent_v4/services/event_service/client.py +++ b/google/cloud/talent_v4/services/event_service/client.py @@ -109,6 +109,22 @@ def _get_default_mtls_endpoint(api_endpoint): DEFAULT_ENDPOINT ) + @classmethod + def from_service_account_info(cls, info: dict, *args, **kwargs): + """Creates an instance of this client using the provided credentials info. + + Args: + info (dict): The service account private key info. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + EventServiceClient: The constructed client. + """ + credentials = service_account.Credentials.from_service_account_info(info) + kwargs["credentials"] = credentials + return cls(*args, **kwargs) + @classmethod def from_service_account_file(cls, filename: str, *args, **kwargs): """Creates an instance of this client using the provided credentials @@ -121,7 +137,7 @@ def from_service_account_file(cls, filename: str, *args, **kwargs): kwargs: Additional arguments to pass to the constructor. Returns: - {@api.name}: The constructed client. + EventServiceClient: The constructed client. """ credentials = service_account.Credentials.from_service_account_file(filename) kwargs["credentials"] = credentials @@ -226,10 +242,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, ~.EventServiceTransport]): The + transport (Union[str, EventServiceTransport]): 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 @@ -265,21 +281,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: @@ -322,7 +334,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, ) @@ -346,22 +358,24 @@ def create_client_event( about self service tools. Args: - request (:class:`~.event_service.CreateClientEventRequest`): + request (google.cloud.talent_v4.types.CreateClientEventRequest): The request object. The report event request. - parent (:class:`str`): + parent (str): Required. Resource name of the tenant under which the event is created. The format is "projects/{project_id}/tenants/{tenant_id}", for example, "projects/foo/tenants/bar". + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - client_event (:class:`~.event.ClientEvent`): + client_event (google.cloud.talent_v4.types.ClientEvent): Required. Events issued when end user interacts with customer's application that uses Cloud Talent Solution. + This corresponds to the ``client_event`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -373,7 +387,7 @@ def create_client_event( sent along with the request as metadata. Returns: - ~.event.ClientEvent: + google.cloud.talent_v4.types.ClientEvent: An event issued when an end user interacts with the application that implements Cloud Talent Solution. diff --git a/google/cloud/talent_v4/services/event_service/transports/base.py b/google/cloud/talent_v4/services/event_service/transports/base.py index 88f54bbc..5f0f004d 100644 --- a/google/cloud/talent_v4/services/event_service/transports/base.py +++ b/google/cloud/talent_v4/services/event_service/transports/base.py @@ -71,10 +71,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. @@ -82,6 +82,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: @@ -91,20 +94,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 = { diff --git a/google/cloud/talent_v4/services/event_service/transports/grpc.py b/google/cloud/talent_v4/services/event_service/transports/grpc.py index c6dfa670..05c80ebc 100644 --- a/google/cloud/talent_v4/services/event_service/transports/grpc.py +++ b/google/cloud/talent_v4/services/event_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" - ) - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) + else: + if api_mtls_endpoint: + host = api_mtls_endpoint + + # Create SSL credentials with client_cert_source or application + # default SSL credentials. + if client_cert_source: + cert, key = client_cert_source() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + else: + self._ssl_channel_credentials = SslCredentials().ssl_credentials - # Create SSL credentials with client_cert_source or application - # default SSL credentials. - if client_cert_source: - cert, key = client_cert_source() - ssl_credentials = grpc.ssl_channel_credentials( - certificate_chain=cert, private_key=key - ) else: - ssl_credentials = SslCredentials().ssl_credentials - - # create a new channel. The provided one is ignored. - self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, - credentials_file=credentials_file, - ssl_credentials=ssl_credentials, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - options=[ - ("grpc.max_send_message_length", -1), - ("grpc.max_receive_message_length", -1), - ], - ) - self._ssl_channel_credentials = ssl_credentials - else: - host = host if ":" in host else host + ":443" + if client_cert_source_for_mtls and not ssl_channel_credentials: + cert, key = client_cert_source_for_mtls() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) + # The base transport sets the host, credentials and scopes + super().__init__( + host=host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + client_info=client_info, + ) - # create a new channel. The provided one is ignored. + if not self._grpc_channel: self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, + self._host, + credentials=self._credentials, credentials_file=credentials_file, - ssl_credentials=ssl_channel_credentials, - scopes=scopes or self.AUTH_SCOPES, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, quota_project_id=quota_project_id, options=[ ("grpc.max_send_message_length", -1), @@ -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/talent_v4/services/event_service/transports/grpc_asyncio.py b/google/cloud/talent_v4/services/event_service/transports/grpc_asyncio.py index 38de85b0..302f0083 100644 --- a/google/cloud/talent_v4/services/event_service/transports/grpc_asyncio.py +++ b/google/cloud/talent_v4/services/event_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" - ) - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) + else: + if api_mtls_endpoint: + host = api_mtls_endpoint + + # Create SSL credentials with client_cert_source or application + # default SSL credentials. + if client_cert_source: + cert, key = client_cert_source() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + else: + self._ssl_channel_credentials = SslCredentials().ssl_credentials - # Create SSL credentials with client_cert_source or application - # default SSL credentials. - if client_cert_source: - cert, key = client_cert_source() - ssl_credentials = grpc.ssl_channel_credentials( - certificate_chain=cert, private_key=key - ) else: - ssl_credentials = SslCredentials().ssl_credentials - - # create a new channel. The provided one is ignored. - self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, - credentials_file=credentials_file, - ssl_credentials=ssl_credentials, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - options=[ - ("grpc.max_send_message_length", -1), - ("grpc.max_receive_message_length", -1), - ], - ) - self._ssl_channel_credentials = ssl_credentials - else: - host = host if ":" in host else host + ":443" + if client_cert_source_for_mtls and not ssl_channel_credentials: + cert, key = client_cert_source_for_mtls() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) + # The base transport sets the host, credentials and scopes + super().__init__( + host=host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + client_info=client_info, + ) - # create a new channel. The provided one is ignored. + if not self._grpc_channel: self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, + self._host, + credentials=self._credentials, credentials_file=credentials_file, - ssl_credentials=ssl_channel_credentials, - scopes=scopes or self.AUTH_SCOPES, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, quota_project_id=quota_project_id, options=[ ("grpc.max_send_message_length", -1), @@ -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/talent_v4/services/job_service/async_client.py b/google/cloud/talent_v4/services/job_service/async_client.py index ec420503..06bee535 100644 --- a/google/cloud/talent_v4/services/job_service/async_client.py +++ b/google/cloud/talent_v4/services/job_service/async_client.py @@ -84,7 +84,36 @@ class JobServiceAsyncClient: JobServiceClient.parse_common_location_path ) - from_service_account_file = JobServiceClient.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: + JobServiceAsyncClient: The constructed client. + """ + return JobServiceClient.from_service_account_info.__func__(JobServiceAsyncClient, 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: + JobServiceAsyncClient: The constructed client. + """ + return JobServiceClient.from_service_account_file.__func__(JobServiceAsyncClient, filename, *args, **kwargs) # type: ignore + from_service_account_json = from_service_account_file @property @@ -163,7 +192,7 @@ async def create_job( but it may take up to 5 minutes. Args: - request (:class:`~.job_service.CreateJobRequest`): + request (:class:`google.cloud.talent_v4.types.CreateJobRequest`): The request object. Create job request. parent (:class:`str`): Required. The resource name of the tenant under which @@ -172,10 +201,11 @@ async def create_job( The format is "projects/{project_id}/tenants/{tenant_id}". For example, "projects/foo/tenants/bar". + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - job (:class:`~.gct_job.Job`): + job (:class:`google.cloud.talent_v4.types.Job`): Required. The Job to be created. This corresponds to the ``job`` field on the ``request`` instance; if ``request`` is provided, this @@ -188,11 +218,11 @@ async def create_job( sent along with the request as metadata. Returns: - ~.gct_job.Job: - A Job resource represents a job posting (also referred - to as a "job listing" or "job requisition"). A job - belongs to a [Company][google.cloud.talent.v4.Company], - which is the hiring entity responsible for the job. + google.cloud.talent_v4.types.Job: + A Job resource represents a job posting (also referred to as a "job listing" + or "job requisition"). A job belongs to a + [Company][google.cloud.talent.v4.Company], which is + the hiring entity responsible for the job. """ # Create or coerce a protobuf request object. @@ -248,7 +278,7 @@ async def batch_create_jobs( r"""Begins executing a batch create jobs operation. Args: - request (:class:`~.job_service.BatchCreateJobsRequest`): + request (:class:`google.cloud.talent_v4.types.BatchCreateJobsRequest`): The request object. Request to create a batch of jobs. parent (:class:`str`): Required. The resource name of the tenant under which @@ -257,13 +287,15 @@ async def batch_create_jobs( The format is "projects/{project_id}/tenants/{tenant_id}". For example, "projects/foo/tenants/bar". + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - jobs (:class:`Sequence[~.job.Job]`): + jobs (:class:`Sequence[google.cloud.talent_v4.types.Job]`): Required. The jobs to be created. A maximum of 200 jobs can be created in a batch. + This corresponds to the ``jobs`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -275,16 +307,13 @@ async def batch_create_jobs( sent along with the request as metadata. Returns: - ~.operation_async.AsyncOperation: + google.api_core.operation_async.AsyncOperation: An object representing a long-running operation. - The result type for the operation will be - :class:``~.job_service.BatchCreateJobsResponse``: The - result of - [JobService.BatchCreateJobs][google.cloud.talent.v4.JobService.BatchCreateJobs]. - It's used to replace - [google.longrunning.Operation.response][google.longrunning.Operation.response] - in case of success. + The result type for the operation will be :class:`google.cloud.talent_v4.types.BatchCreateJobsResponse` The result of [JobService.BatchCreateJobs][google.cloud.talent.v4.JobService.BatchCreateJobs]. It's used to + replace + [google.longrunning.Operation.response][google.longrunning.Operation.response] + in case of success. """ # Create or coerce a protobuf request object. @@ -349,7 +378,7 @@ async def get_job( recently EXPIRED within the last 90 days. Args: - request (:class:`~.job_service.GetJobRequest`): + request (:class:`google.cloud.talent_v4.types.GetJobRequest`): The request object. Get job request. name (:class:`str`): Required. The resource name of the job to retrieve. @@ -357,6 +386,7 @@ async def get_job( The format is "projects/{project_id}/tenants/{tenant_id}/jobs/{job_id}". For example, "projects/foo/tenants/bar/jobs/baz". + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -368,11 +398,11 @@ async def get_job( sent along with the request as metadata. Returns: - ~.job.Job: - A Job resource represents a job posting (also referred - to as a "job listing" or "job requisition"). A job - belongs to a [Company][google.cloud.talent.v4.Company], - which is the hiring entity responsible for the job. + google.cloud.talent_v4.types.Job: + A Job resource represents a job posting (also referred to as a "job listing" + or "job requisition"). A job belongs to a + [Company][google.cloud.talent.v4.Company], which is + the hiring entity responsible for the job. """ # Create or coerce a protobuf request object. @@ -404,6 +434,7 @@ async def get_job( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=DEFAULT_CLIENT_INFO, @@ -437,14 +468,14 @@ async def update_job( minutes. Args: - request (:class:`~.job_service.UpdateJobRequest`): + request (:class:`google.cloud.talent_v4.types.UpdateJobRequest`): The request object. Update job request. - job (:class:`~.gct_job.Job`): + job (:class:`google.cloud.talent_v4.types.Job`): Required. The Job to be updated. This corresponds to the ``job`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - update_mask (:class:`~.field_mask.FieldMask`): + update_mask (:class:`google.protobuf.field_mask_pb2.FieldMask`): Strongly recommended for the best service experience. If @@ -456,6 +487,7 @@ async def update_job( A field mask to restrict the fields that are updated. Only top level fields of [Job][google.cloud.talent.v4.Job] are supported. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -467,11 +499,11 @@ async def update_job( sent along with the request as metadata. Returns: - ~.gct_job.Job: - A Job resource represents a job posting (also referred - to as a "job listing" or "job requisition"). A job - belongs to a [Company][google.cloud.talent.v4.Company], - which is the hiring entity responsible for the job. + google.cloud.talent_v4.types.Job: + A Job resource represents a job posting (also referred to as a "job listing" + or "job requisition"). A job belongs to a + [Company][google.cloud.talent.v4.Company], which is + the hiring entity responsible for the job. """ # Create or coerce a protobuf request object. @@ -527,7 +559,7 @@ async def batch_update_jobs( r"""Begins executing a batch update jobs operation. Args: - request (:class:`~.job_service.BatchUpdateJobsRequest`): + request (:class:`google.cloud.talent_v4.types.BatchUpdateJobsRequest`): The request object. Request to update a batch of jobs. parent (:class:`str`): Required. The resource name of the tenant under which @@ -536,13 +568,15 @@ async def batch_update_jobs( The format is "projects/{project_id}/tenants/{tenant_id}". For example, "projects/foo/tenants/bar". + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - jobs (:class:`Sequence[~.job.Job]`): + jobs (:class:`Sequence[google.cloud.talent_v4.types.Job]`): Required. The jobs to be updated. A maximum of 200 jobs can be updated in a batch. + This corresponds to the ``jobs`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -554,16 +588,13 @@ async def batch_update_jobs( sent along with the request as metadata. Returns: - ~.operation_async.AsyncOperation: + google.api_core.operation_async.AsyncOperation: An object representing a long-running operation. - The result type for the operation will be - :class:``~.job_service.BatchUpdateJobsResponse``: The - result of - [JobService.BatchUpdateJobs][google.cloud.talent.v4.JobService.BatchUpdateJobs]. - It's used to replace - [google.longrunning.Operation.response][google.longrunning.Operation.response] - in case of success. + The result type for the operation will be :class:`google.cloud.talent_v4.types.BatchUpdateJobsResponse` The result of [JobService.BatchUpdateJobs][google.cloud.talent.v4.JobService.BatchUpdateJobs]. It's used to + replace + [google.longrunning.Operation.response][google.longrunning.Operation.response] + in case of success. """ # Create or coerce a protobuf request object. @@ -629,7 +660,7 @@ async def delete_job( seconds, but it may take up to 5 minutes. Args: - request (:class:`~.job_service.DeleteJobRequest`): + request (:class:`google.cloud.talent_v4.types.DeleteJobRequest`): The request object. Delete job request. name (:class:`str`): Required. The resource name of the job to be deleted. @@ -637,6 +668,7 @@ async def delete_job( The format is "projects/{project_id}/tenants/{tenant_id}/jobs/{job_id}". For example, "projects/foo/tenants/bar/jobs/baz". + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -676,6 +708,7 @@ async def delete_job( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=DEFAULT_CLIENT_INFO, @@ -705,7 +738,7 @@ async def batch_delete_jobs( r"""Begins executing a batch delete jobs operation. Args: - request (:class:`~.job_service.BatchDeleteJobsRequest`): + request (:class:`google.cloud.talent_v4.types.BatchDeleteJobsRequest`): The request object. Request to delete a batch of jobs. parent (:class:`str`): Required. The resource name of the tenant under which @@ -717,6 +750,7 @@ async def batch_delete_jobs( The parent of all of the jobs specified in ``names`` must match this field. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -728,6 +762,7 @@ async def batch_delete_jobs( For example, "projects/foo/tenants/bar/jobs/baz". A maximum of 200 jobs can be deleted in a batch. + This corresponds to the ``names`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -739,16 +774,13 @@ async def batch_delete_jobs( sent along with the request as metadata. Returns: - ~.operation_async.AsyncOperation: + google.api_core.operation_async.AsyncOperation: An object representing a long-running operation. - The result type for the operation will be - :class:``~.job_service.BatchDeleteJobsResponse``: The - result of - [JobService.BatchDeleteJobs][google.cloud.talent.v4.JobService.BatchDeleteJobs]. - It's used to replace - [google.longrunning.Operation.response][google.longrunning.Operation.response] - in case of success. + The result type for the operation will be :class:`google.cloud.talent_v4.types.BatchDeleteJobsResponse` The result of [JobService.BatchDeleteJobs][google.cloud.talent.v4.JobService.BatchDeleteJobs]. It's used to + replace + [google.longrunning.Operation.response][google.longrunning.Operation.response] + in case of success. """ # Create or coerce a protobuf request object. @@ -813,7 +845,7 @@ async def list_jobs( r"""Lists jobs by filter. Args: - request (:class:`~.job_service.ListJobsRequest`): + request (:class:`google.cloud.talent_v4.types.ListJobsRequest`): The request object. List jobs request. parent (:class:`str`): Required. The resource name of the tenant under which @@ -822,6 +854,7 @@ async def list_jobs( The format is "projects/{project_id}/tenants/{tenant_id}". For example, "projects/foo/tenants/bar". + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -847,7 +880,8 @@ async def list_jobs( requisitionId = "req-1" - companyName = "projects/foo/tenants/bar/companies/baz" AND status = - "EXPIRED". + "EXPIRED" + This corresponds to the ``filter`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -859,7 +893,7 @@ async def list_jobs( sent along with the request as metadata. Returns: - ~.pagers.ListJobsAsyncPager: + google.cloud.talent_v4.services.job_service.pagers.ListJobsAsyncPager: List jobs response. Iterating over this object will yield results and resolve additional pages @@ -897,6 +931,7 @@ async def list_jobs( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=DEFAULT_CLIENT_INFO, @@ -937,7 +972,7 @@ async def search_jobs( has permission to search against. Args: - request (:class:`~.job_service.SearchJobsRequest`): + request (:class:`google.cloud.talent_v4.types.SearchJobsRequest`): The request object. The Request body of the `SearchJobs` call. @@ -948,7 +983,7 @@ async def search_jobs( sent along with the request as metadata. Returns: - ~.job_service.SearchJobsResponse: + google.cloud.talent_v4.types.SearchJobsResponse: Response for SearchJob method. """ # Create or coerce a protobuf request object. @@ -998,7 +1033,7 @@ async def search_jobs_for_alert( permission to search against. Args: - request (:class:`~.job_service.SearchJobsRequest`): + request (:class:`google.cloud.talent_v4.types.SearchJobsRequest`): The request object. The Request body of the `SearchJobs` call. @@ -1009,7 +1044,7 @@ async def search_jobs_for_alert( sent along with the request as metadata. Returns: - ~.job_service.SearchJobsResponse: + google.cloud.talent_v4.types.SearchJobsResponse: Response for SearchJob method. """ # Create or coerce a protobuf request object. diff --git a/google/cloud/talent_v4/services/job_service/client.py b/google/cloud/talent_v4/services/job_service/client.py index 0e8ec2b0..8a43c082 100644 --- a/google/cloud/talent_v4/services/job_service/client.py +++ b/google/cloud/talent_v4/services/job_service/client.py @@ -118,6 +118,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: + JobServiceClient: 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 @@ -130,7 +146,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. + JobServiceClient: The constructed client. """ credentials = service_account.Credentials.from_service_account_file(filename) kwargs["credentials"] = credentials @@ -267,10 +283,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, ~.JobServiceTransport]): The + transport (Union[str, JobServiceTransport]): 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 @@ -306,21 +322,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: @@ -363,7 +375,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, ) @@ -383,19 +395,20 @@ def create_job( but it may take up to 5 minutes. Args: - request (:class:`~.job_service.CreateJobRequest`): + request (google.cloud.talent_v4.types.CreateJobRequest): The request object. Create job request. - parent (:class:`str`): + parent (str): Required. The resource name of the tenant under which the job is created. The format is "projects/{project_id}/tenants/{tenant_id}". For example, "projects/foo/tenants/bar". + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - job (:class:`~.gct_job.Job`): + job (google.cloud.talent_v4.types.Job): Required. The Job to be created. This corresponds to the ``job`` field on the ``request`` instance; if ``request`` is provided, this @@ -408,11 +421,11 @@ def create_job( sent along with the request as metadata. Returns: - ~.gct_job.Job: - A Job resource represents a job posting (also referred - to as a "job listing" or "job requisition"). A job - belongs to a [Company][google.cloud.talent.v4.Company], - which is the hiring entity responsible for the job. + google.cloud.talent_v4.types.Job: + A Job resource represents a job posting (also referred to as a "job listing" + or "job requisition"). A job belongs to a + [Company][google.cloud.talent.v4.Company], which is + the hiring entity responsible for the job. """ # Create or coerce a protobuf request object. @@ -469,22 +482,24 @@ def batch_create_jobs( r"""Begins executing a batch create jobs operation. Args: - request (:class:`~.job_service.BatchCreateJobsRequest`): + request (google.cloud.talent_v4.types.BatchCreateJobsRequest): The request object. Request to create a batch of jobs. - parent (:class:`str`): + parent (str): Required. The resource name of the tenant under which the job is created. The format is "projects/{project_id}/tenants/{tenant_id}". For example, "projects/foo/tenants/bar". + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - jobs (:class:`Sequence[~.job.Job]`): + jobs (Sequence[google.cloud.talent_v4.types.Job]): Required. The jobs to be created. A maximum of 200 jobs can be created in a batch. + This corresponds to the ``jobs`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -496,16 +511,13 @@ def batch_create_jobs( sent along with the request as metadata. Returns: - ~.operation.Operation: + google.api_core.operation.Operation: An object representing a long-running operation. - The result type for the operation will be - :class:``~.job_service.BatchCreateJobsResponse``: The - result of - [JobService.BatchCreateJobs][google.cloud.talent.v4.JobService.BatchCreateJobs]. - It's used to replace - [google.longrunning.Operation.response][google.longrunning.Operation.response] - in case of success. + The result type for the operation will be :class:`google.cloud.talent_v4.types.BatchCreateJobsResponse` The result of [JobService.BatchCreateJobs][google.cloud.talent.v4.JobService.BatchCreateJobs]. It's used to + replace + [google.longrunning.Operation.response][google.longrunning.Operation.response] + in case of success. """ # Create or coerce a protobuf request object. @@ -530,9 +542,8 @@ def batch_create_jobs( if parent is not None: request.parent = parent - - if jobs: - request.jobs.extend(jobs) + if jobs is not None: + request.jobs = jobs # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. @@ -571,14 +582,15 @@ def get_job( recently EXPIRED within the last 90 days. Args: - request (:class:`~.job_service.GetJobRequest`): + request (google.cloud.talent_v4.types.GetJobRequest): The request object. Get job request. - name (:class:`str`): + name (str): Required. The resource name of the job to retrieve. The format is "projects/{project_id}/tenants/{tenant_id}/jobs/{job_id}". For example, "projects/foo/tenants/bar/jobs/baz". + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -590,11 +602,11 @@ def get_job( sent along with the request as metadata. Returns: - ~.job.Job: - A Job resource represents a job posting (also referred - to as a "job listing" or "job requisition"). A job - belongs to a [Company][google.cloud.talent.v4.Company], - which is the hiring entity responsible for the job. + google.cloud.talent_v4.types.Job: + A Job resource represents a job posting (also referred to as a "job listing" + or "job requisition"). A job belongs to a + [Company][google.cloud.talent.v4.Company], which is + the hiring entity responsible for the job. """ # Create or coerce a protobuf request object. @@ -652,14 +664,14 @@ def update_job( minutes. Args: - request (:class:`~.job_service.UpdateJobRequest`): + request (google.cloud.talent_v4.types.UpdateJobRequest): The request object. Update job request. - job (:class:`~.gct_job.Job`): + job (google.cloud.talent_v4.types.Job): Required. The Job to be updated. This corresponds to the ``job`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - update_mask (:class:`~.field_mask.FieldMask`): + update_mask (google.protobuf.field_mask_pb2.FieldMask): Strongly recommended for the best service experience. If @@ -671,6 +683,7 @@ def update_job( A field mask to restrict the fields that are updated. Only top level fields of [Job][google.cloud.talent.v4.Job] are supported. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -682,11 +695,11 @@ def update_job( sent along with the request as metadata. Returns: - ~.gct_job.Job: - A Job resource represents a job posting (also referred - to as a "job listing" or "job requisition"). A job - belongs to a [Company][google.cloud.talent.v4.Company], - which is the hiring entity responsible for the job. + google.cloud.talent_v4.types.Job: + A Job resource represents a job posting (also referred to as a "job listing" + or "job requisition"). A job belongs to a + [Company][google.cloud.talent.v4.Company], which is + the hiring entity responsible for the job. """ # Create or coerce a protobuf request object. @@ -743,22 +756,24 @@ def batch_update_jobs( r"""Begins executing a batch update jobs operation. Args: - request (:class:`~.job_service.BatchUpdateJobsRequest`): + request (google.cloud.talent_v4.types.BatchUpdateJobsRequest): The request object. Request to update a batch of jobs. - parent (:class:`str`): + parent (str): Required. The resource name of the tenant under which the job is created. The format is "projects/{project_id}/tenants/{tenant_id}". For example, "projects/foo/tenants/bar". + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - jobs (:class:`Sequence[~.job.Job]`): + jobs (Sequence[google.cloud.talent_v4.types.Job]): Required. The jobs to be updated. A maximum of 200 jobs can be updated in a batch. + This corresponds to the ``jobs`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -770,16 +785,13 @@ def batch_update_jobs( sent along with the request as metadata. Returns: - ~.operation.Operation: + google.api_core.operation.Operation: An object representing a long-running operation. - The result type for the operation will be - :class:``~.job_service.BatchUpdateJobsResponse``: The - result of - [JobService.BatchUpdateJobs][google.cloud.talent.v4.JobService.BatchUpdateJobs]. - It's used to replace - [google.longrunning.Operation.response][google.longrunning.Operation.response] - in case of success. + The result type for the operation will be :class:`google.cloud.talent_v4.types.BatchUpdateJobsResponse` The result of [JobService.BatchUpdateJobs][google.cloud.talent.v4.JobService.BatchUpdateJobs]. It's used to + replace + [google.longrunning.Operation.response][google.longrunning.Operation.response] + in case of success. """ # Create or coerce a protobuf request object. @@ -804,9 +816,8 @@ def batch_update_jobs( if parent is not None: request.parent = parent - - if jobs: - request.jobs.extend(jobs) + if jobs is not None: + request.jobs = jobs # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. @@ -846,14 +857,15 @@ def delete_job( seconds, but it may take up to 5 minutes. Args: - request (:class:`~.job_service.DeleteJobRequest`): + request (google.cloud.talent_v4.types.DeleteJobRequest): The request object. Delete job request. - name (:class:`str`): + name (str): Required. The resource name of the job to be deleted. The format is "projects/{project_id}/tenants/{tenant_id}/jobs/{job_id}". For example, "projects/foo/tenants/bar/jobs/baz". + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -915,9 +927,9 @@ def batch_delete_jobs( r"""Begins executing a batch delete jobs operation. Args: - request (:class:`~.job_service.BatchDeleteJobsRequest`): + request (google.cloud.talent_v4.types.BatchDeleteJobsRequest): The request object. Request to delete a batch of jobs. - parent (:class:`str`): + parent (str): Required. The resource name of the tenant under which the job is created. @@ -927,10 +939,11 @@ def batch_delete_jobs( The parent of all of the jobs specified in ``names`` must match this field. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - names (:class:`Sequence[str]`): + names (Sequence[str]): The names of the jobs to delete. The format is @@ -938,6 +951,7 @@ def batch_delete_jobs( For example, "projects/foo/tenants/bar/jobs/baz". A maximum of 200 jobs can be deleted in a batch. + This corresponds to the ``names`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -949,16 +963,13 @@ def batch_delete_jobs( sent along with the request as metadata. Returns: - ~.operation.Operation: + google.api_core.operation.Operation: An object representing a long-running operation. - The result type for the operation will be - :class:``~.job_service.BatchDeleteJobsResponse``: The - result of - [JobService.BatchDeleteJobs][google.cloud.talent.v4.JobService.BatchDeleteJobs]. - It's used to replace - [google.longrunning.Operation.response][google.longrunning.Operation.response] - in case of success. + The result type for the operation will be :class:`google.cloud.talent_v4.types.BatchDeleteJobsResponse` The result of [JobService.BatchDeleteJobs][google.cloud.talent.v4.JobService.BatchDeleteJobs]. It's used to + replace + [google.longrunning.Operation.response][google.longrunning.Operation.response] + in case of success. """ # Create or coerce a protobuf request object. @@ -983,9 +994,8 @@ def batch_delete_jobs( if parent is not None: request.parent = parent - - if names: - request.names.extend(names) + if names is not None: + request.names = names # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. @@ -1024,19 +1034,20 @@ def list_jobs( r"""Lists jobs by filter. Args: - request (:class:`~.job_service.ListJobsRequest`): + request (google.cloud.talent_v4.types.ListJobsRequest): The request object. List jobs request. - parent (:class:`str`): + parent (str): Required. The resource name of the tenant under which the job is created. The format is "projects/{project_id}/tenants/{tenant_id}". For example, "projects/foo/tenants/bar". + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - filter (:class:`str`): + filter (str): Required. The filter string specifies the jobs to be enumerated. @@ -1058,7 +1069,8 @@ def list_jobs( requisitionId = "req-1" - companyName = "projects/foo/tenants/bar/companies/baz" AND status = - "EXPIRED". + "EXPIRED" + This corresponds to the ``filter`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -1070,7 +1082,7 @@ def list_jobs( sent along with the request as metadata. Returns: - ~.pagers.ListJobsPager: + google.cloud.talent_v4.services.job_service.pagers.ListJobsPager: List jobs response. Iterating over this object will yield results and resolve additional pages @@ -1141,7 +1153,7 @@ def search_jobs( has permission to search against. Args: - request (:class:`~.job_service.SearchJobsRequest`): + request (google.cloud.talent_v4.types.SearchJobsRequest): The request object. The Request body of the `SearchJobs` call. @@ -1152,7 +1164,7 @@ def search_jobs( sent along with the request as metadata. Returns: - ~.job_service.SearchJobsResponse: + google.cloud.talent_v4.types.SearchJobsResponse: Response for SearchJob method. """ # Create or coerce a protobuf request object. @@ -1203,7 +1215,7 @@ def search_jobs_for_alert( permission to search against. Args: - request (:class:`~.job_service.SearchJobsRequest`): + request (google.cloud.talent_v4.types.SearchJobsRequest): The request object. The Request body of the `SearchJobs` call. @@ -1214,7 +1226,7 @@ def search_jobs_for_alert( sent along with the request as metadata. Returns: - ~.job_service.SearchJobsResponse: + google.cloud.talent_v4.types.SearchJobsResponse: Response for SearchJob method. """ # Create or coerce a protobuf request object. diff --git a/google/cloud/talent_v4/services/job_service/pagers.py b/google/cloud/talent_v4/services/job_service/pagers.py index e759d8e3..bbef2c82 100644 --- a/google/cloud/talent_v4/services/job_service/pagers.py +++ b/google/cloud/talent_v4/services/job_service/pagers.py @@ -15,7 +15,16 @@ # limitations under the License. # -from typing import Any, AsyncIterable, Awaitable, Callable, Iterable, Sequence, Tuple +from typing import ( + Any, + AsyncIterable, + Awaitable, + Callable, + Iterable, + Sequence, + Tuple, + Optional, +) from google.cloud.talent_v4.types import job from google.cloud.talent_v4.types import job_service @@ -25,7 +34,7 @@ class ListJobsPager: """A pager for iterating through ``list_jobs`` requests. This class thinly wraps an initial - :class:`~.job_service.ListJobsResponse` object, and + :class:`google.cloud.talent_v4.types.ListJobsResponse` object, and provides an ``__iter__`` method to iterate through its ``jobs`` field. @@ -34,7 +43,7 @@ class ListJobsPager: through the ``jobs`` field on the corresponding responses. - All the usual :class:`~.job_service.ListJobsResponse` + All the usual :class:`google.cloud.talent_v4.types.ListJobsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -52,9 +61,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.job_service.ListJobsRequest`): + request (google.cloud.talent_v4.types.ListJobsRequest): The initial request object. - response (:class:`~.job_service.ListJobsResponse`): + response (google.cloud.talent_v4.types.ListJobsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -87,7 +96,7 @@ class ListJobsAsyncPager: """A pager for iterating through ``list_jobs`` requests. This class thinly wraps an initial - :class:`~.job_service.ListJobsResponse` object, and + :class:`google.cloud.talent_v4.types.ListJobsResponse` object, and provides an ``__aiter__`` method to iterate through its ``jobs`` field. @@ -96,7 +105,7 @@ class ListJobsAsyncPager: through the ``jobs`` field on the corresponding responses. - All the usual :class:`~.job_service.ListJobsResponse` + All the usual :class:`google.cloud.talent_v4.types.ListJobsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -114,9 +123,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.job_service.ListJobsRequest`): + request (google.cloud.talent_v4.types.ListJobsRequest): The initial request object. - response (:class:`~.job_service.ListJobsResponse`): + response (google.cloud.talent_v4.types.ListJobsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. diff --git a/google/cloud/talent_v4/services/job_service/transports/base.py b/google/cloud/talent_v4/services/job_service/transports/base.py index 37a4781f..97429e5b 100644 --- a/google/cloud/talent_v4/services/job_service/transports/base.py +++ b/google/cloud/talent_v4/services/job_service/transports/base.py @@ -75,10 +75,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. @@ -86,6 +86,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: @@ -95,20 +98,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 = { @@ -127,6 +127,7 @@ def _prep_wrapped_messages(self, client_info): predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=client_info, @@ -146,6 +147,7 @@ def _prep_wrapped_messages(self, client_info): predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=client_info, @@ -162,6 +164,7 @@ def _prep_wrapped_messages(self, client_info): predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=client_info, diff --git a/google/cloud/talent_v4/services/job_service/transports/grpc.py b/google/cloud/talent_v4/services/job_service/transports/grpc.py index 9f8ddd1e..d80e73f4 100644 --- a/google/cloud/talent_v4/services/job_service/transports/grpc.py +++ b/google/cloud/talent_v4/services/job_service/transports/grpc.py @@ -63,6 +63,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: @@ -93,6 +94,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): @@ -107,72 +112,61 @@ def __init__( google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` and ``credentials_file`` are passed. """ + self._grpc_channel = None self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} + self._operations_client = None + + if api_mtls_endpoint: + warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning) + if client_cert_source: + warnings.warn("client_cert_source is deprecated", DeprecationWarning) if channel: - # Sanity check: Ensure that channel and credentials are not both - # provided. + # Ignore credentials if a channel was passed. credentials = False - # If a channel was explicitly provided, set it. self._grpc_channel = channel self._ssl_channel_credentials = None - elif api_mtls_endpoint: - warnings.warn( - "api_mtls_endpoint and client_cert_source are deprecated", - DeprecationWarning, - ) - host = ( - api_mtls_endpoint - if ":" in api_mtls_endpoint - else api_mtls_endpoint + ":443" - ) + else: + if api_mtls_endpoint: + host = api_mtls_endpoint + + # Create SSL credentials with client_cert_source or application + # default SSL credentials. + if client_cert_source: + cert, key = client_cert_source() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + else: + self._ssl_channel_credentials = SslCredentials().ssl_credentials - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) - - # Create SSL credentials with client_cert_source or application - # default SSL credentials. - if client_cert_source: - cert, key = client_cert_source() - ssl_credentials = grpc.ssl_channel_credentials( - certificate_chain=cert, private_key=key - ) else: - ssl_credentials = SslCredentials().ssl_credentials + if client_cert_source_for_mtls and not ssl_channel_credentials: + cert, key = client_cert_source_for_mtls() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) - # create a new channel. The provided one is ignored. - self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, - credentials_file=credentials_file, - ssl_credentials=ssl_credentials, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - options=[ - ("grpc.max_send_message_length", -1), - ("grpc.max_receive_message_length", -1), - ], - ) - self._ssl_channel_credentials = ssl_credentials - else: - host = host if ":" in host else host + ":443" - - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) + # The base transport sets the host, credentials and scopes + super().__init__( + host=host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + client_info=client_info, + ) - # create a new channel. The provided one is ignored. + if not self._grpc_channel: self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, + self._host, + credentials=self._credentials, credentials_file=credentials_file, - ssl_credentials=ssl_channel_credentials, - scopes=scopes or self.AUTH_SCOPES, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, quota_project_id=quota_project_id, options=[ ("grpc.max_send_message_length", -1), @@ -180,18 +174,8 @@ def __init__( ], ) - self._stubs = {} # type: Dict[str, Callable] - self._operations_client = None - - # Run the base constructor. - super().__init__( - host=host, - credentials=credentials, - credentials_file=credentials_file, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - client_info=client_info, - ) + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) @classmethod def create_channel( @@ -205,7 +189,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/talent_v4/services/job_service/transports/grpc_asyncio.py b/google/cloud/talent_v4/services/job_service/transports/grpc_asyncio.py index 2a50e03c..599527c8 100644 --- a/google/cloud/talent_v4/services/job_service/transports/grpc_asyncio.py +++ b/google/cloud/talent_v4/services/job_service/transports/grpc_asyncio.py @@ -67,7 +67,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 @@ -107,6 +107,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: @@ -138,12 +139,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: @@ -152,72 +157,61 @@ def __init__( google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` and ``credentials_file`` are passed. """ + self._grpc_channel = None self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} + self._operations_client = None + + if api_mtls_endpoint: + warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning) + if client_cert_source: + warnings.warn("client_cert_source is deprecated", DeprecationWarning) if channel: - # Sanity check: Ensure that channel and credentials are not both - # provided. + # Ignore credentials if a channel was passed. credentials = False - # If a channel was explicitly provided, set it. self._grpc_channel = channel self._ssl_channel_credentials = None - elif api_mtls_endpoint: - warnings.warn( - "api_mtls_endpoint and client_cert_source are deprecated", - DeprecationWarning, - ) - host = ( - api_mtls_endpoint - if ":" in api_mtls_endpoint - else api_mtls_endpoint + ":443" - ) + else: + if api_mtls_endpoint: + host = api_mtls_endpoint + + # Create SSL credentials with client_cert_source or application + # default SSL credentials. + if client_cert_source: + cert, key = client_cert_source() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + else: + self._ssl_channel_credentials = SslCredentials().ssl_credentials - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) - - # Create SSL credentials with client_cert_source or application - # default SSL credentials. - if client_cert_source: - cert, key = client_cert_source() - ssl_credentials = grpc.ssl_channel_credentials( - certificate_chain=cert, private_key=key - ) else: - ssl_credentials = SslCredentials().ssl_credentials + if client_cert_source_for_mtls and not ssl_channel_credentials: + cert, key = client_cert_source_for_mtls() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) - # create a new channel. The provided one is ignored. - self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, - credentials_file=credentials_file, - ssl_credentials=ssl_credentials, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - options=[ - ("grpc.max_send_message_length", -1), - ("grpc.max_receive_message_length", -1), - ], - ) - self._ssl_channel_credentials = ssl_credentials - else: - host = host if ":" in host else host + ":443" - - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) + # The base transport sets the host, credentials and scopes + super().__init__( + host=host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + client_info=client_info, + ) - # create a new channel. The provided one is ignored. + if not self._grpc_channel: self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, + self._host, + credentials=self._credentials, credentials_file=credentials_file, - ssl_credentials=ssl_channel_credentials, - scopes=scopes or self.AUTH_SCOPES, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, quota_project_id=quota_project_id, options=[ ("grpc.max_send_message_length", -1), @@ -225,18 +219,8 @@ def __init__( ], ) - # Run the base constructor. - super().__init__( - host=host, - credentials=credentials, - credentials_file=credentials_file, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - client_info=client_info, - ) - - self._stubs = {} - self._operations_client = None + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) @property def grpc_channel(self) -> aio.Channel: diff --git a/google/cloud/talent_v4/services/tenant_service/async_client.py b/google/cloud/talent_v4/services/tenant_service/async_client.py index 07940a99..51ebcab7 100644 --- a/google/cloud/talent_v4/services/tenant_service/async_client.py +++ b/google/cloud/talent_v4/services/tenant_service/async_client.py @@ -81,7 +81,36 @@ class TenantServiceAsyncClient: TenantServiceClient.parse_common_location_path ) - from_service_account_file = TenantServiceClient.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: + TenantServiceAsyncClient: The constructed client. + """ + return TenantServiceClient.from_service_account_info.__func__(TenantServiceAsyncClient, 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: + TenantServiceAsyncClient: The constructed client. + """ + return TenantServiceClient.from_service_account_file.__func__(TenantServiceAsyncClient, filename, *args, **kwargs) # type: ignore + from_service_account_json = from_service_account_file @property @@ -158,7 +187,7 @@ async def create_tenant( r"""Creates a new tenant entity. Args: - request (:class:`~.tenant_service.CreateTenantRequest`): + request (:class:`google.cloud.talent_v4.types.CreateTenantRequest`): The request object. The Request of the CreateTenant method. parent (:class:`str`): @@ -167,10 +196,11 @@ async def create_tenant( The format is "projects/{project_id}", for example, "projects/foo". + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - tenant (:class:`~.gct_tenant.Tenant`): + tenant (:class:`google.cloud.talent_v4.types.Tenant`): Required. The tenant to be created. This corresponds to the ``tenant`` field on the ``request`` instance; if ``request`` is provided, this @@ -183,7 +213,7 @@ async def create_tenant( sent along with the request as metadata. Returns: - ~.gct_tenant.Tenant: + google.cloud.talent_v4.types.Tenant: A Tenant resource represents a tenant in the service. A tenant is a group or entity that shares common access with @@ -245,7 +275,7 @@ async def get_tenant( r"""Retrieves specified tenant. Args: - request (:class:`~.tenant_service.GetTenantRequest`): + request (:class:`google.cloud.talent_v4.types.GetTenantRequest`): The request object. Request for getting a tenant by name. name (:class:`str`): @@ -255,6 +285,7 @@ async def get_tenant( The format is "projects/{project_id}/tenants/{tenant_id}", for example, "projects/foo/tenants/bar". + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -266,7 +297,7 @@ async def get_tenant( sent along with the request as metadata. Returns: - ~.tenant.Tenant: + google.cloud.talent_v4.types.Tenant: A Tenant resource represents a tenant in the service. A tenant is a group or entity that shares common access with @@ -305,6 +336,7 @@ async def get_tenant( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=DEFAULT_CLIENT_INFO, @@ -335,17 +367,18 @@ async def update_tenant( r"""Updates specified tenant. Args: - request (:class:`~.tenant_service.UpdateTenantRequest`): + request (:class:`google.cloud.talent_v4.types.UpdateTenantRequest`): The request object. Request for updating a specified tenant. - tenant (:class:`~.gct_tenant.Tenant`): + tenant (:class:`google.cloud.talent_v4.types.Tenant`): Required. The tenant resource to replace the current resource in the system. + This corresponds to the ``tenant`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - update_mask (:class:`~.field_mask.FieldMask`): + update_mask (:class:`google.protobuf.field_mask_pb2.FieldMask`): Strongly recommended for the best service experience. If @@ -357,6 +390,7 @@ async def update_tenant( A field mask to specify the tenant fields to be updated. Only top level fields of [Tenant][google.cloud.talent.v4.Tenant] are supported. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -368,7 +402,7 @@ async def update_tenant( sent along with the request as metadata. Returns: - ~.gct_tenant.Tenant: + google.cloud.talent_v4.types.Tenant: A Tenant resource represents a tenant in the service. A tenant is a group or entity that shares common access with @@ -432,7 +466,7 @@ async def delete_tenant( r"""Deletes specified tenant. Args: - request (:class:`~.tenant_service.DeleteTenantRequest`): + request (:class:`google.cloud.talent_v4.types.DeleteTenantRequest`): The request object. Request to delete a tenant. name (:class:`str`): Required. The resource name of the tenant to be deleted. @@ -440,6 +474,7 @@ async def delete_tenant( The format is "projects/{project_id}/tenants/{tenant_id}", for example, "projects/foo/tenants/bar". + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -479,6 +514,7 @@ async def delete_tenant( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=DEFAULT_CLIENT_INFO, @@ -507,7 +543,7 @@ async def list_tenants( r"""Lists all tenants associated with the project. Args: - request (:class:`~.tenant_service.ListTenantsRequest`): + request (:class:`google.cloud.talent_v4.types.ListTenantsRequest`): The request object. List tenants for which the client has ACL visibility. parent (:class:`str`): @@ -516,6 +552,7 @@ async def list_tenants( The format is "projects/{project_id}", for example, "projects/foo". + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -527,7 +564,7 @@ async def list_tenants( sent along with the request as metadata. Returns: - ~.pagers.ListTenantsAsyncPager: + google.cloud.talent_v4.services.tenant_service.pagers.ListTenantsAsyncPager: The List tenants response object. Iterating over this object will yield results and resolve additional pages @@ -563,6 +600,7 @@ async def list_tenants( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=DEFAULT_CLIENT_INFO, diff --git a/google/cloud/talent_v4/services/tenant_service/client.py b/google/cloud/talent_v4/services/tenant_service/client.py index 7492a9c3..ef6d560c 100644 --- a/google/cloud/talent_v4/services/tenant_service/client.py +++ b/google/cloud/talent_v4/services/tenant_service/client.py @@ -113,6 +113,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: + TenantServiceClient: 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 @@ -125,7 +141,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. + TenantServiceClient: The constructed client. """ credentials = service_account.Credentials.from_service_account_file(filename) kwargs["credentials"] = credentials @@ -230,10 +246,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, ~.TenantServiceTransport]): The + transport (Union[str, TenantServiceTransport]): 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 @@ -269,21 +285,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: @@ -326,7 +338,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, ) @@ -344,19 +356,20 @@ def create_tenant( r"""Creates a new tenant entity. Args: - request (:class:`~.tenant_service.CreateTenantRequest`): + request (google.cloud.talent_v4.types.CreateTenantRequest): The request object. The Request of the CreateTenant method. - parent (:class:`str`): + parent (str): Required. Resource name of the project under which the tenant is created. The format is "projects/{project_id}", for example, "projects/foo". + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - tenant (:class:`~.gct_tenant.Tenant`): + tenant (google.cloud.talent_v4.types.Tenant): Required. The tenant to be created. This corresponds to the ``tenant`` field on the ``request`` instance; if ``request`` is provided, this @@ -369,7 +382,7 @@ def create_tenant( sent along with the request as metadata. Returns: - ~.gct_tenant.Tenant: + google.cloud.talent_v4.types.Tenant: A Tenant resource represents a tenant in the service. A tenant is a group or entity that shares common access with @@ -432,16 +445,17 @@ def get_tenant( r"""Retrieves specified tenant. Args: - request (:class:`~.tenant_service.GetTenantRequest`): + request (google.cloud.talent_v4.types.GetTenantRequest): The request object. Request for getting a tenant by name. - name (:class:`str`): + name (str): Required. The resource name of the tenant to be retrieved. The format is "projects/{project_id}/tenants/{tenant_id}", for example, "projects/foo/tenants/bar". + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -453,7 +467,7 @@ def get_tenant( sent along with the request as metadata. Returns: - ~.tenant.Tenant: + google.cloud.talent_v4.types.Tenant: A Tenant resource represents a tenant in the service. A tenant is a group or entity that shares common access with @@ -515,17 +529,18 @@ def update_tenant( r"""Updates specified tenant. Args: - request (:class:`~.tenant_service.UpdateTenantRequest`): + request (google.cloud.talent_v4.types.UpdateTenantRequest): The request object. Request for updating a specified tenant. - tenant (:class:`~.gct_tenant.Tenant`): + tenant (google.cloud.talent_v4.types.Tenant): Required. The tenant resource to replace the current resource in the system. + This corresponds to the ``tenant`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - update_mask (:class:`~.field_mask.FieldMask`): + update_mask (google.protobuf.field_mask_pb2.FieldMask): Strongly recommended for the best service experience. If @@ -537,6 +552,7 @@ def update_tenant( A field mask to specify the tenant fields to be updated. Only top level fields of [Tenant][google.cloud.talent.v4.Tenant] are supported. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -548,7 +564,7 @@ def update_tenant( sent along with the request as metadata. Returns: - ~.gct_tenant.Tenant: + google.cloud.talent_v4.types.Tenant: A Tenant resource represents a tenant in the service. A tenant is a group or entity that shares common access with @@ -613,14 +629,15 @@ def delete_tenant( r"""Deletes specified tenant. Args: - request (:class:`~.tenant_service.DeleteTenantRequest`): + request (google.cloud.talent_v4.types.DeleteTenantRequest): The request object. Request to delete a tenant. - name (:class:`str`): + name (str): Required. The resource name of the tenant to be deleted. The format is "projects/{project_id}/tenants/{tenant_id}", for example, "projects/foo/tenants/bar". + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -681,15 +698,16 @@ def list_tenants( r"""Lists all tenants associated with the project. Args: - request (:class:`~.tenant_service.ListTenantsRequest`): + request (google.cloud.talent_v4.types.ListTenantsRequest): The request object. List tenants for which the client has ACL visibility. - parent (:class:`str`): + parent (str): Required. Resource name of the project under which the tenant is created. The format is "projects/{project_id}", for example, "projects/foo". + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -701,7 +719,7 @@ def list_tenants( sent along with the request as metadata. Returns: - ~.pagers.ListTenantsPager: + google.cloud.talent_v4.services.tenant_service.pagers.ListTenantsPager: The List tenants response object. Iterating over this object will yield results and resolve additional pages diff --git a/google/cloud/talent_v4/services/tenant_service/pagers.py b/google/cloud/talent_v4/services/tenant_service/pagers.py index d671fdb7..91d4a213 100644 --- a/google/cloud/talent_v4/services/tenant_service/pagers.py +++ b/google/cloud/talent_v4/services/tenant_service/pagers.py @@ -15,7 +15,16 @@ # limitations under the License. # -from typing import Any, AsyncIterable, Awaitable, Callable, Iterable, Sequence, Tuple +from typing import ( + Any, + AsyncIterable, + Awaitable, + Callable, + Iterable, + Sequence, + Tuple, + Optional, +) from google.cloud.talent_v4.types import tenant from google.cloud.talent_v4.types import tenant_service @@ -25,7 +34,7 @@ class ListTenantsPager: """A pager for iterating through ``list_tenants`` requests. This class thinly wraps an initial - :class:`~.tenant_service.ListTenantsResponse` object, and + :class:`google.cloud.talent_v4.types.ListTenantsResponse` object, and provides an ``__iter__`` method to iterate through its ``tenants`` field. @@ -34,7 +43,7 @@ class ListTenantsPager: through the ``tenants`` field on the corresponding responses. - All the usual :class:`~.tenant_service.ListTenantsResponse` + All the usual :class:`google.cloud.talent_v4.types.ListTenantsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -52,9 +61,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.tenant_service.ListTenantsRequest`): + request (google.cloud.talent_v4.types.ListTenantsRequest): The initial request object. - response (:class:`~.tenant_service.ListTenantsResponse`): + response (google.cloud.talent_v4.types.ListTenantsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -87,7 +96,7 @@ class ListTenantsAsyncPager: """A pager for iterating through ``list_tenants`` requests. This class thinly wraps an initial - :class:`~.tenant_service.ListTenantsResponse` object, and + :class:`google.cloud.talent_v4.types.ListTenantsResponse` object, and provides an ``__aiter__`` method to iterate through its ``tenants`` field. @@ -96,7 +105,7 @@ class ListTenantsAsyncPager: through the ``tenants`` field on the corresponding responses. - All the usual :class:`~.tenant_service.ListTenantsResponse` + All the usual :class:`google.cloud.talent_v4.types.ListTenantsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -114,9 +123,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.tenant_service.ListTenantsRequest`): + request (google.cloud.talent_v4.types.ListTenantsRequest): The initial request object. - response (:class:`~.tenant_service.ListTenantsResponse`): + response (google.cloud.talent_v4.types.ListTenantsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. diff --git a/google/cloud/talent_v4/services/tenant_service/transports/base.py b/google/cloud/talent_v4/services/tenant_service/transports/base.py index dee8e4f0..c921d237 100644 --- a/google/cloud/talent_v4/services/tenant_service/transports/base.py +++ b/google/cloud/talent_v4/services/tenant_service/transports/base.py @@ -73,10 +73,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. @@ -84,6 +84,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: @@ -93,20 +96,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 = { @@ -122,6 +122,7 @@ def _prep_wrapped_messages(self, client_info): predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=client_info, @@ -138,6 +139,7 @@ def _prep_wrapped_messages(self, client_info): predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=client_info, @@ -151,6 +153,7 @@ def _prep_wrapped_messages(self, client_info): predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=client_info, diff --git a/google/cloud/talent_v4/services/tenant_service/transports/grpc.py b/google/cloud/talent_v4/services/tenant_service/transports/grpc.py index f6ff6185..d837f65e 100644 --- a/google/cloud/talent_v4/services/tenant_service/transports/grpc.py +++ b/google/cloud/talent_v4/services/tenant_service/transports/grpc.py @@ -61,6 +61,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: @@ -91,6 +92,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): @@ -105,72 +110,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), @@ -178,17 +171,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( @@ -202,7 +186,7 @@ def create_channel( ) -> grpc.Channel: """Create and return a gRPC channel object. Args: - address (Optional[str]): The host for the channel to use. + host (Optional[str]): The host for the channel to use. credentials (Optional[~.Credentials]): The authorization credentials to attach to requests. These credentials identify this application to the service. If diff --git a/google/cloud/talent_v4/services/tenant_service/transports/grpc_asyncio.py b/google/cloud/talent_v4/services/tenant_service/transports/grpc_asyncio.py index dac79077..072a50dc 100644 --- a/google/cloud/talent_v4/services/tenant_service/transports/grpc_asyncio.py +++ b/google/cloud/talent_v4/services/tenant_service/transports/grpc_asyncio.py @@ -65,7 +65,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 @@ -105,6 +105,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: @@ -136,12 +137,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: @@ -150,72 +155,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), @@ -223,17 +216,8 @@ def __init__( ], ) - # Run the base constructor. - super().__init__( - host=host, - credentials=credentials, - credentials_file=credentials_file, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - client_info=client_info, - ) - - self._stubs = {} + # 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/talent_v4/types/__init__.py b/google/cloud/talent_v4/types/__init__.py index faf71c78..29719f84 100644 --- a/google/cloud/talent_v4/types/__init__.py +++ b/google/cloud/talent_v4/types/__init__.py @@ -16,34 +16,34 @@ # from .common import ( - TimestampRange, + BatchOperationMetadata, + CompensationInfo, + CustomAttribute, + DeviceInfo, Location, RequestMetadata, ResponseMetadata, - DeviceInfo, - CustomAttribute, SpellingCorrection, - CompensationInfo, - BatchOperationMetadata, + TimestampRange, + CommuteMethod, CompanySize, - JobBenefit, DegreeType, EmploymentType, - JobLevel, + HtmlSanitization, + JobBenefit, JobCategory, + JobLevel, PostingRegion, Visibility, - HtmlSanitization, - CommuteMethod, ) from .company import Company from .company_service import ( CreateCompanyRequest, - GetCompanyRequest, - UpdateCompanyRequest, DeleteCompanyRequest, + GetCompanyRequest, ListCompaniesRequest, ListCompaniesResponse, + UpdateCompanyRequest, ) from .completion_service import ( CompleteQueryRequest, @@ -55,10 +55,10 @@ ) from .event_service import CreateClientEventRequest from .filters import ( + CommuteFilter, + CompensationFilter, JobQuery, LocationFilter, - CompensationFilter, - CommuteFilter, ) from .histogram import ( HistogramQuery, @@ -66,93 +66,93 @@ ) from .job import Job from .job_service import ( + BatchCreateJobsRequest, + BatchCreateJobsResponse, + BatchDeleteJobsRequest, + BatchDeleteJobsResponse, + BatchUpdateJobsRequest, + BatchUpdateJobsResponse, CreateJobRequest, - GetJobRequest, - UpdateJobRequest, DeleteJobRequest, + GetJobRequest, + JobResult, ListJobsRequest, ListJobsResponse, SearchJobsRequest, SearchJobsResponse, - BatchCreateJobsRequest, - BatchUpdateJobsRequest, - BatchDeleteJobsRequest, - JobResult, - BatchCreateJobsResponse, - BatchUpdateJobsResponse, - BatchDeleteJobsResponse, + UpdateJobRequest, JobView, ) from .tenant import Tenant from .tenant_service import ( CreateTenantRequest, - GetTenantRequest, - UpdateTenantRequest, DeleteTenantRequest, + GetTenantRequest, ListTenantsRequest, ListTenantsResponse, + UpdateTenantRequest, ) __all__ = ( - "TimestampRange", + "BatchOperationMetadata", + "CompensationInfo", + "CustomAttribute", + "DeviceInfo", "Location", "RequestMetadata", "ResponseMetadata", - "DeviceInfo", - "CustomAttribute", "SpellingCorrection", - "CompensationInfo", - "BatchOperationMetadata", + "TimestampRange", + "CommuteMethod", "CompanySize", - "JobBenefit", "DegreeType", "EmploymentType", - "JobLevel", + "HtmlSanitization", + "JobBenefit", "JobCategory", + "JobLevel", "PostingRegion", "Visibility", - "HtmlSanitization", - "CommuteMethod", "Company", "CreateCompanyRequest", - "GetCompanyRequest", - "UpdateCompanyRequest", "DeleteCompanyRequest", + "GetCompanyRequest", "ListCompaniesRequest", "ListCompaniesResponse", + "UpdateCompanyRequest", "CompleteQueryRequest", "CompleteQueryResponse", "ClientEvent", "JobEvent", "CreateClientEventRequest", + "CommuteFilter", + "CompensationFilter", "JobQuery", "LocationFilter", - "CompensationFilter", - "CommuteFilter", "HistogramQuery", "HistogramQueryResult", "Job", + "BatchCreateJobsRequest", + "BatchCreateJobsResponse", + "BatchDeleteJobsRequest", + "BatchDeleteJobsResponse", + "BatchUpdateJobsRequest", + "BatchUpdateJobsResponse", "CreateJobRequest", - "GetJobRequest", - "UpdateJobRequest", "DeleteJobRequest", + "GetJobRequest", + "JobResult", "ListJobsRequest", "ListJobsResponse", "SearchJobsRequest", "SearchJobsResponse", - "BatchCreateJobsRequest", - "BatchUpdateJobsRequest", - "BatchDeleteJobsRequest", - "JobResult", - "BatchCreateJobsResponse", - "BatchUpdateJobsResponse", - "BatchDeleteJobsResponse", + "UpdateJobRequest", "JobView", "Tenant", "CreateTenantRequest", - "GetTenantRequest", - "UpdateTenantRequest", "DeleteTenantRequest", + "GetTenantRequest", "ListTenantsRequest", "ListTenantsResponse", + "UpdateTenantRequest", ) diff --git a/google/cloud/talent_v4/types/common.py b/google/cloud/talent_v4/types/common.py index 13b73611..6acd7469 100644 --- a/google/cloud/talent_v4/types/common.py +++ b/google/cloud/talent_v4/types/common.py @@ -178,6 +178,7 @@ class Visibility(proto.Enum): r"""Deprecated. All resources are only visible to the owner. An enum that represents who has view access to the resource. """ + _pb_options = {"deprecated": True} VISIBILITY_UNSPECIFIED = 0 ACCOUNT_ONLY = 1 SHARED_WITH_GOOGLE = 2 @@ -206,9 +207,9 @@ class TimestampRange(proto.Message): r"""Message representing a period of time between two timestamps. Attributes: - start_time (~.timestamp.Timestamp): + start_time (google.protobuf.timestamp_pb2.Timestamp): Begin of the period (inclusive). - end_time (~.timestamp.Timestamp): + end_time (google.protobuf.timestamp_pb2.Timestamp): End of the period (exclusive). """ @@ -222,7 +223,7 @@ class Location(proto.Message): information. Attributes: - location_type (~.common.Location.LocationType): + location_type (google.cloud.talent_v4.types.Location.LocationType): The type of a location, which corresponds to the address lines field of [google.type.PostalAddress][google.type.PostalAddress]. For @@ -230,13 +231,13 @@ class Location(proto.Message): [LocationType.NEIGHBORHOOD][google.cloud.talent.v4.Location.LocationType.NEIGHBORHOOD], and "Kansas City, KS, USA" has a type of [LocationType.LOCALITY][google.cloud.talent.v4.Location.LocationType.LOCALITY]. - postal_address (~.gt_postal_address.PostalAddress): + postal_address (google.type.postal_address_pb2.PostalAddress): Postal address of the location that includes human readable information, such as postal delivery and payments addresses. Given a postal address, a postal service can deliver items to a premises, P.O. Box, or other delivery location. - lat_lng (~.latlng.LatLng): + lat_lng (google.type.latlng_pb2.LatLng): An object representing a latitude/longitude pair. radius_miles (float): @@ -342,7 +343,7 @@ class RequestMetadata(proto.Message): and [user_id][google.cloud.talent.v4.RequestMetadata.user_id] for the best service experience. - device_info (~.common.DeviceInfo): + device_info (google.cloud.talent_v4.types.DeviceInfo): The type of device used by the job seeker at the time of the call to the service. """ @@ -378,7 +379,7 @@ class DeviceInfo(proto.Message): devices. Attributes: - device_type (~.common.DeviceInfo.DeviceType): + device_type (google.cloud.talent_v4.types.DeviceInfo.DeviceType): Type of the device. id (str): A device-specific ID. The ID must be a unique @@ -495,14 +496,14 @@ class CompensationInfo(proto.Message): r"""Job compensation details. Attributes: - entries (Sequence[~.common.CompensationInfo.CompensationEntry]): + entries (Sequence[google.cloud.talent_v4.types.CompensationInfo.CompensationEntry]): Job compensation information. At most one entry can be of type [CompensationInfo.CompensationType.BASE][google.cloud.talent.v4.CompensationInfo.CompensationType.BASE], which is referred as **base compensation entry** for the job. - annualized_base_compensation_range (~.common.CompensationInfo.CompensationRange): + annualized_base_compensation_range (google.cloud.talent_v4.types.CompensationInfo.CompensationRange): Output only. Annualized base compensation range. Computed as base compensation entry's [CompensationEntry.amount][google.cloud.talent.v4.CompensationInfo.CompensationEntry.amount] @@ -512,7 +513,7 @@ class CompensationInfo(proto.Message): See [CompensationEntry][google.cloud.talent.v4.CompensationInfo.CompensationEntry] for explanation on compensation annualization. - annualized_total_compensation_range (~.common.CompensationInfo.CompensationRange): + annualized_total_compensation_range (google.cloud.talent_v4.types.CompensationInfo.CompensationRange): Output only. Annualized total compensation range. Computed as all compensation entries' [CompensationEntry.amount][google.cloud.talent.v4.CompensationInfo.CompensationEntry.amount] @@ -594,25 +595,25 @@ class CompensationEntry(proto.Message): [expected_units_per_year][google.cloud.talent.v4.CompensationInfo.CompensationEntry.expected_units_per_year]. Attributes: - type_ (~.common.CompensationInfo.CompensationType): + type_ (google.cloud.talent_v4.types.CompensationInfo.CompensationType): Compensation type. Default is [CompensationType.COMPENSATION_TYPE_UNSPECIFIED][google.cloud.talent.v4.CompensationInfo.CompensationType.COMPENSATION_TYPE_UNSPECIFIED]. - unit (~.common.CompensationInfo.CompensationUnit): + unit (google.cloud.talent_v4.types.CompensationInfo.CompensationUnit): Frequency of the specified amount. Default is [CompensationUnit.COMPENSATION_UNIT_UNSPECIFIED][google.cloud.talent.v4.CompensationInfo.CompensationUnit.COMPENSATION_UNIT_UNSPECIFIED]. - amount (~.money.Money): + amount (google.type.money_pb2.Money): Compensation amount. - range_ (~.common.CompensationInfo.CompensationRange): + range_ (google.cloud.talent_v4.types.CompensationInfo.CompensationRange): Compensation range. description (str): Compensation description. For example, could indicate equity terms or provide additional context to an estimated bonus. - expected_units_per_year (~.wrappers.DoubleValue): + expected_units_per_year (google.protobuf.wrappers_pb2.DoubleValue): Expected number of units paid each year. If not specified, when [Job.employment_types][google.cloud.talent.v4.Job.employment_types] @@ -656,12 +657,12 @@ class CompensationRange(proto.Message): r"""Compensation range. Attributes: - max_compensation (~.money.Money): + max_compensation (google.type.money_pb2.Money): The maximum amount of compensation. If left empty, the value is set to a maximal compensation value and the currency code is set to match the [currency code][google.type.Money.currency_code] of min_compensation. - min_compensation (~.money.Money): + min_compensation (google.type.money_pb2.Money): The minimum amount of compensation. If left empty, the value is set to zero and the currency code is set to match the [currency code][google.type.Money.currency_code] of @@ -689,7 +690,7 @@ class BatchOperationMetadata(proto.Message): [google.longrunning.Operation.metadata][google.longrunning.Operation.metadata]. Attributes: - state (~.common.BatchOperationMetadata.State): + state (google.cloud.talent_v4.types.BatchOperationMetadata.State): The state of a long running operation. state_description (str): More detailed information about operation @@ -701,14 +702,14 @@ class BatchOperationMetadata(proto.Message): Count of failed item(s) inside an operation. total_count (int): Count of total item(s) inside an operation. - create_time (~.timestamp.Timestamp): + create_time (google.protobuf.timestamp_pb2.Timestamp): The time when the batch operation is created. - update_time (~.timestamp.Timestamp): + update_time (google.protobuf.timestamp_pb2.Timestamp): The time when the batch operation status is updated. The metadata and the [update_time][google.cloud.talent.v4.BatchOperationMetadata.update_time] is refreshed every minute otherwise cached data is returned. - end_time (~.timestamp.Timestamp): + end_time (google.protobuf.timestamp_pb2.Timestamp): The time when the batch operation is finished and [google.longrunning.Operation.done][google.longrunning.Operation.done] is set to ``true``. diff --git a/google/cloud/talent_v4/types/company.py b/google/cloud/talent_v4/types/company.py index 9955928e..84df7fe7 100644 --- a/google/cloud/talent_v4/types/company.py +++ b/google/cloud/talent_v4/types/company.py @@ -48,7 +48,7 @@ class Company(proto.Message): used to uniquely identify the company. The maximum number of allowed characters is 255. - size (~.common.CompanySize): + size (google.cloud.talent_v4.types.CompanySize): The employer's company size. headquarters_address (str): The street address of the company's main headquarters, which @@ -87,7 +87,7 @@ class Company(proto.Message): search keyword. Custom field values with parenthesis, brackets and special symbols are not searchable as-is, and those keyword queries must be surrounded by quotes. - derived_info (~.company.Company.DerivedInfo): + derived_info (google.cloud.talent_v4.types.Company.DerivedInfo): Output only. Derived details about the company. suspended (bool): @@ -101,7 +101,7 @@ class DerivedInfo(proto.Message): r"""Derived details about the company. Attributes: - headquarters_location (~.common.Location): + headquarters_location (google.cloud.talent_v4.types.Location): A structured headquarters location of the company, resolved from [Company.headquarters_address][google.cloud.talent.v4.Company.headquarters_address] diff --git a/google/cloud/talent_v4/types/company_service.py b/google/cloud/talent_v4/types/company_service.py index 0e166ef9..c6862175 100644 --- a/google/cloud/talent_v4/types/company_service.py +++ b/google/cloud/talent_v4/types/company_service.py @@ -46,7 +46,7 @@ class CreateCompanyRequest(proto.Message): The format is "projects/{project_id}/tenants/{tenant_id}", for example, "projects/foo/tenants/bar". - company (~.gct_company.Company): + company (google.cloud.talent_v4.types.Company): Required. The company to be created. """ @@ -75,10 +75,10 @@ class UpdateCompanyRequest(proto.Message): r"""Request for updating a specified company. Attributes: - company (~.gct_company.Company): + company (google.cloud.talent_v4.types.Company): Required. The company resource to replace the current resource in the system. - update_mask (~.field_mask.FieldMask): + update_mask (google.protobuf.field_mask_pb2.FieldMask): Strongly recommended for the best service experience. If @@ -153,11 +153,11 @@ class ListCompaniesResponse(proto.Message): r"""The List companies response object. Attributes: - companies (Sequence[~.gct_company.Company]): + companies (Sequence[google.cloud.talent_v4.types.Company]): Companies for the current client. next_page_token (str): A token to retrieve the next page of results. - metadata (~.common.ResponseMetadata): + metadata (google.cloud.talent_v4.types.ResponseMetadata): Additional information for the API invocation, such as the request tracking id. """ diff --git a/google/cloud/talent_v4/types/completion_service.py b/google/cloud/talent_v4/types/completion_service.py index ba2529b2..fe233356 100644 --- a/google/cloud/talent_v4/types/completion_service.py +++ b/google/cloud/talent_v4/types/completion_service.py @@ -57,10 +57,10 @@ class CompleteQueryRequest(proto.Message): The format is "projects/{project_id}/tenants/{tenant_id}/companies/{company_id}", for example, "projects/foo/tenants/bar/companies/baz". - scope (~.completion_service.CompleteQueryRequest.CompletionScope): + scope (google.cloud.talent_v4.types.CompleteQueryRequest.CompletionScope): The scope of the completion. The defaults is [CompletionScope.PUBLIC][google.cloud.talent.v4.CompleteQueryRequest.CompletionScope.PUBLIC]. - type_ (~.completion_service.CompleteQueryRequest.CompletionType): + type_ (google.cloud.talent_v4.types.CompleteQueryRequest.CompletionType): The completion topic. The default is [CompletionType.COMBINED][google.cloud.talent.v4.CompleteQueryRequest.CompletionType.COMBINED]. """ @@ -97,10 +97,10 @@ class CompleteQueryResponse(proto.Message): r"""Response of auto-complete query. Attributes: - completion_results (Sequence[~.completion_service.CompleteQueryResponse.CompletionResult]): + completion_results (Sequence[google.cloud.talent_v4.types.CompleteQueryResponse.CompletionResult]): Results of the matching job/company candidates. - metadata (~.common.ResponseMetadata): + metadata (google.cloud.talent_v4.types.ResponseMetadata): Additional information for the API invocation, such as the request tracking id. """ @@ -111,7 +111,7 @@ class CompletionResult(proto.Message): Attributes: suggestion (str): The suggestion for the query. - type_ (~.completion_service.CompleteQueryRequest.CompletionType): + type_ (google.cloud.talent_v4.types.CompleteQueryRequest.CompletionType): The completion topic. image_uri (str): The URI of the company image for diff --git a/google/cloud/talent_v4/types/event.py b/google/cloud/talent_v4/types/event.py index 8ecb3a87..40ffe6f2 100644 --- a/google/cloud/talent_v4/types/event.py +++ b/google/cloud/talent_v4/types/event.py @@ -44,9 +44,9 @@ class ClientEvent(proto.Message): event_id (str): Required. A unique identifier, generated by the client application. - create_time (~.timestamp.Timestamp): + create_time (google.protobuf.timestamp_pb2.Timestamp): Required. The timestamp of the event. - job_event (~.event.JobEvent): + job_event (google.cloud.talent_v4.types.JobEvent): An event issued when a job seeker interacts with the application that implements Cloud Talent Solution. @@ -72,7 +72,7 @@ class JobEvent(proto.Message): application that implements Cloud Talent Solution. Attributes: - type_ (~.event.JobEvent.JobEventType): + type_ (google.cloud.talent_v4.types.JobEvent.JobEventType): Required. The type of the event (see [JobEventType][google.cloud.talent.v4.JobEvent.JobEventType]). jobs (Sequence[str]): diff --git a/google/cloud/talent_v4/types/event_service.py b/google/cloud/talent_v4/types/event_service.py index 264d2f2d..8a328f9a 100644 --- a/google/cloud/talent_v4/types/event_service.py +++ b/google/cloud/talent_v4/types/event_service.py @@ -36,7 +36,7 @@ class CreateClientEventRequest(proto.Message): The format is "projects/{project_id}/tenants/{tenant_id}", for example, "projects/foo/tenants/bar". - client_event (~.event.ClientEvent): + client_event (google.cloud.talent_v4.types.ClientEvent): Required. Events issued when end user interacts with customer's application that uses Cloud Talent Solution. diff --git a/google/cloud/talent_v4/types/filters.py b/google/cloud/talent_v4/types/filters.py index 62a8aa57..482632fa 100644 --- a/google/cloud/talent_v4/types/filters.py +++ b/google/cloud/talent_v4/types/filters.py @@ -65,7 +65,7 @@ class JobQuery(proto.Message): For example, "projects/foo/tenants/bar/companies/baz". At most 20 company filters are allowed. - location_filters (Sequence[~.filters.LocationFilter]): + location_filters (Sequence[google.cloud.talent_v4.types.LocationFilter]): The location filter specifies geo-regions containing the jobs to search against. See [LocationFilter][google.cloud.talent.v4.LocationFilter] for @@ -83,7 +83,7 @@ class JobQuery(proto.Message): locations. At most 5 location filters are allowed. - job_categories (Sequence[~.common.JobCategory]): + job_categories (Sequence[google.cloud.talent_v4.types.JobCategory]): The category filter specifies the categories of jobs to search against. See [JobCategory][google.cloud.talent.v4.JobCategory] for more @@ -94,7 +94,7 @@ class JobQuery(proto.Message): If multiple values are specified, jobs from any of the specified categories are searched against. - commute_filter (~.filters.CommuteFilter): + commute_filter (google.cloud.talent_v4.types.CommuteFilter): Allows filtering jobs by commute time with different travel methods (for example, driving or public transit). @@ -118,7 +118,7 @@ class JobQuery(proto.Message): companies. At most 20 company display name filters are allowed. - compensation_filter (~.filters.CompensationFilter): + compensation_filter (google.cloud.talent_v4.types.CompensationFilter): This search filter is applied only to [Job.compensation_info][google.cloud.talent.v4.Job.compensation_info]. For example, if the filter is specified as "Hourly job with @@ -157,7 +157,7 @@ class JobQuery(proto.Message): misspelled query, for example, "enginee" is corrected to "engineer". Defaults to false: a spell check is performed. - employment_types (Sequence[~.common.EmploymentType]): + employment_types (Sequence[google.cloud.talent_v4.types.EmploymentType]): The employment type filter specifies the employment type of jobs to search against, such as [EmploymentType.FULL_TIME][google.cloud.talent.v4.EmploymentType.FULL_TIME]. @@ -180,7 +180,7 @@ class JobQuery(proto.Message): Languages `__. At most 10 language code filters are allowed. - publish_time_range (~.common.TimestampRange): + publish_time_range (google.cloud.talent_v4.types.TimestampRange): Jobs published within a range specified by this filter are searched against. excluded_jobs (Sequence[str]): @@ -246,7 +246,7 @@ class LocationFilter(proto.Message): See https://www.unicode.org/cldr/charts/30/supplemental/territory_information.html for details. Example: "CH" for Switzerland. - lat_lng (~.latlng.LatLng): + lat_lng (google.type.latlng_pb2.LatLng): The latitude and longitude of the geographic center to search from. This field is ignored if ``address`` is provided. @@ -255,7 +255,7 @@ class LocationFilter(proto.Message): searched for is identified as a city or smaller. This field is ignored if the location being searched for is a state or larger. - telecommute_preference (~.filters.LocationFilter.TelecommutePreference): + telecommute_preference (google.cloud.talent_v4.types.LocationFilter.TelecommutePreference): Allows the client to return jobs without a set location, specifically, telecommuting jobs (telecommuting is considered by the service as a special location. @@ -304,12 +304,12 @@ class CompensationFilter(proto.Message): r"""Filter on job compensation type and amount. Attributes: - type_ (~.filters.CompensationFilter.FilterType): + type_ (google.cloud.talent_v4.types.CompensationFilter.FilterType): Required. Type of filter. - units (Sequence[~.common.CompensationInfo.CompensationUnit]): + units (Sequence[google.cloud.talent_v4.types.CompensationInfo.CompensationUnit]): Required. Specify desired ``base compensation entry's`` [CompensationInfo.CompensationUnit][google.cloud.talent.v4.CompensationInfo.CompensationUnit]. - range_ (~.common.CompensationInfo.CompensationRange): + range_ (google.cloud.talent_v4.types.CompensationInfo.CompensationRange): Compensation range. include_jobs_with_unspecified_compensation_range (bool): If set to true, jobs with unspecified @@ -341,13 +341,13 @@ class CommuteFilter(proto.Message): r"""Parameters needed for commute search. Attributes: - commute_method (~.common.CommuteMethod): + commute_method (google.cloud.talent_v4.types.CommuteMethod): Required. The method of transportation to calculate the commute time for. - start_coordinates (~.latlng.LatLng): + start_coordinates (google.type.latlng_pb2.LatLng): Required. The latitude and longitude of the location to calculate the commute time from. - travel_duration (~.duration.Duration): + travel_duration (google.protobuf.duration_pb2.Duration): Required. The maximum travel time in seconds. The maximum allowed value is ``3600s`` (one hour). Format is ``123s``. allow_imprecise_addresses (bool): @@ -357,10 +357,10 @@ class CommuteFilter(proto.Message): used. If this field is set to ``false`` or isn't specified, only jobs that include street level addresses will be returned by commute search. - road_traffic (~.filters.CommuteFilter.RoadTraffic): + road_traffic (google.cloud.talent_v4.types.CommuteFilter.RoadTraffic): Specifies the traffic density to use when calculating commute time. - departure_time (~.timeofday.TimeOfDay): + departure_time (google.type.timeofday_pb2.TimeOfDay): The departure time used to calculate traffic impact, represented as [google.type.TimeOfDay][google.type.TimeOfDay] in local time diff --git a/google/cloud/talent_v4/types/histogram.py b/google/cloud/talent_v4/types/histogram.py index ac6443df..ec9484c9 100644 --- a/google/cloud/talent_v4/types/histogram.py +++ b/google/cloud/talent_v4/types/histogram.py @@ -48,7 +48,7 @@ class HistogramQueryResult(proto.Message): Attributes: histogram_query (str): Requested histogram expression. - histogram (Sequence[~.gct_histogram.HistogramQueryResult.HistogramEntry]): + histogram (Sequence[google.cloud.talent_v4.types.HistogramQueryResult.HistogramEntry]): A map from the values of the facet associated with distinct values to the number of matching entries with corresponding value. diff --git a/google/cloud/talent_v4/types/job.py b/google/cloud/talent_v4/types/job.py index f1320f94..2bd27c59 100644 --- a/google/cloud/talent_v4/types/job.py +++ b/google/cloud/talent_v4/types/job.py @@ -111,15 +111,15 @@ class Job(proto.Message): experience. The maximum number of allowed characters is 500. - application_info (~.job.Job.ApplicationInfo): + application_info (google.cloud.talent_v4.types.Job.ApplicationInfo): Job application information. - job_benefits (Sequence[~.common.JobBenefit]): + job_benefits (Sequence[google.cloud.talent_v4.types.JobBenefit]): The benefits included with the job. - compensation_info (~.common.CompensationInfo): + compensation_info (google.cloud.talent_v4.types.CompensationInfo): Job compensation information (a.k.a. "pay rate") i.e., the compensation that will paid to the employee. - custom_attributes (Sequence[~.job.Job.CustomAttributesEntry]): + custom_attributes (Sequence[google.cloud.talent_v4.types.Job.CustomAttributesEntry]): A map of fields to hold both filterable and non-filterable custom job attributes that are not covered by the provided structured fields. @@ -134,7 +134,7 @@ class Job(proto.Message): than 255 characters. For unfilterable ``string_values``, the maximum total size of ``string_values`` across all keys is 50KB. - degree_types (Sequence[~.common.DegreeType]): + degree_types (Sequence[google.cloud.talent_v4.types.DegreeType]): The desired education degrees for the job, such as Bachelors, Masters. department (str): @@ -142,7 +142,7 @@ class Job(proto.Message): company with the open position. The maximum number of allowed characters is 255. - employment_types (Sequence[~.common.EmploymentType]): + employment_types (Sequence[google.cloud.talent_v4.types.EmploymentType]): The employment type(s) of a job, for example, [full time][google.cloud.talent.v4.EmploymentType.FULL_TIME] or [part @@ -167,7 +167,7 @@ class Job(proto.Message): present, detected language code based on [Job.description][google.cloud.talent.v4.Job.description] is assigned, otherwise defaults to 'en_US'. - job_level (~.common.JobLevel): + job_level (google.cloud.talent_v4.types.JobLevel): The experience level associated with the job, such as "Entry Level". promotion_value (int): @@ -200,7 +200,7 @@ class Job(proto.Message): markup tags. The maximum number of allowed characters is 10,000. - posting_region (~.common.PostingRegion): + posting_region (google.cloud.talent_v4.types.PostingRegion): The job [PostingRegion][google.cloud.talent.v4.PostingRegion] (for example, state, country) throughout which the job is @@ -215,7 +215,7 @@ class Job(proto.Message): setting job [Job.addresses][google.cloud.talent.v4.Job.addresses] to the same location level as this field is strongly recommended. - visibility (~.common.Visibility): + visibility (google.cloud.talent_v4.types.Visibility): Deprecated. The job is only visible to the owner. The visibility of the job. @@ -223,21 +223,21 @@ class Job(proto.Message): Defaults to [Visibility.ACCOUNT_ONLY][google.cloud.talent.v4.Visibility.ACCOUNT_ONLY] if not specified. - job_start_time (~.timestamp.Timestamp): + job_start_time (google.protobuf.timestamp_pb2.Timestamp): The start timestamp of the job in UTC time zone. Typically this field is used for contracting engagements. Invalid timestamps are ignored. - job_end_time (~.timestamp.Timestamp): + job_end_time (google.protobuf.timestamp_pb2.Timestamp): The end timestamp of the job. Typically this field is used for contracting engagements. Invalid timestamps are ignored. - posting_publish_time (~.timestamp.Timestamp): + posting_publish_time (google.protobuf.timestamp_pb2.Timestamp): The timestamp this job posting was most recently published. The default value is the time the request arrives at the server. Invalid timestamps are ignored. - posting_expire_time (~.timestamp.Timestamp): + posting_expire_time (google.protobuf.timestamp_pb2.Timestamp): Strongly recommended for the best service experience. The expiration timestamp of the job. After this timestamp, @@ -295,19 +295,19 @@ class Job(proto.Message): the masks are empty meaning that every field is updated, the job posting expires after 30 days from the job's last update time. Otherwise the expiration date isn't updated. - posting_create_time (~.timestamp.Timestamp): + posting_create_time (google.protobuf.timestamp_pb2.Timestamp): Output only. The timestamp when this job posting was created. - posting_update_time (~.timestamp.Timestamp): + posting_update_time (google.protobuf.timestamp_pb2.Timestamp): Output only. The timestamp when this job posting was last updated. company_display_name (str): Output only. Display name of the company listing the job. - derived_info (~.job.Job.DerivedInfo): + derived_info (google.cloud.talent_v4.types.Job.DerivedInfo): Output only. Derived details about the job posting. - processing_options (~.job.Job.ProcessingOptions): + processing_options (google.cloud.talent_v4.types.Job.ProcessingOptions): Options for job processing. """ @@ -347,7 +347,7 @@ class DerivedInfo(proto.Message): r"""Derived details about the job posting. Attributes: - locations (Sequence[~.common.Location]): + locations (Sequence[google.cloud.talent_v4.types.Location]): Structured locations of the job, resolved from [Job.addresses][google.cloud.talent.v4.Job.addresses]. @@ -355,7 +355,7 @@ class DerivedInfo(proto.Message): are exactly matched to [Job.addresses][google.cloud.talent.v4.Job.addresses] in the same order. - job_categories (Sequence[~.common.JobCategory]): + job_categories (Sequence[google.cloud.talent_v4.types.JobCategory]): Job categories derived from [Job.title][google.cloud.talent.v4.Job.title] and [Job.description][google.cloud.talent.v4.Job.description]. @@ -376,7 +376,7 @@ class ProcessingOptions(proto.Message): disable_street_address_resolution (bool): If set to ``true``, the service does not attempt to resolve a more precise address for the job. - html_sanitization (~.common.HtmlSanitization): + html_sanitization (google.cloud.talent_v4.types.HtmlSanitization): Option for job HTML content sanitization. Applied fields are: diff --git a/google/cloud/talent_v4/types/job_service.py b/google/cloud/talent_v4/types/job_service.py index 4b53ed10..78289bbe 100644 --- a/google/cloud/talent_v4/types/job_service.py +++ b/google/cloud/talent_v4/types/job_service.py @@ -74,7 +74,7 @@ class CreateJobRequest(proto.Message): The format is "projects/{project_id}/tenants/{tenant_id}". For example, "projects/foo/tenants/bar". - job (~.gct_job.Job): + job (google.cloud.talent_v4.types.Job): Required. The Job to be created. """ @@ -102,9 +102,9 @@ class UpdateJobRequest(proto.Message): r"""Update job request. Attributes: - job (~.gct_job.Job): + job (google.cloud.talent_v4.types.Job): Required. The Job to be updated. - update_mask (~.field_mask.FieldMask): + update_mask (google.protobuf.field_mask_pb2.FieldMask): Strongly recommended for the best service experience. If @@ -182,7 +182,7 @@ class ListJobsRequest(proto.Message): maximum allowed page size is 100. Default is 100 if empty or a number < 1 is specified. - job_view (~.job_service.JobView): + job_view (google.cloud.talent_v4.types.JobView): The desired job attributes returned for jobs in the search response. Defaults to [JobView.JOB_VIEW_FULL][google.cloud.talent.v4.JobView.JOB_VIEW_FULL] @@ -204,13 +204,13 @@ class ListJobsResponse(proto.Message): r"""List jobs response. Attributes: - jobs (Sequence[~.gct_job.Job]): + jobs (Sequence[google.cloud.talent_v4.types.Job]): The Jobs for a given company. The maximum number of items returned is based on the limit field provided in the request. next_page_token (str): A token to retrieve the next page of results. - metadata (~.common.ResponseMetadata): + metadata (google.cloud.talent_v4.types.ResponseMetadata): Additional information for the API invocation, such as the request tracking id. """ @@ -235,17 +235,17 @@ class SearchJobsRequest(proto.Message): The format is "projects/{project_id}/tenants/{tenant_id}". For example, "projects/foo/tenants/bar". - search_mode (~.job_service.SearchJobsRequest.SearchMode): + search_mode (google.cloud.talent_v4.types.SearchJobsRequest.SearchMode): Mode of a search. Defaults to [SearchMode.JOB_SEARCH][google.cloud.talent.v4.SearchJobsRequest.SearchMode.JOB_SEARCH]. - request_metadata (~.common.RequestMetadata): + request_metadata (google.cloud.talent_v4.types.RequestMetadata): Required. The meta information collected about the job searcher, used to improve the search quality of the service. The identifiers (such as ``user_id``) are provided by users, and must be unique and consistent. - job_query (~.filters.JobQuery): + job_query (google.cloud.talent_v4.types.JobQuery): Query used to search against jobs, such as keyword, location filters, etc. enable_broadening (bool): @@ -255,7 +255,7 @@ class SearchJobsRequest(proto.Message): results list. Defaults to false. - histogram_queries (Sequence[~.histogram.HistogramQuery]): + histogram_queries (Sequence[google.cloud.talent_v4.types.HistogramQuery]): An expression specifies a histogram request against matching jobs. @@ -368,7 +368,7 @@ class SearchJobsRequest(proto.Message): - ``count(base_compensation, [bucket(1000, 10000), bucket(10000, 100000), bucket(100000, MAX)])`` - ``count(string_custom_attribute["some-string-custom-attribute"])`` - ``count(numeric_custom_attribute["some-numeric-custom-attribute"], [bucket(MIN, 0, "negative"), bucket(0, MAX, "non-negative"])`` - job_view (~.job_service.JobView): + job_view (google.cloud.talent_v4.types.JobView): The desired job attributes returned for jobs in the search response. Defaults to [JobView.JOB_VIEW_SMALL][google.cloud.talent.v4.JobView.JOB_VIEW_SMALL] @@ -458,7 +458,7 @@ class SearchJobsRequest(proto.Message): (37.4 feet). Diversification strategy is still applied unless explicitly disabled in [diversification_level][google.cloud.talent.v4.SearchJobsRequest.diversification_level]. - diversification_level (~.job_service.SearchJobsRequest.DiversificationLevel): + diversification_level (google.cloud.talent_v4.types.SearchJobsRequest.DiversificationLevel): Controls whether highly similar jobs are returned next to each other in the search results. Jobs are identified as highly similar based on their titles, job categories, and @@ -470,7 +470,7 @@ class SearchJobsRequest(proto.Message): Defaults to [DiversificationLevel.SIMPLE][google.cloud.talent.v4.SearchJobsRequest.DiversificationLevel.SIMPLE] if no value is specified. - custom_ranking_info (~.job_service.SearchJobsRequest.CustomRankingInfo): + custom_ranking_info (google.cloud.talent_v4.types.SearchJobsRequest.CustomRankingInfo): Controls over how job documents get ranked on top of existing relevance score (determined by API algorithm). @@ -528,7 +528,7 @@ class CustomRankingInfo(proto.Message): [SearchJobsRequest][google.cloud.talent.v4.SearchJobsRequest]. Attributes: - importance_level (~.job_service.SearchJobsRequest.CustomRankingInfo.ImportanceLevel): + importance_level (google.cloud.talent_v4.types.SearchJobsRequest.CustomRankingInfo.ImportanceLevel): Required. Controls over how important the score of [CustomRankingInfo.ranking_expression][google.cloud.talent.v4.SearchJobsRequest.CustomRankingInfo.ranking_expression] gets applied to job's final ranking position. @@ -623,17 +623,17 @@ class SearchJobsResponse(proto.Message): r"""Response for SearchJob method. Attributes: - matching_jobs (Sequence[~.job_service.SearchJobsResponse.MatchingJob]): + matching_jobs (Sequence[google.cloud.talent_v4.types.SearchJobsResponse.MatchingJob]): The Job entities that match the specified [SearchJobsRequest][google.cloud.talent.v4.SearchJobsRequest]. - histogram_query_results (Sequence[~.histogram.HistogramQueryResult]): + histogram_query_results (Sequence[google.cloud.talent_v4.types.HistogramQueryResult]): The histogram results that match with specified [SearchJobsRequest.histogram_queries][google.cloud.talent.v4.SearchJobsRequest.histogram_queries]. next_page_token (str): The token that specifies the starting position of the next page of results. This field is empty if there are no more results. - location_filters (Sequence[~.common.Location]): + location_filters (Sequence[google.cloud.talent_v4.types.Location]): The location filters that the service applied to the specified query. If any filters are lat-lng based, the [Location.location_type][google.cloud.talent.v4.Location.location_type] @@ -644,7 +644,7 @@ class SearchJobsResponse(proto.Message): query. Note: This size is precise only if the total is less than 100,000. - metadata (~.common.ResponseMetadata): + metadata (google.cloud.talent_v4.types.ResponseMetadata): Additional information for the API invocation, such as the request tracking id. broadened_query_jobs_count (int): @@ -659,7 +659,7 @@ class SearchJobsResponse(proto.Message): broadening) query. If this field is non-zero, subsequent requests with offset after this result set should contain all broadened results. - spell_correction (~.common.SpellingCorrection): + spell_correction (google.cloud.talent_v4.types.SpellingCorrection): The spell checking result, and correction. """ @@ -668,7 +668,7 @@ class MatchingJob(proto.Message): [SearchJobsResponse][google.cloud.talent.v4.SearchJobsResponse]. Attributes: - job (~.gct_job.Job): + job (google.cloud.talent_v4.types.Job): Job resource that matches the specified [SearchJobsRequest][google.cloud.talent.v4.SearchJobsRequest]. job_summary (str): @@ -687,7 +687,7 @@ class MatchingJob(proto.Message): keywords, if available. All HTML tags in the original fields are stripped when returned in this field, and matching query keywords are enclosed in HTML bold tags. - commute_info (~.job_service.SearchJobsResponse.CommuteInfo): + commute_info (google.cloud.talent_v4.types.SearchJobsResponse.CommuteInfo): Commute information which is generated based on specified [CommuteFilter][google.cloud.talent.v4.CommuteFilter]. """ @@ -708,10 +708,10 @@ class CommuteInfo(proto.Message): r"""Commute details related to this job. Attributes: - job_location (~.common.Location): + job_location (google.cloud.talent_v4.types.Location): Location used as the destination in the commute calculation. - travel_duration (~.duration.Duration): + travel_duration (google.protobuf.duration_pb2.Duration): The number of seconds required to travel to the job location from the query location. A duration of 0 seconds indicates that the job @@ -762,7 +762,7 @@ class BatchCreateJobsRequest(proto.Message): The format is "projects/{project_id}/tenants/{tenant_id}". For example, "projects/foo/tenants/bar". - jobs (Sequence[~.gct_job.Job]): + jobs (Sequence[google.cloud.talent_v4.types.Job]): Required. The jobs to be created. A maximum of 200 jobs can be created in a batch. """ @@ -782,10 +782,10 @@ class BatchUpdateJobsRequest(proto.Message): The format is "projects/{project_id}/tenants/{tenant_id}". For example, "projects/foo/tenants/bar". - jobs (Sequence[~.gct_job.Job]): + jobs (Sequence[google.cloud.talent_v4.types.Job]): Required. The jobs to be updated. A maximum of 200 jobs can be updated in a batch. - update_mask (~.field_mask.FieldMask): + update_mask (google.protobuf.field_mask_pb2.FieldMask): Strongly recommended for the best service experience. Be aware that it will also increase latency when checking the status of a batch operation. @@ -848,7 +848,7 @@ class JobResult(proto.Message): r"""Mutation result of a job from a batch operation. Attributes: - job (~.gct_job.Job): + job (google.cloud.talent_v4.types.Job): Here [Job][google.cloud.talent.v4.Job] only contains basic information including [name][google.cloud.talent.v4.Job.name], @@ -858,7 +858,7 @@ class JobResult(proto.Message): [requisition_id][google.cloud.talent.v4.Job.requisition_id], use getJob method to retrieve detailed information of the created/updated job. - status (~.gr_status.Status): + status (google.rpc.status_pb2.Status): The status of the job processed. This field is populated if the processing of the [job][google.cloud.talent.v4.JobResult.job] fails. @@ -877,7 +877,7 @@ class BatchCreateJobsResponse(proto.Message): in case of success. Attributes: - job_results (Sequence[~.job_service.JobResult]): + job_results (Sequence[google.cloud.talent_v4.types.JobResult]): List of job mutation results from a batch create operation. It can change until operation status is FINISHED, FAILED or CANCELLED. @@ -894,7 +894,7 @@ class BatchUpdateJobsResponse(proto.Message): in case of success. Attributes: - job_results (Sequence[~.job_service.JobResult]): + job_results (Sequence[google.cloud.talent_v4.types.JobResult]): List of job mutation results from a batch update operation. It can change until operation status is FINISHED, FAILED or CANCELLED. @@ -911,7 +911,7 @@ class BatchDeleteJobsResponse(proto.Message): in case of success. Attributes: - job_results (Sequence[~.job_service.JobResult]): + job_results (Sequence[google.cloud.talent_v4.types.JobResult]): List of job mutation results from a batch delete operation. It can change until operation status is FINISHED, FAILED or CANCELLED. diff --git a/google/cloud/talent_v4/types/tenant_service.py b/google/cloud/talent_v4/types/tenant_service.py index 2f77b0d1..be5e4d8d 100644 --- a/google/cloud/talent_v4/types/tenant_service.py +++ b/google/cloud/talent_v4/types/tenant_service.py @@ -46,7 +46,7 @@ class CreateTenantRequest(proto.Message): The format is "projects/{project_id}", for example, "projects/foo". - tenant (~.gct_tenant.Tenant): + tenant (google.cloud.talent_v4.types.Tenant): Required. The tenant to be created. """ @@ -73,10 +73,10 @@ class UpdateTenantRequest(proto.Message): r"""Request for updating a specified tenant. Attributes: - tenant (~.gct_tenant.Tenant): + tenant (google.cloud.talent_v4.types.Tenant): Required. The tenant resource to replace the current resource in the system. - update_mask (~.field_mask.FieldMask): + update_mask (google.protobuf.field_mask_pb2.FieldMask): Strongly recommended for the best service experience. If @@ -139,11 +139,11 @@ class ListTenantsResponse(proto.Message): r"""The List tenants response object. Attributes: - tenants (Sequence[~.gct_tenant.Tenant]): + tenants (Sequence[google.cloud.talent_v4.types.Tenant]): Tenants for the current client. next_page_token (str): A token to retrieve the next page of results. - metadata (~.common.ResponseMetadata): + metadata (google.cloud.talent_v4.types.ResponseMetadata): Additional information for the API invocation, such as the request tracking id. """ diff --git a/google/cloud/talent_v4beta1/services/application_service/async_client.py b/google/cloud/talent_v4beta1/services/application_service/async_client.py index 8236846b..6c6bb683 100644 --- a/google/cloud/talent_v4beta1/services/application_service/async_client.py +++ b/google/cloud/talent_v4beta1/services/application_service/async_client.py @@ -92,7 +92,36 @@ class ApplicationServiceAsyncClient: ApplicationServiceClient.parse_common_location_path ) - from_service_account_file = ApplicationServiceClient.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: + ApplicationServiceAsyncClient: The constructed client. + """ + return ApplicationServiceClient.from_service_account_info.__func__(ApplicationServiceAsyncClient, 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: + ApplicationServiceAsyncClient: The constructed client. + """ + return ApplicationServiceClient.from_service_account_file.__func__(ApplicationServiceAsyncClient, filename, *args, **kwargs) # type: ignore + from_service_account_json = from_service_account_file @property @@ -170,7 +199,7 @@ async def create_application( r"""Creates a new application entity. Args: - request (:class:`~.application_service.CreateApplicationRequest`): + request (:class:`google.cloud.talent_v4beta1.types.CreateApplicationRequest`): The request object. The Request of the CreateApplication method. parent (:class:`str`): @@ -180,12 +209,14 @@ async def create_application( The format is "projects/{project_id}/tenants/{tenant_id}/profiles/{profile_id}". For example, "projects/foo/tenants/bar/profiles/baz". + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - application (:class:`~.gct_application.Application`): + application (:class:`google.cloud.talent_v4beta1.types.Application`): Required. The application to be created. + This corresponds to the ``application`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -197,7 +228,7 @@ async def create_application( sent along with the request as metadata. Returns: - ~.gct_application.Application: + google.cloud.talent_v4beta1.types.Application: Resource that represents a job application record of a candidate. @@ -254,7 +285,7 @@ async def get_application( r"""Retrieves specified application. Args: - request (:class:`~.application_service.GetApplicationRequest`): + request (:class:`google.cloud.talent_v4beta1.types.GetApplicationRequest`): The request object. Request for getting a application by name. name (:class:`str`): @@ -265,6 +296,7 @@ async def get_application( "projects/{project_id}/tenants/{tenant_id}/profiles/{profile_id}/applications/{application_id}". For example, "projects/foo/tenants/bar/profiles/baz/applications/qux". + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -276,7 +308,7 @@ async def get_application( sent along with the request as metadata. Returns: - ~.application.Application: + google.cloud.talent_v4beta1.types.Application: Resource that represents a job application record of a candidate. @@ -310,6 +342,7 @@ async def get_application( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=DEFAULT_CLIENT_INFO, @@ -339,13 +372,14 @@ async def update_application( r"""Updates specified application. Args: - request (:class:`~.application_service.UpdateApplicationRequest`): + request (:class:`google.cloud.talent_v4beta1.types.UpdateApplicationRequest`): The request object. Request for updating a specified application. - application (:class:`~.gct_application.Application`): + application (:class:`google.cloud.talent_v4beta1.types.Application`): Required. The application resource to replace the current resource in the system. + This corresponds to the ``application`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -357,7 +391,7 @@ async def update_application( sent along with the request as metadata. Returns: - ~.gct_application.Application: + google.cloud.talent_v4beta1.types.Application: Resource that represents a job application record of a candidate. @@ -414,7 +448,7 @@ async def delete_application( r"""Deletes specified application. Args: - request (:class:`~.application_service.DeleteApplicationRequest`): + request (:class:`google.cloud.talent_v4beta1.types.DeleteApplicationRequest`): The request object. Request to delete a application. name (:class:`str`): Required. The resource name of the application to be @@ -424,6 +458,7 @@ async def delete_application( "projects/{project_id}/tenants/{tenant_id}/profiles/{profile_id}/applications/{application_id}". For example, "projects/foo/tenants/bar/profiles/baz/applications/qux". + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -463,6 +498,7 @@ async def delete_application( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=DEFAULT_CLIENT_INFO, @@ -491,7 +527,7 @@ async def list_applications( r"""Lists all applications associated with the profile. Args: - request (:class:`~.application_service.ListApplicationsRequest`): + request (:class:`google.cloud.talent_v4beta1.types.ListApplicationsRequest`): The request object. List applications for which the client has ACL visibility. parent (:class:`str`): @@ -501,6 +537,7 @@ async def list_applications( The format is "projects/{project_id}/tenants/{tenant_id}/profiles/{profile_id}", for example, "projects/foo/tenants/bar/profiles/baz". + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -512,7 +549,7 @@ async def list_applications( sent along with the request as metadata. Returns: - ~.pagers.ListApplicationsAsyncPager: + google.cloud.talent_v4beta1.services.application_service.pagers.ListApplicationsAsyncPager: The List applications response object. Iterating over this object will yield @@ -549,6 +586,7 @@ async def list_applications( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=DEFAULT_CLIENT_INFO, diff --git a/google/cloud/talent_v4beta1/services/application_service/client.py b/google/cloud/talent_v4beta1/services/application_service/client.py index b8204de1..f93ebd01 100644 --- a/google/cloud/talent_v4beta1/services/application_service/client.py +++ b/google/cloud/talent_v4beta1/services/application_service/client.py @@ -120,6 +120,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: + ApplicationServiceClient: 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 @@ -132,7 +148,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. + ApplicationServiceClient: The constructed client. """ credentials = service_account.Credentials.from_service_account_file(filename) kwargs["credentials"] = credentials @@ -290,10 +306,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, ~.ApplicationServiceTransport]): The + transport (Union[str, ApplicationServiceTransport]): 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 @@ -329,21 +345,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: @@ -386,7 +398,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, ) @@ -404,22 +416,24 @@ def create_application( r"""Creates a new application entity. Args: - request (:class:`~.application_service.CreateApplicationRequest`): + request (google.cloud.talent_v4beta1.types.CreateApplicationRequest): The request object. The Request of the CreateApplication method. - parent (:class:`str`): + parent (str): Required. Resource name of the profile under which the application is created. The format is "projects/{project_id}/tenants/{tenant_id}/profiles/{profile_id}". For example, "projects/foo/tenants/bar/profiles/baz". + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - application (:class:`~.gct_application.Application`): + application (google.cloud.talent_v4beta1.types.Application): Required. The application to be created. + This corresponds to the ``application`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -431,7 +445,7 @@ def create_application( sent along with the request as metadata. Returns: - ~.gct_application.Application: + google.cloud.talent_v4beta1.types.Application: Resource that represents a job application record of a candidate. @@ -489,10 +503,10 @@ def get_application( r"""Retrieves specified application. Args: - request (:class:`~.application_service.GetApplicationRequest`): + request (google.cloud.talent_v4beta1.types.GetApplicationRequest): The request object. Request for getting a application by name. - name (:class:`str`): + name (str): Required. The resource name of the application to be retrieved. @@ -500,6 +514,7 @@ def get_application( "projects/{project_id}/tenants/{tenant_id}/profiles/{profile_id}/applications/{application_id}". For example, "projects/foo/tenants/bar/profiles/baz/applications/qux". + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -511,7 +526,7 @@ def get_application( sent along with the request as metadata. Returns: - ~.application.Application: + google.cloud.talent_v4beta1.types.Application: Resource that represents a job application record of a candidate. @@ -567,13 +582,14 @@ def update_application( r"""Updates specified application. Args: - request (:class:`~.application_service.UpdateApplicationRequest`): + request (google.cloud.talent_v4beta1.types.UpdateApplicationRequest): The request object. Request for updating a specified application. - application (:class:`~.gct_application.Application`): + application (google.cloud.talent_v4beta1.types.Application): Required. The application resource to replace the current resource in the system. + This corresponds to the ``application`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -585,7 +601,7 @@ def update_application( sent along with the request as metadata. Returns: - ~.gct_application.Application: + google.cloud.talent_v4beta1.types.Application: Resource that represents a job application record of a candidate. @@ -643,9 +659,9 @@ def delete_application( r"""Deletes specified application. Args: - request (:class:`~.application_service.DeleteApplicationRequest`): + request (google.cloud.talent_v4beta1.types.DeleteApplicationRequest): The request object. Request to delete a application. - name (:class:`str`): + name (str): Required. The resource name of the application to be deleted. @@ -653,6 +669,7 @@ def delete_application( "projects/{project_id}/tenants/{tenant_id}/profiles/{profile_id}/applications/{application_id}". For example, "projects/foo/tenants/bar/profiles/baz/applications/qux". + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -713,16 +730,17 @@ def list_applications( r"""Lists all applications associated with the profile. Args: - request (:class:`~.application_service.ListApplicationsRequest`): + request (google.cloud.talent_v4beta1.types.ListApplicationsRequest): The request object. List applications for which the client has ACL visibility. - parent (:class:`str`): + parent (str): Required. Resource name of the profile under which the application is created. The format is "projects/{project_id}/tenants/{tenant_id}/profiles/{profile_id}", for example, "projects/foo/tenants/bar/profiles/baz". + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -734,7 +752,7 @@ def list_applications( sent along with the request as metadata. Returns: - ~.pagers.ListApplicationsPager: + google.cloud.talent_v4beta1.services.application_service.pagers.ListApplicationsPager: The List applications response object. Iterating over this object will yield diff --git a/google/cloud/talent_v4beta1/services/application_service/pagers.py b/google/cloud/talent_v4beta1/services/application_service/pagers.py index 0525dae8..1aa9124c 100644 --- a/google/cloud/talent_v4beta1/services/application_service/pagers.py +++ b/google/cloud/talent_v4beta1/services/application_service/pagers.py @@ -15,7 +15,16 @@ # limitations under the License. # -from typing import Any, AsyncIterable, Awaitable, Callable, Iterable, Sequence, Tuple +from typing import ( + Any, + AsyncIterable, + Awaitable, + Callable, + Iterable, + Sequence, + Tuple, + Optional, +) from google.cloud.talent_v4beta1.types import application from google.cloud.talent_v4beta1.types import application_service @@ -25,7 +34,7 @@ class ListApplicationsPager: """A pager for iterating through ``list_applications`` requests. This class thinly wraps an initial - :class:`~.application_service.ListApplicationsResponse` object, and + :class:`google.cloud.talent_v4beta1.types.ListApplicationsResponse` object, and provides an ``__iter__`` method to iterate through its ``applications`` field. @@ -34,7 +43,7 @@ class ListApplicationsPager: through the ``applications`` field on the corresponding responses. - All the usual :class:`~.application_service.ListApplicationsResponse` + All the usual :class:`google.cloud.talent_v4beta1.types.ListApplicationsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -52,9 +61,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.application_service.ListApplicationsRequest`): + request (google.cloud.talent_v4beta1.types.ListApplicationsRequest): The initial request object. - response (:class:`~.application_service.ListApplicationsResponse`): + response (google.cloud.talent_v4beta1.types.ListApplicationsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -87,7 +96,7 @@ class ListApplicationsAsyncPager: """A pager for iterating through ``list_applications`` requests. This class thinly wraps an initial - :class:`~.application_service.ListApplicationsResponse` object, and + :class:`google.cloud.talent_v4beta1.types.ListApplicationsResponse` object, and provides an ``__aiter__`` method to iterate through its ``applications`` field. @@ -96,7 +105,7 @@ class ListApplicationsAsyncPager: through the ``applications`` field on the corresponding responses. - All the usual :class:`~.application_service.ListApplicationsResponse` + All the usual :class:`google.cloud.talent_v4beta1.types.ListApplicationsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -114,9 +123,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.application_service.ListApplicationsRequest`): + request (google.cloud.talent_v4beta1.types.ListApplicationsRequest): The initial request object. - response (:class:`~.application_service.ListApplicationsResponse`): + response (google.cloud.talent_v4beta1.types.ListApplicationsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. diff --git a/google/cloud/talent_v4beta1/services/application_service/transports/base.py b/google/cloud/talent_v4beta1/services/application_service/transports/base.py index 83ba6405..9667920d 100644 --- a/google/cloud/talent_v4beta1/services/application_service/transports/base.py +++ b/google/cloud/talent_v4beta1/services/application_service/transports/base.py @@ -73,10 +73,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. @@ -84,6 +84,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: @@ -93,20 +96,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 = { @@ -122,6 +122,7 @@ def _prep_wrapped_messages(self, client_info): predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=client_info, @@ -138,6 +139,7 @@ def _prep_wrapped_messages(self, client_info): predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=client_info, @@ -151,6 +153,7 @@ def _prep_wrapped_messages(self, client_info): predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=client_info, diff --git a/google/cloud/talent_v4beta1/services/application_service/transports/grpc.py b/google/cloud/talent_v4beta1/services/application_service/transports/grpc.py index 07e17b28..e47f721b 100644 --- a/google/cloud/talent_v4beta1/services/application_service/transports/grpc.py +++ b/google/cloud/talent_v4beta1/services/application_service/transports/grpc.py @@ -61,6 +61,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: @@ -91,6 +92,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): @@ -105,72 +110,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), @@ -178,17 +171,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( @@ -202,7 +186,7 @@ def create_channel( ) -> grpc.Channel: """Create and return a gRPC channel object. Args: - address (Optional[str]): The host for the channel to use. + host (Optional[str]): The host for the channel to use. credentials (Optional[~.Credentials]): The authorization credentials to attach to requests. These credentials identify this application to the service. If diff --git a/google/cloud/talent_v4beta1/services/application_service/transports/grpc_asyncio.py b/google/cloud/talent_v4beta1/services/application_service/transports/grpc_asyncio.py index 0727f683..95164149 100644 --- a/google/cloud/talent_v4beta1/services/application_service/transports/grpc_asyncio.py +++ b/google/cloud/talent_v4beta1/services/application_service/transports/grpc_asyncio.py @@ -65,7 +65,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 @@ -105,6 +105,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: @@ -136,12 +137,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: @@ -150,72 +155,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), @@ -223,17 +216,8 @@ def __init__( ], ) - # Run the base constructor. - super().__init__( - host=host, - credentials=credentials, - credentials_file=credentials_file, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - client_info=client_info, - ) - - self._stubs = {} + # 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/talent_v4beta1/services/company_service/async_client.py b/google/cloud/talent_v4beta1/services/company_service/async_client.py index 98c39a8e..30a4dfff 100644 --- a/google/cloud/talent_v4beta1/services/company_service/async_client.py +++ b/google/cloud/talent_v4beta1/services/company_service/async_client.py @@ -81,7 +81,36 @@ class CompanyServiceAsyncClient: CompanyServiceClient.parse_common_location_path ) - from_service_account_file = CompanyServiceClient.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: + CompanyServiceAsyncClient: The constructed client. + """ + return CompanyServiceClient.from_service_account_info.__func__(CompanyServiceAsyncClient, 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: + CompanyServiceAsyncClient: The constructed client. + """ + return CompanyServiceClient.from_service_account_file.__func__(CompanyServiceAsyncClient, filename, *args, **kwargs) # type: ignore + from_service_account_json = from_service_account_file @property @@ -158,7 +187,7 @@ async def create_company( r"""Creates a new company entity. Args: - request (:class:`~.company_service.CreateCompanyRequest`): + request (:class:`google.cloud.talent_v4beta1.types.CreateCompanyRequest`): The request object. The Request of the CreateCompany method. parent (:class:`str`): @@ -170,10 +199,11 @@ async def create_company( example, "projects/foo/tenant/bar". If tenant id is unspecified, a default tenant is created, for example, "projects/foo". + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - company (:class:`~.gct_company.Company`): + company (:class:`google.cloud.talent_v4beta1.types.Company`): Required. The company to be created. This corresponds to the ``company`` field on the ``request`` instance; if ``request`` is provided, this @@ -186,7 +216,7 @@ async def create_company( sent along with the request as metadata. Returns: - ~.gct_company.Company: + google.cloud.talent_v4beta1.types.Company: A Company resource represents a company in the service. A company is the entity that owns job postings, that is, @@ -247,7 +277,7 @@ async def get_company( r"""Retrieves specified company. Args: - request (:class:`~.company_service.GetCompanyRequest`): + request (:class:`google.cloud.talent_v4beta1.types.GetCompanyRequest`): The request object. Request for getting a company by name. name (:class:`str`): @@ -261,6 +291,7 @@ async def get_company( If tenant id is unspecified, the default tenant is used, for example, "projects/api-test-project/companies/bar". + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -272,7 +303,7 @@ async def get_company( sent along with the request as metadata. Returns: - ~.company.Company: + google.cloud.talent_v4beta1.types.Company: A Company resource represents a company in the service. A company is the entity that owns job postings, that is, @@ -310,6 +341,7 @@ async def get_company( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=DEFAULT_CLIENT_INFO, @@ -339,13 +371,14 @@ async def update_company( r"""Updates specified company. Args: - request (:class:`~.company_service.UpdateCompanyRequest`): + request (:class:`google.cloud.talent_v4beta1.types.UpdateCompanyRequest`): The request object. Request for updating a specified company. - company (:class:`~.gct_company.Company`): + company (:class:`google.cloud.talent_v4beta1.types.Company`): Required. The company resource to replace the current resource in the system. + This corresponds to the ``company`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -357,7 +390,7 @@ async def update_company( sent along with the request as metadata. Returns: - ~.gct_company.Company: + google.cloud.talent_v4beta1.types.Company: A Company resource represents a company in the service. A company is the entity that owns job postings, that is, @@ -420,7 +453,7 @@ async def delete_company( it. Args: - request (:class:`~.company_service.DeleteCompanyRequest`): + request (:class:`google.cloud.talent_v4beta1.types.DeleteCompanyRequest`): The request object. Request to delete a company. name (:class:`str`): Required. The resource name of the company to be @@ -432,6 +465,7 @@ async def delete_company( If tenant id is unspecified, the default tenant is used, for example, "projects/foo/companies/bar". + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -471,6 +505,7 @@ async def delete_company( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=DEFAULT_CLIENT_INFO, @@ -499,7 +534,7 @@ async def list_companies( r"""Lists all companies associated with the project. Args: - request (:class:`~.company_service.ListCompaniesRequest`): + request (:class:`google.cloud.talent_v4beta1.types.ListCompaniesRequest`): The request object. List companies for which the client has ACL visibility. parent (:class:`str`): @@ -512,6 +547,7 @@ async def list_companies( If tenant id is unspecified, the default tenant will be used, for example, "projects/foo". + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -523,7 +559,7 @@ async def list_companies( sent along with the request as metadata. Returns: - ~.pagers.ListCompaniesAsyncPager: + google.cloud.talent_v4beta1.services.company_service.pagers.ListCompaniesAsyncPager: The List companies response object. Iterating over this object will yield results and resolve additional pages @@ -559,6 +595,7 @@ async def list_companies( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=DEFAULT_CLIENT_INFO, diff --git a/google/cloud/talent_v4beta1/services/company_service/client.py b/google/cloud/talent_v4beta1/services/company_service/client.py index e4638852..aa2572b5 100644 --- a/google/cloud/talent_v4beta1/services/company_service/client.py +++ b/google/cloud/talent_v4beta1/services/company_service/client.py @@ -115,6 +115,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: + CompanyServiceClient: 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 @@ -127,7 +143,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. + CompanyServiceClient: The constructed client. """ credentials = service_account.Credentials.from_service_account_file(filename) kwargs["credentials"] = credentials @@ -235,10 +251,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, ~.CompanyServiceTransport]): The + transport (Union[str, CompanyServiceTransport]): 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 @@ -274,21 +290,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: @@ -331,7 +343,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, ) @@ -349,10 +361,10 @@ def create_company( r"""Creates a new company entity. Args: - request (:class:`~.company_service.CreateCompanyRequest`): + request (google.cloud.talent_v4beta1.types.CreateCompanyRequest): The request object. The Request of the CreateCompany method. - parent (:class:`str`): + parent (str): Required. Resource name of the tenant under which the company is created. @@ -361,10 +373,11 @@ def create_company( example, "projects/foo/tenant/bar". If tenant id is unspecified, a default tenant is created, for example, "projects/foo". + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - company (:class:`~.gct_company.Company`): + company (google.cloud.talent_v4beta1.types.Company): Required. The company to be created. This corresponds to the ``company`` field on the ``request`` instance; if ``request`` is provided, this @@ -377,7 +390,7 @@ def create_company( sent along with the request as metadata. Returns: - ~.gct_company.Company: + google.cloud.talent_v4beta1.types.Company: A Company resource represents a company in the service. A company is the entity that owns job postings, that is, @@ -439,10 +452,10 @@ def get_company( r"""Retrieves specified company. Args: - request (:class:`~.company_service.GetCompanyRequest`): + request (google.cloud.talent_v4beta1.types.GetCompanyRequest): The request object. Request for getting a company by name. - name (:class:`str`): + name (str): Required. The resource name of the company to be retrieved. @@ -453,6 +466,7 @@ def get_company( If tenant id is unspecified, the default tenant is used, for example, "projects/api-test-project/companies/bar". + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -464,7 +478,7 @@ def get_company( sent along with the request as metadata. Returns: - ~.company.Company: + google.cloud.talent_v4beta1.types.Company: A Company resource represents a company in the service. A company is the entity that owns job postings, that is, @@ -524,13 +538,14 @@ def update_company( r"""Updates specified company. Args: - request (:class:`~.company_service.UpdateCompanyRequest`): + request (google.cloud.talent_v4beta1.types.UpdateCompanyRequest): The request object. Request for updating a specified company. - company (:class:`~.gct_company.Company`): + company (google.cloud.talent_v4beta1.types.Company): Required. The company resource to replace the current resource in the system. + This corresponds to the ``company`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -542,7 +557,7 @@ def update_company( sent along with the request as metadata. Returns: - ~.gct_company.Company: + google.cloud.talent_v4beta1.types.Company: A Company resource represents a company in the service. A company is the entity that owns job postings, that is, @@ -606,9 +621,9 @@ def delete_company( it. Args: - request (:class:`~.company_service.DeleteCompanyRequest`): + request (google.cloud.talent_v4beta1.types.DeleteCompanyRequest): The request object. Request to delete a company. - name (:class:`str`): + name (str): Required. The resource name of the company to be deleted. @@ -618,6 +633,7 @@ def delete_company( If tenant id is unspecified, the default tenant is used, for example, "projects/foo/companies/bar". + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -678,10 +694,10 @@ def list_companies( r"""Lists all companies associated with the project. Args: - request (:class:`~.company_service.ListCompaniesRequest`): + request (google.cloud.talent_v4beta1.types.ListCompaniesRequest): The request object. List companies for which the client has ACL visibility. - parent (:class:`str`): + parent (str): Required. Resource name of the tenant under which the company is created. @@ -691,6 +707,7 @@ def list_companies( If tenant id is unspecified, the default tenant will be used, for example, "projects/foo". + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -702,7 +719,7 @@ def list_companies( sent along with the request as metadata. Returns: - ~.pagers.ListCompaniesPager: + google.cloud.talent_v4beta1.services.company_service.pagers.ListCompaniesPager: The List companies response object. Iterating over this object will yield results and resolve additional pages diff --git a/google/cloud/talent_v4beta1/services/company_service/pagers.py b/google/cloud/talent_v4beta1/services/company_service/pagers.py index 6b25c9a9..cb04a126 100644 --- a/google/cloud/talent_v4beta1/services/company_service/pagers.py +++ b/google/cloud/talent_v4beta1/services/company_service/pagers.py @@ -15,7 +15,16 @@ # limitations under the License. # -from typing import Any, AsyncIterable, Awaitable, Callable, Iterable, Sequence, Tuple +from typing import ( + Any, + AsyncIterable, + Awaitable, + Callable, + Iterable, + Sequence, + Tuple, + Optional, +) from google.cloud.talent_v4beta1.types import company from google.cloud.talent_v4beta1.types import company_service @@ -25,7 +34,7 @@ class ListCompaniesPager: """A pager for iterating through ``list_companies`` requests. This class thinly wraps an initial - :class:`~.company_service.ListCompaniesResponse` object, and + :class:`google.cloud.talent_v4beta1.types.ListCompaniesResponse` object, and provides an ``__iter__`` method to iterate through its ``companies`` field. @@ -34,7 +43,7 @@ class ListCompaniesPager: through the ``companies`` field on the corresponding responses. - All the usual :class:`~.company_service.ListCompaniesResponse` + All the usual :class:`google.cloud.talent_v4beta1.types.ListCompaniesResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -52,9 +61,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.company_service.ListCompaniesRequest`): + request (google.cloud.talent_v4beta1.types.ListCompaniesRequest): The initial request object. - response (:class:`~.company_service.ListCompaniesResponse`): + response (google.cloud.talent_v4beta1.types.ListCompaniesResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -87,7 +96,7 @@ class ListCompaniesAsyncPager: """A pager for iterating through ``list_companies`` requests. This class thinly wraps an initial - :class:`~.company_service.ListCompaniesResponse` object, and + :class:`google.cloud.talent_v4beta1.types.ListCompaniesResponse` object, and provides an ``__aiter__`` method to iterate through its ``companies`` field. @@ -96,7 +105,7 @@ class ListCompaniesAsyncPager: through the ``companies`` field on the corresponding responses. - All the usual :class:`~.company_service.ListCompaniesResponse` + All the usual :class:`google.cloud.talent_v4beta1.types.ListCompaniesResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -114,9 +123,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.company_service.ListCompaniesRequest`): + request (google.cloud.talent_v4beta1.types.ListCompaniesRequest): The initial request object. - response (:class:`~.company_service.ListCompaniesResponse`): + response (google.cloud.talent_v4beta1.types.ListCompaniesResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. diff --git a/google/cloud/talent_v4beta1/services/company_service/transports/base.py b/google/cloud/talent_v4beta1/services/company_service/transports/base.py index 39fb541b..e4af061a 100644 --- a/google/cloud/talent_v4beta1/services/company_service/transports/base.py +++ b/google/cloud/talent_v4beta1/services/company_service/transports/base.py @@ -73,10 +73,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. @@ -84,6 +84,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: @@ -93,20 +96,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 = { @@ -122,6 +122,7 @@ def _prep_wrapped_messages(self, client_info): predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=client_info, @@ -138,6 +139,7 @@ def _prep_wrapped_messages(self, client_info): predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=client_info, @@ -151,6 +153,7 @@ def _prep_wrapped_messages(self, client_info): predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=client_info, diff --git a/google/cloud/talent_v4beta1/services/company_service/transports/grpc.py b/google/cloud/talent_v4beta1/services/company_service/transports/grpc.py index 4c833246..b1d479f5 100644 --- a/google/cloud/talent_v4beta1/services/company_service/transports/grpc.py +++ b/google/cloud/talent_v4beta1/services/company_service/transports/grpc.py @@ -61,6 +61,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: @@ -91,6 +92,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): @@ -105,72 +110,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), @@ -178,17 +171,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( @@ -202,7 +186,7 @@ def create_channel( ) -> grpc.Channel: """Create and return a gRPC channel object. Args: - address (Optional[str]): The host for the channel to use. + host (Optional[str]): The host for the channel to use. credentials (Optional[~.Credentials]): The authorization credentials to attach to requests. These credentials identify this application to the service. If diff --git a/google/cloud/talent_v4beta1/services/company_service/transports/grpc_asyncio.py b/google/cloud/talent_v4beta1/services/company_service/transports/grpc_asyncio.py index 79a1d5fd..70bdce4b 100644 --- a/google/cloud/talent_v4beta1/services/company_service/transports/grpc_asyncio.py +++ b/google/cloud/talent_v4beta1/services/company_service/transports/grpc_asyncio.py @@ -65,7 +65,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 @@ -105,6 +105,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: @@ -136,12 +137,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: @@ -150,72 +155,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), @@ -223,17 +216,8 @@ def __init__( ], ) - # Run the base constructor. - super().__init__( - host=host, - credentials=credentials, - credentials_file=credentials_file, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - client_info=client_info, - ) - - self._stubs = {} + # 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/talent_v4beta1/services/completion/async_client.py b/google/cloud/talent_v4beta1/services/completion/async_client.py index 40da92eb..194a7b7e 100644 --- a/google/cloud/talent_v4beta1/services/completion/async_client.py +++ b/google/cloud/talent_v4beta1/services/completion/async_client.py @@ -70,7 +70,36 @@ class CompletionAsyncClient: CompletionClient.parse_common_location_path ) - from_service_account_file = CompletionClient.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: + CompletionAsyncClient: The constructed client. + """ + return CompletionClient.from_service_account_info.__func__(CompletionAsyncClient, 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: + CompletionAsyncClient: The constructed client. + """ + return CompletionClient.from_service_account_file.__func__(CompletionAsyncClient, filename, *args, **kwargs) # type: ignore + from_service_account_json = from_service_account_file @property @@ -147,7 +176,7 @@ async def complete_query( complete search box. Args: - request (:class:`~.completion_service.CompleteQueryRequest`): + request (:class:`google.cloud.talent_v4beta1.types.CompleteQueryRequest`): The request object. Auto-complete parameters. retry (google.api_core.retry.Retry): Designation of what errors, if any, @@ -157,7 +186,7 @@ async def complete_query( sent along with the request as metadata. Returns: - ~.completion_service.CompleteQueryResponse: + google.cloud.talent_v4beta1.types.CompleteQueryResponse: Response of auto-complete query. """ # Create or coerce a protobuf request object. @@ -175,6 +204,7 @@ async def complete_query( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=DEFAULT_CLIENT_INFO, diff --git a/google/cloud/talent_v4beta1/services/completion/client.py b/google/cloud/talent_v4beta1/services/completion/client.py index f01febaf..780d7342 100644 --- a/google/cloud/talent_v4beta1/services/completion/client.py +++ b/google/cloud/talent_v4beta1/services/completion/client.py @@ -108,6 +108,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: + CompletionClient: 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 @@ -120,7 +136,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. + CompletionClient: The constructed client. """ credentials = service_account.Credentials.from_service_account_file(filename) kwargs["credentials"] = credentials @@ -228,10 +244,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, ~.CompletionTransport]): The + transport (Union[str, CompletionTransport]): 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 @@ -267,21 +283,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: @@ -324,7 +336,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, ) @@ -342,7 +354,7 @@ def complete_query( complete search box. Args: - request (:class:`~.completion_service.CompleteQueryRequest`): + request (google.cloud.talent_v4beta1.types.CompleteQueryRequest): The request object. Auto-complete parameters. retry (google.api_core.retry.Retry): Designation of what errors, if any, @@ -352,7 +364,7 @@ def complete_query( sent along with the request as metadata. Returns: - ~.completion_service.CompleteQueryResponse: + google.cloud.talent_v4beta1.types.CompleteQueryResponse: Response of auto-complete query. """ # Create or coerce a protobuf request object. diff --git a/google/cloud/talent_v4beta1/services/completion/transports/base.py b/google/cloud/talent_v4beta1/services/completion/transports/base.py index 95e41990..fb7aaee0 100644 --- a/google/cloud/talent_v4beta1/services/completion/transports/base.py +++ b/google/cloud/talent_v4beta1/services/completion/transports/base.py @@ -70,10 +70,10 @@ def __init__( scope (Optional[Sequence[str]]): A list of scopes. quota_project_id (Optional[str]): An optional project to use for billing and quota. - client_info (google.api_core.gapic_v1.client_info.ClientInfo): - The client info used to send a user-agent string along with - API requests. If ``None``, then default info will be used. - Generally, you only need to set this if you're developing + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing your own client library. """ # Save the hostname. Default to port 443 (HTTPS) if none is specified. @@ -81,6 +81,9 @@ def __init__( host += ":443" self._host = host + # Save the scopes. + self._scopes = scopes or self.AUTH_SCOPES + # If no credentials are provided, then determine the appropriate # defaults. if credentials and credentials_file: @@ -90,20 +93,17 @@ def __init__( if credentials_file is not None: credentials, _ = auth.load_credentials_from_file( - credentials_file, scopes=scopes, quota_project_id=quota_project_id + credentials_file, scopes=self._scopes, quota_project_id=quota_project_id ) elif credentials is None: credentials, _ = auth.default( - scopes=scopes, quota_project_id=quota_project_id + scopes=self._scopes, quota_project_id=quota_project_id ) # Save the credentials. self._credentials = credentials - # Lifted into its own function so it can be stubbed out during tests. - self._prep_wrapped_messages(client_info) - def _prep_wrapped_messages(self, client_info): # Precompute the wrapped methods. self._wrapped_methods = { @@ -116,6 +116,7 @@ def _prep_wrapped_messages(self, client_info): predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=client_info, diff --git a/google/cloud/talent_v4beta1/services/completion/transports/grpc.py b/google/cloud/talent_v4beta1/services/completion/transports/grpc.py index 086da12a..164a4e5d 100644 --- a/google/cloud/talent_v4beta1/services/completion/transports/grpc.py +++ b/google/cloud/talent_v4beta1/services/completion/transports/grpc.py @@ -57,6 +57,7 @@ def __init__( api_mtls_endpoint: str = None, client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, quota_project_id: Optional[str] = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: @@ -87,6 +88,10 @@ def __init__( ``api_mtls_endpoint`` is None. ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials for grpc channel. It is ignored if ``channel`` is provided. + client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]): + A callback to provide client certificate bytes and private key bytes, + both in PEM format. It is used to configure mutual TLS channel. It is + ignored if ``channel`` or ``ssl_channel_credentials`` is provided. quota_project_id (Optional[str]): An optional project to use for billing and quota. client_info (google.api_core.gapic_v1.client_info.ClientInfo): @@ -101,72 +106,60 @@ def __init__( google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` and ``credentials_file`` are passed. """ + self._grpc_channel = None self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} + + if api_mtls_endpoint: + warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning) + if client_cert_source: + warnings.warn("client_cert_source is deprecated", DeprecationWarning) if channel: - # Sanity check: Ensure that channel and credentials are not both - # provided. + # Ignore credentials if a channel was passed. credentials = False - # If a channel was explicitly provided, set it. self._grpc_channel = channel self._ssl_channel_credentials = None - elif api_mtls_endpoint: - warnings.warn( - "api_mtls_endpoint and client_cert_source are deprecated", - DeprecationWarning, - ) - - host = ( - api_mtls_endpoint - if ":" in api_mtls_endpoint - else api_mtls_endpoint + ":443" - ) - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) + else: + if api_mtls_endpoint: + host = api_mtls_endpoint + + # Create SSL credentials with client_cert_source or application + # default SSL credentials. + if client_cert_source: + cert, key = client_cert_source() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + else: + self._ssl_channel_credentials = SslCredentials().ssl_credentials - # Create SSL credentials with client_cert_source or application - # default SSL credentials. - if client_cert_source: - cert, key = client_cert_source() - ssl_credentials = grpc.ssl_channel_credentials( - certificate_chain=cert, private_key=key - ) else: - ssl_credentials = SslCredentials().ssl_credentials - - # create a new channel. The provided one is ignored. - self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, - credentials_file=credentials_file, - ssl_credentials=ssl_credentials, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - options=[ - ("grpc.max_send_message_length", -1), - ("grpc.max_receive_message_length", -1), - ], - ) - self._ssl_channel_credentials = ssl_credentials - else: - host = host if ":" in host else host + ":443" + if client_cert_source_for_mtls and not ssl_channel_credentials: + cert, key = client_cert_source_for_mtls() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) + # The base transport sets the host, credentials and scopes + super().__init__( + host=host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + client_info=client_info, + ) - # create a new channel. The provided one is ignored. + if not self._grpc_channel: self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, + self._host, + credentials=self._credentials, credentials_file=credentials_file, - ssl_credentials=ssl_channel_credentials, - scopes=scopes or self.AUTH_SCOPES, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, quota_project_id=quota_project_id, options=[ ("grpc.max_send_message_length", -1), @@ -174,17 +167,8 @@ def __init__( ], ) - self._stubs = {} # type: Dict[str, Callable] - - # Run the base constructor. - super().__init__( - host=host, - credentials=credentials, - credentials_file=credentials_file, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - client_info=client_info, - ) + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) @classmethod def create_channel( @@ -198,7 +182,7 @@ def create_channel( ) -> grpc.Channel: """Create and return a gRPC channel object. Args: - address (Optional[str]): The host for the channel to use. + host (Optional[str]): The host for the channel to use. credentials (Optional[~.Credentials]): The authorization credentials to attach to requests. These credentials identify this application to the service. If diff --git a/google/cloud/talent_v4beta1/services/completion/transports/grpc_asyncio.py b/google/cloud/talent_v4beta1/services/completion/transports/grpc_asyncio.py index fa49dda0..88a6a731 100644 --- a/google/cloud/talent_v4beta1/services/completion/transports/grpc_asyncio.py +++ b/google/cloud/talent_v4beta1/services/completion/transports/grpc_asyncio.py @@ -61,7 +61,7 @@ def create_channel( ) -> aio.Channel: """Create and return a gRPC AsyncIO channel object. Args: - address (Optional[str]): The host for the channel to use. + host (Optional[str]): The host for the channel to use. credentials (Optional[~.Credentials]): The authorization credentials to attach to requests. These credentials identify this application to the service. If @@ -101,6 +101,7 @@ def __init__( api_mtls_endpoint: str = None, client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, quota_project_id=None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: @@ -132,12 +133,16 @@ def __init__( ``api_mtls_endpoint`` is None. ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials for grpc channel. It is ignored if ``channel`` is provided. + client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]): + A callback to provide client certificate bytes and private key bytes, + both in PEM format. It is used to configure mutual TLS channel. It is + ignored if ``channel`` or ``ssl_channel_credentials`` is provided. quota_project_id (Optional[str]): An optional project to use for billing and quota. - client_info (google.api_core.gapic_v1.client_info.ClientInfo): - The client info used to send a user-agent string along with - API requests. If ``None``, then default info will be used. - Generally, you only need to set this if you're developing + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing your own client library. Raises: @@ -146,72 +151,60 @@ def __init__( google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` and ``credentials_file`` are passed. """ + self._grpc_channel = None self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} + + if api_mtls_endpoint: + warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning) + if client_cert_source: + warnings.warn("client_cert_source is deprecated", DeprecationWarning) if channel: - # Sanity check: Ensure that channel and credentials are not both - # provided. + # Ignore credentials if a channel was passed. credentials = False - # If a channel was explicitly provided, set it. self._grpc_channel = channel self._ssl_channel_credentials = None - elif api_mtls_endpoint: - warnings.warn( - "api_mtls_endpoint and client_cert_source are deprecated", - DeprecationWarning, - ) - - host = ( - api_mtls_endpoint - if ":" in api_mtls_endpoint - else api_mtls_endpoint + ":443" - ) - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) + else: + if api_mtls_endpoint: + host = api_mtls_endpoint + + # Create SSL credentials with client_cert_source or application + # default SSL credentials. + if client_cert_source: + cert, key = client_cert_source() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + else: + self._ssl_channel_credentials = SslCredentials().ssl_credentials - # Create SSL credentials with client_cert_source or application - # default SSL credentials. - if client_cert_source: - cert, key = client_cert_source() - ssl_credentials = grpc.ssl_channel_credentials( - certificate_chain=cert, private_key=key - ) else: - ssl_credentials = SslCredentials().ssl_credentials - - # create a new channel. The provided one is ignored. - self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, - credentials_file=credentials_file, - ssl_credentials=ssl_credentials, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - options=[ - ("grpc.max_send_message_length", -1), - ("grpc.max_receive_message_length", -1), - ], - ) - self._ssl_channel_credentials = ssl_credentials - else: - host = host if ":" in host else host + ":443" + if client_cert_source_for_mtls and not ssl_channel_credentials: + cert, key = client_cert_source_for_mtls() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) + # The base transport sets the host, credentials and scopes + super().__init__( + host=host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + client_info=client_info, + ) - # create a new channel. The provided one is ignored. + if not self._grpc_channel: self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, + self._host, + credentials=self._credentials, credentials_file=credentials_file, - ssl_credentials=ssl_channel_credentials, - scopes=scopes or self.AUTH_SCOPES, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, quota_project_id=quota_project_id, options=[ ("grpc.max_send_message_length", -1), @@ -219,17 +212,8 @@ def __init__( ], ) - # Run the base constructor. - super().__init__( - host=host, - credentials=credentials, - credentials_file=credentials_file, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - client_info=client_info, - ) - - self._stubs = {} + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) @property def grpc_channel(self) -> aio.Channel: diff --git a/google/cloud/talent_v4beta1/services/event_service/async_client.py b/google/cloud/talent_v4beta1/services/event_service/async_client.py index 553aed17..4bddf1e1 100644 --- a/google/cloud/talent_v4beta1/services/event_service/async_client.py +++ b/google/cloud/talent_v4beta1/services/event_service/async_client.py @@ -73,7 +73,36 @@ class EventServiceAsyncClient: EventServiceClient.parse_common_location_path ) - from_service_account_file = EventServiceClient.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: + EventServiceAsyncClient: The constructed client. + """ + return EventServiceClient.from_service_account_info.__func__(EventServiceAsyncClient, 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: + EventServiceAsyncClient: The constructed client. + """ + return EventServiceClient.from_service_account_file.__func__(EventServiceAsyncClient, filename, *args, **kwargs) # type: ignore + from_service_account_json = from_service_account_file @property @@ -156,7 +185,7 @@ async def create_client_event( about self service tools. Args: - request (:class:`~.event_service.CreateClientEventRequest`): + request (:class:`google.cloud.talent_v4beta1.types.CreateClientEventRequest`): The request object. The report event request. parent (:class:`str`): Required. Resource name of the tenant under which the @@ -167,13 +196,15 @@ async def create_client_event( example, "projects/foo/tenant/bar". If tenant id is unspecified, a default tenant is created, for example, "projects/foo". + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - client_event (:class:`~.event.ClientEvent`): + client_event (:class:`google.cloud.talent_v4beta1.types.ClientEvent`): Required. Events issued when end user interacts with customer's application that uses Cloud Talent Solution. + This corresponds to the ``client_event`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -185,7 +216,7 @@ async def create_client_event( sent along with the request as metadata. Returns: - ~.event.ClientEvent: + google.cloud.talent_v4beta1.types.ClientEvent: An event issued when an end user interacts with the application that implements Cloud Talent Solution. diff --git a/google/cloud/talent_v4beta1/services/event_service/client.py b/google/cloud/talent_v4beta1/services/event_service/client.py index 21204729..b231a98d 100644 --- a/google/cloud/talent_v4beta1/services/event_service/client.py +++ b/google/cloud/talent_v4beta1/services/event_service/client.py @@ -109,6 +109,22 @@ def _get_default_mtls_endpoint(api_endpoint): DEFAULT_ENDPOINT ) + @classmethod + def from_service_account_info(cls, info: dict, *args, **kwargs): + """Creates an instance of this client using the provided credentials info. + + Args: + info (dict): The service account private key info. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + EventServiceClient: The constructed client. + """ + credentials = service_account.Credentials.from_service_account_info(info) + kwargs["credentials"] = credentials + return cls(*args, **kwargs) + @classmethod def from_service_account_file(cls, filename: str, *args, **kwargs): """Creates an instance of this client using the provided credentials @@ -121,7 +137,7 @@ def from_service_account_file(cls, filename: str, *args, **kwargs): kwargs: Additional arguments to pass to the constructor. Returns: - {@api.name}: The constructed client. + EventServiceClient: The constructed client. """ credentials = service_account.Credentials.from_service_account_file(filename) kwargs["credentials"] = credentials @@ -229,10 +245,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, ~.EventServiceTransport]): The + transport (Union[str, EventServiceTransport]): 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 @@ -268,21 +284,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: @@ -325,7 +337,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, ) @@ -349,9 +361,9 @@ def create_client_event( about self service tools. Args: - request (:class:`~.event_service.CreateClientEventRequest`): + request (google.cloud.talent_v4beta1.types.CreateClientEventRequest): The request object. The report event request. - parent (:class:`str`): + parent (str): Required. Resource name of the tenant under which the event is created. @@ -360,13 +372,15 @@ def create_client_event( example, "projects/foo/tenant/bar". If tenant id is unspecified, a default tenant is created, for example, "projects/foo". + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - client_event (:class:`~.event.ClientEvent`): + client_event (google.cloud.talent_v4beta1.types.ClientEvent): Required. Events issued when end user interacts with customer's application that uses Cloud Talent Solution. + This corresponds to the ``client_event`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -378,7 +392,7 @@ def create_client_event( sent along with the request as metadata. Returns: - ~.event.ClientEvent: + google.cloud.talent_v4beta1.types.ClientEvent: An event issued when an end user interacts with the application that implements Cloud Talent Solution. diff --git a/google/cloud/talent_v4beta1/services/event_service/transports/base.py b/google/cloud/talent_v4beta1/services/event_service/transports/base.py index cd643c9d..0fdd167b 100644 --- a/google/cloud/talent_v4beta1/services/event_service/transports/base.py +++ b/google/cloud/talent_v4beta1/services/event_service/transports/base.py @@ -71,10 +71,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. @@ -82,6 +82,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: @@ -91,20 +94,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 = { diff --git a/google/cloud/talent_v4beta1/services/event_service/transports/grpc.py b/google/cloud/talent_v4beta1/services/event_service/transports/grpc.py index 5b8edccd..18186207 100644 --- a/google/cloud/talent_v4beta1/services/event_service/transports/grpc.py +++ b/google/cloud/talent_v4beta1/services/event_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" - ) - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) + else: + if api_mtls_endpoint: + host = api_mtls_endpoint + + # Create SSL credentials with client_cert_source or application + # default SSL credentials. + if client_cert_source: + cert, key = client_cert_source() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + else: + self._ssl_channel_credentials = SslCredentials().ssl_credentials - # Create SSL credentials with client_cert_source or application - # default SSL credentials. - if client_cert_source: - cert, key = client_cert_source() - ssl_credentials = grpc.ssl_channel_credentials( - certificate_chain=cert, private_key=key - ) else: - ssl_credentials = SslCredentials().ssl_credentials - - # create a new channel. The provided one is ignored. - self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, - credentials_file=credentials_file, - ssl_credentials=ssl_credentials, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - options=[ - ("grpc.max_send_message_length", -1), - ("grpc.max_receive_message_length", -1), - ], - ) - self._ssl_channel_credentials = ssl_credentials - else: - host = host if ":" in host else host + ":443" + if client_cert_source_for_mtls and not ssl_channel_credentials: + cert, key = client_cert_source_for_mtls() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) + # The base transport sets the host, credentials and scopes + super().__init__( + host=host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + client_info=client_info, + ) - # create a new channel. The provided one is ignored. + if not self._grpc_channel: self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, + self._host, + credentials=self._credentials, credentials_file=credentials_file, - ssl_credentials=ssl_channel_credentials, - scopes=scopes or self.AUTH_SCOPES, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, quota_project_id=quota_project_id, options=[ ("grpc.max_send_message_length", -1), @@ -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/talent_v4beta1/services/event_service/transports/grpc_asyncio.py b/google/cloud/talent_v4beta1/services/event_service/transports/grpc_asyncio.py index 6a4cbe75..687b2763 100644 --- a/google/cloud/talent_v4beta1/services/event_service/transports/grpc_asyncio.py +++ b/google/cloud/talent_v4beta1/services/event_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" - ) - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) + else: + if api_mtls_endpoint: + host = api_mtls_endpoint + + # Create SSL credentials with client_cert_source or application + # default SSL credentials. + if client_cert_source: + cert, key = client_cert_source() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + else: + self._ssl_channel_credentials = SslCredentials().ssl_credentials - # Create SSL credentials with client_cert_source or application - # default SSL credentials. - if client_cert_source: - cert, key = client_cert_source() - ssl_credentials = grpc.ssl_channel_credentials( - certificate_chain=cert, private_key=key - ) else: - ssl_credentials = SslCredentials().ssl_credentials - - # create a new channel. The provided one is ignored. - self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, - credentials_file=credentials_file, - ssl_credentials=ssl_credentials, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - options=[ - ("grpc.max_send_message_length", -1), - ("grpc.max_receive_message_length", -1), - ], - ) - self._ssl_channel_credentials = ssl_credentials - else: - host = host if ":" in host else host + ":443" + if client_cert_source_for_mtls and not ssl_channel_credentials: + cert, key = client_cert_source_for_mtls() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) + # The base transport sets the host, credentials and scopes + super().__init__( + host=host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + client_info=client_info, + ) - # create a new channel. The provided one is ignored. + if not self._grpc_channel: self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, + self._host, + credentials=self._credentials, credentials_file=credentials_file, - ssl_credentials=ssl_channel_credentials, - scopes=scopes or self.AUTH_SCOPES, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, quota_project_id=quota_project_id, options=[ ("grpc.max_send_message_length", -1), @@ -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/talent_v4beta1/services/job_service/async_client.py b/google/cloud/talent_v4beta1/services/job_service/async_client.py index a5ad40c6..9f758a33 100644 --- a/google/cloud/talent_v4beta1/services/job_service/async_client.py +++ b/google/cloud/talent_v4beta1/services/job_service/async_client.py @@ -80,7 +80,36 @@ class JobServiceAsyncClient: JobServiceClient.parse_common_location_path ) - from_service_account_file = JobServiceClient.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: + JobServiceAsyncClient: The constructed client. + """ + return JobServiceClient.from_service_account_info.__func__(JobServiceAsyncClient, 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: + JobServiceAsyncClient: The constructed client. + """ + return JobServiceClient.from_service_account_file.__func__(JobServiceAsyncClient, filename, *args, **kwargs) # type: ignore + from_service_account_json = from_service_account_file @property @@ -159,7 +188,7 @@ async def create_job( but it may take up to 5 minutes. Args: - request (:class:`~.job_service.CreateJobRequest`): + request (:class:`google.cloud.talent_v4beta1.types.CreateJobRequest`): The request object. Create job request. parent (:class:`str`): Required. The resource name of the tenant under which @@ -170,10 +199,11 @@ async def create_job( example, "projects/foo/tenant/bar". If tenant id is unspecified a default tenant is created. For example, "projects/foo". + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - job (:class:`~.gct_job.Job`): + job (:class:`google.cloud.talent_v4beta1.types.Job`): Required. The Job to be created. This corresponds to the ``job`` field on the ``request`` instance; if ``request`` is provided, this @@ -186,12 +216,11 @@ async def create_job( sent along with the request as metadata. Returns: - ~.gct_job.Job: - A Job resource represents a job posting (also referred - to as a "job listing" or "job requisition"). A job - belongs to a - [Company][google.cloud.talent.v4beta1.Company], which is - the hiring entity responsible for the job. + google.cloud.talent_v4beta1.types.Job: + A Job resource represents a job posting (also referred to as a "job listing" + or "job requisition"). A job belongs to a + [Company][google.cloud.talent.v4beta1.Company], which + is the hiring entity responsible for the job. """ # Create or coerce a protobuf request object. @@ -247,7 +276,7 @@ async def batch_create_jobs( r"""Begins executing a batch create jobs operation. Args: - request (:class:`~.job_service.BatchCreateJobsRequest`): + request (:class:`google.cloud.talent_v4beta1.types.BatchCreateJobsRequest`): The request object. Request to create a batch of jobs. parent (:class:`str`): Required. The resource name of the tenant under which @@ -258,10 +287,11 @@ async def batch_create_jobs( example, "projects/foo/tenant/bar". If tenant id is unspecified, a default tenant is created. For example, "projects/foo". + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - jobs (:class:`Sequence[~.job.Job]`): + jobs (:class:`Sequence[google.cloud.talent_v4beta1.types.Job]`): Required. The jobs to be created. This corresponds to the ``jobs`` field on the ``request`` instance; if ``request`` is provided, this @@ -274,18 +304,14 @@ async def batch_create_jobs( sent along with the request as metadata. Returns: - ~.operation_async.AsyncOperation: + google.api_core.operation_async.AsyncOperation: An object representing a long-running operation. - The result type for the operation will be - :class:``~.job_service.JobOperationResult``: The result - of - [JobService.BatchCreateJobs][google.cloud.talent.v4beta1.JobService.BatchCreateJobs] - or - [JobService.BatchUpdateJobs][google.cloud.talent.v4beta1.JobService.BatchUpdateJobs] - APIs. It's used to replace - [google.longrunning.Operation.response][google.longrunning.Operation.response] - in case of success. + The result type for the operation will be :class:`google.cloud.talent_v4beta1.types.JobOperationResult` The result of [JobService.BatchCreateJobs][google.cloud.talent.v4beta1.JobService.BatchCreateJobs] or + [JobService.BatchUpdateJobs][google.cloud.talent.v4beta1.JobService.BatchUpdateJobs] + APIs. It's used to replace + [google.longrunning.Operation.response][google.longrunning.Operation.response] + in case of success. """ # Create or coerce a protobuf request object. @@ -350,7 +376,7 @@ async def get_job( recently EXPIRED within the last 90 days. Args: - request (:class:`~.job_service.GetJobRequest`): + request (:class:`google.cloud.talent_v4beta1.types.GetJobRequest`): The request object. Get job request. name (:class:`str`): Required. The resource name of the job to retrieve. @@ -361,6 +387,7 @@ async def get_job( If tenant id is unspecified, the default tenant is used. For example, "projects/foo/jobs/bar". + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -372,12 +399,11 @@ async def get_job( sent along with the request as metadata. Returns: - ~.job.Job: - A Job resource represents a job posting (also referred - to as a "job listing" or "job requisition"). A job - belongs to a - [Company][google.cloud.talent.v4beta1.Company], which is - the hiring entity responsible for the job. + google.cloud.talent_v4beta1.types.Job: + A Job resource represents a job posting (also referred to as a "job listing" + or "job requisition"). A job belongs to a + [Company][google.cloud.talent.v4beta1.Company], which + is the hiring entity responsible for the job. """ # Create or coerce a protobuf request object. @@ -409,6 +435,7 @@ async def get_job( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=DEFAULT_CLIENT_INFO, @@ -441,9 +468,9 @@ async def update_job( minutes. Args: - request (:class:`~.job_service.UpdateJobRequest`): + request (:class:`google.cloud.talent_v4beta1.types.UpdateJobRequest`): The request object. Update job request. - job (:class:`~.gct_job.Job`): + job (:class:`google.cloud.talent_v4beta1.types.Job`): Required. The Job to be updated. This corresponds to the ``job`` field on the ``request`` instance; if ``request`` is provided, this @@ -456,12 +483,11 @@ async def update_job( sent along with the request as metadata. Returns: - ~.gct_job.Job: - A Job resource represents a job posting (also referred - to as a "job listing" or "job requisition"). A job - belongs to a - [Company][google.cloud.talent.v4beta1.Company], which is - the hiring entity responsible for the job. + google.cloud.talent_v4beta1.types.Job: + A Job resource represents a job posting (also referred to as a "job listing" + or "job requisition"). A job belongs to a + [Company][google.cloud.talent.v4beta1.Company], which + is the hiring entity responsible for the job. """ # Create or coerce a protobuf request object. @@ -515,7 +541,7 @@ async def batch_update_jobs( r"""Begins executing a batch update jobs operation. Args: - request (:class:`~.job_service.BatchUpdateJobsRequest`): + request (:class:`google.cloud.talent_v4beta1.types.BatchUpdateJobsRequest`): The request object. Request to update a batch of jobs. parent (:class:`str`): Required. The resource name of the tenant under which @@ -526,10 +552,11 @@ async def batch_update_jobs( example, "projects/foo/tenant/bar". If tenant id is unspecified, a default tenant is created. For example, "projects/foo". + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - jobs (:class:`Sequence[~.job.Job]`): + jobs (:class:`Sequence[google.cloud.talent_v4beta1.types.Job]`): Required. The jobs to be updated. This corresponds to the ``jobs`` field on the ``request`` instance; if ``request`` is provided, this @@ -542,18 +569,14 @@ async def batch_update_jobs( sent along with the request as metadata. Returns: - ~.operation_async.AsyncOperation: + google.api_core.operation_async.AsyncOperation: An object representing a long-running operation. - The result type for the operation will be - :class:``~.job_service.JobOperationResult``: The result - of - [JobService.BatchCreateJobs][google.cloud.talent.v4beta1.JobService.BatchCreateJobs] - or - [JobService.BatchUpdateJobs][google.cloud.talent.v4beta1.JobService.BatchUpdateJobs] - APIs. It's used to replace - [google.longrunning.Operation.response][google.longrunning.Operation.response] - in case of success. + The result type for the operation will be :class:`google.cloud.talent_v4beta1.types.JobOperationResult` The result of [JobService.BatchCreateJobs][google.cloud.talent.v4beta1.JobService.BatchCreateJobs] or + [JobService.BatchUpdateJobs][google.cloud.talent.v4beta1.JobService.BatchUpdateJobs] + APIs. It's used to replace + [google.longrunning.Operation.response][google.longrunning.Operation.response] + in case of success. """ # Create or coerce a protobuf request object. @@ -619,7 +642,7 @@ async def delete_job( seconds, but it may take up to 5 minutes. Args: - request (:class:`~.job_service.DeleteJobRequest`): + request (:class:`google.cloud.talent_v4beta1.types.DeleteJobRequest`): The request object. Delete job request. name (:class:`str`): Required. The resource name of the job to be deleted. @@ -630,6 +653,7 @@ async def delete_job( If tenant id is unspecified, the default tenant is used. For example, "projects/foo/jobs/bar". + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -669,6 +693,7 @@ async def delete_job( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=DEFAULT_CLIENT_INFO, @@ -699,7 +724,7 @@ async def batch_delete_jobs( filter. Args: - request (:class:`~.job_service.BatchDeleteJobsRequest`): + request (:class:`google.cloud.talent_v4beta1.types.BatchDeleteJobsRequest`): The request object. Batch delete jobs request. parent (:class:`str`): Required. The resource name of the tenant under which @@ -710,6 +735,7 @@ async def batch_delete_jobs( example, "projects/foo/tenant/bar". If tenant id is unspecified, a default tenant is created. For example, "projects/foo". + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -725,7 +751,8 @@ async def batch_delete_jobs( - ``requisitionId`` (Required) Sample Query: companyName = "projects/foo/companies/bar" - AND requisitionId = "req-1". + AND requisitionId = "req-1" + This corresponds to the ``filter`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -788,7 +815,7 @@ async def list_jobs( r"""Lists jobs by filter. Args: - request (:class:`~.job_service.ListJobsRequest`): + request (:class:`google.cloud.talent_v4beta1.types.ListJobsRequest`): The request object. List jobs request. parent (:class:`str`): Required. The resource name of the tenant under which @@ -799,6 +826,7 @@ async def list_jobs( example, "projects/foo/tenant/bar". If tenant id is unspecified, a default tenant is created. For example, "projects/foo". + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -824,7 +852,8 @@ async def list_jobs( requisitionId = "req-1" - companyName = "projects/foo/tenants/bar/companies/baz" AND status = - "EXPIRED". + "EXPIRED" + This corresponds to the ``filter`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -836,7 +865,7 @@ async def list_jobs( sent along with the request as metadata. Returns: - ~.pagers.ListJobsAsyncPager: + google.cloud.talent_v4beta1.services.job_service.pagers.ListJobsAsyncPager: List jobs response. Iterating over this object will yield results and resolve additional pages @@ -874,6 +903,7 @@ async def list_jobs( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=DEFAULT_CLIENT_INFO, @@ -914,7 +944,7 @@ async def search_jobs( has permission to search against. Args: - request (:class:`~.job_service.SearchJobsRequest`): + request (:class:`google.cloud.talent_v4beta1.types.SearchJobsRequest`): The request object. The Request body of the `SearchJobs` call. @@ -925,7 +955,7 @@ async def search_jobs( sent along with the request as metadata. Returns: - ~.pagers.SearchJobsAsyncPager: + google.cloud.talent_v4beta1.services.job_service.pagers.SearchJobsAsyncPager: Response for SearchJob method. Iterating over this object will yield results and resolve additional pages @@ -985,7 +1015,7 @@ async def search_jobs_for_alert( permission to search against. Args: - request (:class:`~.job_service.SearchJobsRequest`): + request (:class:`google.cloud.talent_v4beta1.types.SearchJobsRequest`): The request object. The Request body of the `SearchJobs` call. @@ -996,7 +1026,7 @@ async def search_jobs_for_alert( sent along with the request as metadata. Returns: - ~.pagers.SearchJobsForAlertAsyncPager: + google.cloud.talent_v4beta1.services.job_service.pagers.SearchJobsForAlertAsyncPager: Response for SearchJob method. Iterating over this object will yield results and resolve additional pages diff --git a/google/cloud/talent_v4beta1/services/job_service/client.py b/google/cloud/talent_v4beta1/services/job_service/client.py index 726b75ae..d044dc14 100644 --- a/google/cloud/talent_v4beta1/services/job_service/client.py +++ b/google/cloud/talent_v4beta1/services/job_service/client.py @@ -116,6 +116,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: + JobServiceClient: 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 @@ -128,7 +144,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. + JobServiceClient: The constructed client. """ credentials = service_account.Credentials.from_service_account_file(filename) kwargs["credentials"] = credentials @@ -252,10 +268,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, ~.JobServiceTransport]): The + transport (Union[str, JobServiceTransport]): 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 @@ -291,21 +307,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: @@ -348,7 +360,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, ) @@ -368,9 +380,9 @@ def create_job( but it may take up to 5 minutes. Args: - request (:class:`~.job_service.CreateJobRequest`): + request (google.cloud.talent_v4beta1.types.CreateJobRequest): The request object. Create job request. - parent (:class:`str`): + parent (str): Required. The resource name of the tenant under which the job is created. @@ -379,10 +391,11 @@ def create_job( example, "projects/foo/tenant/bar". If tenant id is unspecified a default tenant is created. For example, "projects/foo". + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - job (:class:`~.gct_job.Job`): + job (google.cloud.talent_v4beta1.types.Job): Required. The Job to be created. This corresponds to the ``job`` field on the ``request`` instance; if ``request`` is provided, this @@ -395,12 +408,11 @@ def create_job( sent along with the request as metadata. Returns: - ~.gct_job.Job: - A Job resource represents a job posting (also referred - to as a "job listing" or "job requisition"). A job - belongs to a - [Company][google.cloud.talent.v4beta1.Company], which is - the hiring entity responsible for the job. + google.cloud.talent_v4beta1.types.Job: + A Job resource represents a job posting (also referred to as a "job listing" + or "job requisition"). A job belongs to a + [Company][google.cloud.talent.v4beta1.Company], which + is the hiring entity responsible for the job. """ # Create or coerce a protobuf request object. @@ -457,9 +469,9 @@ def batch_create_jobs( r"""Begins executing a batch create jobs operation. Args: - request (:class:`~.job_service.BatchCreateJobsRequest`): + request (google.cloud.talent_v4beta1.types.BatchCreateJobsRequest): The request object. Request to create a batch of jobs. - parent (:class:`str`): + parent (str): Required. The resource name of the tenant under which the job is created. @@ -468,10 +480,11 @@ def batch_create_jobs( example, "projects/foo/tenant/bar". If tenant id is unspecified, a default tenant is created. For example, "projects/foo". + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - jobs (:class:`Sequence[~.job.Job]`): + jobs (Sequence[google.cloud.talent_v4beta1.types.Job]): Required. The jobs to be created. This corresponds to the ``jobs`` field on the ``request`` instance; if ``request`` is provided, this @@ -484,18 +497,14 @@ def batch_create_jobs( sent along with the request as metadata. Returns: - ~.operation.Operation: + google.api_core.operation.Operation: An object representing a long-running operation. - The result type for the operation will be - :class:``~.job_service.JobOperationResult``: The result - of - [JobService.BatchCreateJobs][google.cloud.talent.v4beta1.JobService.BatchCreateJobs] - or - [JobService.BatchUpdateJobs][google.cloud.talent.v4beta1.JobService.BatchUpdateJobs] - APIs. It's used to replace - [google.longrunning.Operation.response][google.longrunning.Operation.response] - in case of success. + The result type for the operation will be :class:`google.cloud.talent_v4beta1.types.JobOperationResult` The result of [JobService.BatchCreateJobs][google.cloud.talent.v4beta1.JobService.BatchCreateJobs] or + [JobService.BatchUpdateJobs][google.cloud.talent.v4beta1.JobService.BatchUpdateJobs] + APIs. It's used to replace + [google.longrunning.Operation.response][google.longrunning.Operation.response] + in case of success. """ # Create or coerce a protobuf request object. @@ -520,9 +529,8 @@ def batch_create_jobs( if parent is not None: request.parent = parent - - if jobs: - request.jobs.extend(jobs) + if jobs is not None: + request.jobs = jobs # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. @@ -561,9 +569,9 @@ def get_job( recently EXPIRED within the last 90 days. Args: - request (:class:`~.job_service.GetJobRequest`): + request (google.cloud.talent_v4beta1.types.GetJobRequest): The request object. Get job request. - name (:class:`str`): + name (str): Required. The resource name of the job to retrieve. The format is @@ -572,6 +580,7 @@ def get_job( If tenant id is unspecified, the default tenant is used. For example, "projects/foo/jobs/bar". + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -583,12 +592,11 @@ def get_job( sent along with the request as metadata. Returns: - ~.job.Job: - A Job resource represents a job posting (also referred - to as a "job listing" or "job requisition"). A job - belongs to a - [Company][google.cloud.talent.v4beta1.Company], which is - the hiring entity responsible for the job. + google.cloud.talent_v4beta1.types.Job: + A Job resource represents a job posting (also referred to as a "job listing" + or "job requisition"). A job belongs to a + [Company][google.cloud.talent.v4beta1.Company], which + is the hiring entity responsible for the job. """ # Create or coerce a protobuf request object. @@ -645,9 +653,9 @@ def update_job( minutes. Args: - request (:class:`~.job_service.UpdateJobRequest`): + request (google.cloud.talent_v4beta1.types.UpdateJobRequest): The request object. Update job request. - job (:class:`~.gct_job.Job`): + job (google.cloud.talent_v4beta1.types.Job): Required. The Job to be updated. This corresponds to the ``job`` field on the ``request`` instance; if ``request`` is provided, this @@ -660,12 +668,11 @@ def update_job( sent along with the request as metadata. Returns: - ~.gct_job.Job: - A Job resource represents a job posting (also referred - to as a "job listing" or "job requisition"). A job - belongs to a - [Company][google.cloud.talent.v4beta1.Company], which is - the hiring entity responsible for the job. + google.cloud.talent_v4beta1.types.Job: + A Job resource represents a job posting (also referred to as a "job listing" + or "job requisition"). A job belongs to a + [Company][google.cloud.talent.v4beta1.Company], which + is the hiring entity responsible for the job. """ # Create or coerce a protobuf request object. @@ -720,9 +727,9 @@ def batch_update_jobs( r"""Begins executing a batch update jobs operation. Args: - request (:class:`~.job_service.BatchUpdateJobsRequest`): + request (google.cloud.talent_v4beta1.types.BatchUpdateJobsRequest): The request object. Request to update a batch of jobs. - parent (:class:`str`): + parent (str): Required. The resource name of the tenant under which the job is created. @@ -731,10 +738,11 @@ def batch_update_jobs( example, "projects/foo/tenant/bar". If tenant id is unspecified, a default tenant is created. For example, "projects/foo". + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - jobs (:class:`Sequence[~.job.Job]`): + jobs (Sequence[google.cloud.talent_v4beta1.types.Job]): Required. The jobs to be updated. This corresponds to the ``jobs`` field on the ``request`` instance; if ``request`` is provided, this @@ -747,18 +755,14 @@ def batch_update_jobs( sent along with the request as metadata. Returns: - ~.operation.Operation: + google.api_core.operation.Operation: An object representing a long-running operation. - The result type for the operation will be - :class:``~.job_service.JobOperationResult``: The result - of - [JobService.BatchCreateJobs][google.cloud.talent.v4beta1.JobService.BatchCreateJobs] - or - [JobService.BatchUpdateJobs][google.cloud.talent.v4beta1.JobService.BatchUpdateJobs] - APIs. It's used to replace - [google.longrunning.Operation.response][google.longrunning.Operation.response] - in case of success. + The result type for the operation will be :class:`google.cloud.talent_v4beta1.types.JobOperationResult` The result of [JobService.BatchCreateJobs][google.cloud.talent.v4beta1.JobService.BatchCreateJobs] or + [JobService.BatchUpdateJobs][google.cloud.talent.v4beta1.JobService.BatchUpdateJobs] + APIs. It's used to replace + [google.longrunning.Operation.response][google.longrunning.Operation.response] + in case of success. """ # Create or coerce a protobuf request object. @@ -783,9 +787,8 @@ def batch_update_jobs( if parent is not None: request.parent = parent - - if jobs: - request.jobs.extend(jobs) + if jobs is not None: + request.jobs = jobs # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. @@ -825,9 +828,9 @@ def delete_job( seconds, but it may take up to 5 minutes. Args: - request (:class:`~.job_service.DeleteJobRequest`): + request (google.cloud.talent_v4beta1.types.DeleteJobRequest): The request object. Delete job request. - name (:class:`str`): + name (str): Required. The resource name of the job to be deleted. The format is @@ -836,6 +839,7 @@ def delete_job( If tenant id is unspecified, the default tenant is used. For example, "projects/foo/jobs/bar". + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -898,9 +902,9 @@ def batch_delete_jobs( filter. Args: - request (:class:`~.job_service.BatchDeleteJobsRequest`): + request (google.cloud.talent_v4beta1.types.BatchDeleteJobsRequest): The request object. Batch delete jobs request. - parent (:class:`str`): + parent (str): Required. The resource name of the tenant under which the job is created. @@ -909,10 +913,11 @@ def batch_delete_jobs( example, "projects/foo/tenant/bar". If tenant id is unspecified, a default tenant is created. For example, "projects/foo". + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - filter (:class:`str`): + filter (str): Required. The filter string specifies the jobs to be deleted. @@ -924,7 +929,8 @@ def batch_delete_jobs( - ``requisitionId`` (Required) Sample Query: companyName = "projects/foo/companies/bar" - AND requisitionId = "req-1". + AND requisitionId = "req-1" + This corresponds to the ``filter`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -988,9 +994,9 @@ def list_jobs( r"""Lists jobs by filter. Args: - request (:class:`~.job_service.ListJobsRequest`): + request (google.cloud.talent_v4beta1.types.ListJobsRequest): The request object. List jobs request. - parent (:class:`str`): + parent (str): Required. The resource name of the tenant under which the job is created. @@ -999,10 +1005,11 @@ def list_jobs( example, "projects/foo/tenant/bar". If tenant id is unspecified, a default tenant is created. For example, "projects/foo". + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - filter (:class:`str`): + filter (str): Required. The filter string specifies the jobs to be enumerated. @@ -1024,7 +1031,8 @@ def list_jobs( requisitionId = "req-1" - companyName = "projects/foo/tenants/bar/companies/baz" AND status = - "EXPIRED". + "EXPIRED" + This corresponds to the ``filter`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -1036,7 +1044,7 @@ def list_jobs( sent along with the request as metadata. Returns: - ~.pagers.ListJobsPager: + google.cloud.talent_v4beta1.services.job_service.pagers.ListJobsPager: List jobs response. Iterating over this object will yield results and resolve additional pages @@ -1107,7 +1115,7 @@ def search_jobs( has permission to search against. Args: - request (:class:`~.job_service.SearchJobsRequest`): + request (google.cloud.talent_v4beta1.types.SearchJobsRequest): The request object. The Request body of the `SearchJobs` call. @@ -1118,7 +1126,7 @@ def search_jobs( sent along with the request as metadata. Returns: - ~.pagers.SearchJobsPager: + google.cloud.talent_v4beta1.services.job_service.pagers.SearchJobsPager: Response for SearchJob method. Iterating over this object will yield results and resolve additional pages @@ -1179,7 +1187,7 @@ def search_jobs_for_alert( permission to search against. Args: - request (:class:`~.job_service.SearchJobsRequest`): + request (google.cloud.talent_v4beta1.types.SearchJobsRequest): The request object. The Request body of the `SearchJobs` call. @@ -1190,7 +1198,7 @@ def search_jobs_for_alert( sent along with the request as metadata. Returns: - ~.pagers.SearchJobsForAlertPager: + google.cloud.talent_v4beta1.services.job_service.pagers.SearchJobsForAlertPager: Response for SearchJob method. Iterating over this object will yield results and resolve additional pages diff --git a/google/cloud/talent_v4beta1/services/job_service/pagers.py b/google/cloud/talent_v4beta1/services/job_service/pagers.py index fcefff46..47d07398 100644 --- a/google/cloud/talent_v4beta1/services/job_service/pagers.py +++ b/google/cloud/talent_v4beta1/services/job_service/pagers.py @@ -15,7 +15,16 @@ # limitations under the License. # -from typing import Any, AsyncIterable, Awaitable, Callable, Iterable, Sequence, Tuple +from typing import ( + Any, + AsyncIterable, + Awaitable, + Callable, + Iterable, + Sequence, + Tuple, + Optional, +) from google.cloud.talent_v4beta1.types import job from google.cloud.talent_v4beta1.types import job_service @@ -25,7 +34,7 @@ class ListJobsPager: """A pager for iterating through ``list_jobs`` requests. This class thinly wraps an initial - :class:`~.job_service.ListJobsResponse` object, and + :class:`google.cloud.talent_v4beta1.types.ListJobsResponse` object, and provides an ``__iter__`` method to iterate through its ``jobs`` field. @@ -34,7 +43,7 @@ class ListJobsPager: through the ``jobs`` field on the corresponding responses. - All the usual :class:`~.job_service.ListJobsResponse` + All the usual :class:`google.cloud.talent_v4beta1.types.ListJobsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -52,9 +61,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.job_service.ListJobsRequest`): + request (google.cloud.talent_v4beta1.types.ListJobsRequest): The initial request object. - response (:class:`~.job_service.ListJobsResponse`): + response (google.cloud.talent_v4beta1.types.ListJobsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -87,7 +96,7 @@ class ListJobsAsyncPager: """A pager for iterating through ``list_jobs`` requests. This class thinly wraps an initial - :class:`~.job_service.ListJobsResponse` object, and + :class:`google.cloud.talent_v4beta1.types.ListJobsResponse` object, and provides an ``__aiter__`` method to iterate through its ``jobs`` field. @@ -96,7 +105,7 @@ class ListJobsAsyncPager: through the ``jobs`` field on the corresponding responses. - All the usual :class:`~.job_service.ListJobsResponse` + All the usual :class:`google.cloud.talent_v4beta1.types.ListJobsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -114,9 +123,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.job_service.ListJobsRequest`): + request (google.cloud.talent_v4beta1.types.ListJobsRequest): The initial request object. - response (:class:`~.job_service.ListJobsResponse`): + response (google.cloud.talent_v4beta1.types.ListJobsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -153,7 +162,7 @@ class SearchJobsPager: """A pager for iterating through ``search_jobs`` requests. This class thinly wraps an initial - :class:`~.job_service.SearchJobsResponse` object, and + :class:`google.cloud.talent_v4beta1.types.SearchJobsResponse` object, and provides an ``__iter__`` method to iterate through its ``matching_jobs`` field. @@ -162,7 +171,7 @@ class SearchJobsPager: through the ``matching_jobs`` field on the corresponding responses. - All the usual :class:`~.job_service.SearchJobsResponse` + All the usual :class:`google.cloud.talent_v4beta1.types.SearchJobsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -180,9 +189,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.job_service.SearchJobsRequest`): + request (google.cloud.talent_v4beta1.types.SearchJobsRequest): The initial request object. - response (:class:`~.job_service.SearchJobsResponse`): + response (google.cloud.talent_v4beta1.types.SearchJobsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -215,7 +224,7 @@ class SearchJobsAsyncPager: """A pager for iterating through ``search_jobs`` requests. This class thinly wraps an initial - :class:`~.job_service.SearchJobsResponse` object, and + :class:`google.cloud.talent_v4beta1.types.SearchJobsResponse` object, and provides an ``__aiter__`` method to iterate through its ``matching_jobs`` field. @@ -224,7 +233,7 @@ class SearchJobsAsyncPager: through the ``matching_jobs`` field on the corresponding responses. - All the usual :class:`~.job_service.SearchJobsResponse` + All the usual :class:`google.cloud.talent_v4beta1.types.SearchJobsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -242,9 +251,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.job_service.SearchJobsRequest`): + request (google.cloud.talent_v4beta1.types.SearchJobsRequest): The initial request object. - response (:class:`~.job_service.SearchJobsResponse`): + response (google.cloud.talent_v4beta1.types.SearchJobsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -281,7 +290,7 @@ class SearchJobsForAlertPager: """A pager for iterating through ``search_jobs_for_alert`` requests. This class thinly wraps an initial - :class:`~.job_service.SearchJobsResponse` object, and + :class:`google.cloud.talent_v4beta1.types.SearchJobsResponse` object, and provides an ``__iter__`` method to iterate through its ``matching_jobs`` field. @@ -290,7 +299,7 @@ class SearchJobsForAlertPager: through the ``matching_jobs`` field on the corresponding responses. - All the usual :class:`~.job_service.SearchJobsResponse` + All the usual :class:`google.cloud.talent_v4beta1.types.SearchJobsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -308,9 +317,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.job_service.SearchJobsRequest`): + request (google.cloud.talent_v4beta1.types.SearchJobsRequest): The initial request object. - response (:class:`~.job_service.SearchJobsResponse`): + response (google.cloud.talent_v4beta1.types.SearchJobsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -343,7 +352,7 @@ class SearchJobsForAlertAsyncPager: """A pager for iterating through ``search_jobs_for_alert`` requests. This class thinly wraps an initial - :class:`~.job_service.SearchJobsResponse` object, and + :class:`google.cloud.talent_v4beta1.types.SearchJobsResponse` object, and provides an ``__aiter__`` method to iterate through its ``matching_jobs`` field. @@ -352,7 +361,7 @@ class SearchJobsForAlertAsyncPager: through the ``matching_jobs`` field on the corresponding responses. - All the usual :class:`~.job_service.SearchJobsResponse` + All the usual :class:`google.cloud.talent_v4beta1.types.SearchJobsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -370,9 +379,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.job_service.SearchJobsRequest`): + request (google.cloud.talent_v4beta1.types.SearchJobsRequest): The initial request object. - response (:class:`~.job_service.SearchJobsResponse`): + response (google.cloud.talent_v4beta1.types.SearchJobsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. diff --git a/google/cloud/talent_v4beta1/services/job_service/transports/base.py b/google/cloud/talent_v4beta1/services/job_service/transports/base.py index ffef5f17..5cb1997b 100644 --- a/google/cloud/talent_v4beta1/services/job_service/transports/base.py +++ b/google/cloud/talent_v4beta1/services/job_service/transports/base.py @@ -75,10 +75,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. @@ -86,6 +86,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: @@ -95,20 +98,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 = { @@ -127,6 +127,7 @@ def _prep_wrapped_messages(self, client_info): predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=client_info, @@ -146,6 +147,7 @@ def _prep_wrapped_messages(self, client_info): predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=client_info, @@ -162,6 +164,7 @@ def _prep_wrapped_messages(self, client_info): predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=client_info, diff --git a/google/cloud/talent_v4beta1/services/job_service/transports/grpc.py b/google/cloud/talent_v4beta1/services/job_service/transports/grpc.py index c3526f6f..188b42a6 100644 --- a/google/cloud/talent_v4beta1/services/job_service/transports/grpc.py +++ b/google/cloud/talent_v4beta1/services/job_service/transports/grpc.py @@ -63,6 +63,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: @@ -93,6 +94,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): @@ -107,72 +112,61 @@ def __init__( google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` and ``credentials_file`` are passed. """ + self._grpc_channel = None self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} + self._operations_client = None + + if api_mtls_endpoint: + warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning) + if client_cert_source: + warnings.warn("client_cert_source is deprecated", DeprecationWarning) if channel: - # Sanity check: Ensure that channel and credentials are not both - # provided. + # Ignore credentials if a channel was passed. credentials = False - # If a channel was explicitly provided, set it. self._grpc_channel = channel self._ssl_channel_credentials = None - elif api_mtls_endpoint: - warnings.warn( - "api_mtls_endpoint and client_cert_source are deprecated", - DeprecationWarning, - ) - host = ( - api_mtls_endpoint - if ":" in api_mtls_endpoint - else api_mtls_endpoint + ":443" - ) + else: + if api_mtls_endpoint: + host = api_mtls_endpoint + + # Create SSL credentials with client_cert_source or application + # default SSL credentials. + if client_cert_source: + cert, key = client_cert_source() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + else: + self._ssl_channel_credentials = SslCredentials().ssl_credentials - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) - - # Create SSL credentials with client_cert_source or application - # default SSL credentials. - if client_cert_source: - cert, key = client_cert_source() - ssl_credentials = grpc.ssl_channel_credentials( - certificate_chain=cert, private_key=key - ) else: - ssl_credentials = SslCredentials().ssl_credentials + if client_cert_source_for_mtls and not ssl_channel_credentials: + cert, key = client_cert_source_for_mtls() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) - # create a new channel. The provided one is ignored. - self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, - credentials_file=credentials_file, - ssl_credentials=ssl_credentials, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - options=[ - ("grpc.max_send_message_length", -1), - ("grpc.max_receive_message_length", -1), - ], - ) - self._ssl_channel_credentials = ssl_credentials - else: - host = host if ":" in host else host + ":443" - - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) + # The base transport sets the host, credentials and scopes + super().__init__( + host=host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + client_info=client_info, + ) - # create a new channel. The provided one is ignored. + if not self._grpc_channel: self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, + self._host, + credentials=self._credentials, credentials_file=credentials_file, - ssl_credentials=ssl_channel_credentials, - scopes=scopes or self.AUTH_SCOPES, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, quota_project_id=quota_project_id, options=[ ("grpc.max_send_message_length", -1), @@ -180,18 +174,8 @@ def __init__( ], ) - self._stubs = {} # type: Dict[str, Callable] - self._operations_client = None - - # Run the base constructor. - super().__init__( - host=host, - credentials=credentials, - credentials_file=credentials_file, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - client_info=client_info, - ) + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) @classmethod def create_channel( @@ -205,7 +189,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/talent_v4beta1/services/job_service/transports/grpc_asyncio.py b/google/cloud/talent_v4beta1/services/job_service/transports/grpc_asyncio.py index 794df7cf..4896073b 100644 --- a/google/cloud/talent_v4beta1/services/job_service/transports/grpc_asyncio.py +++ b/google/cloud/talent_v4beta1/services/job_service/transports/grpc_asyncio.py @@ -67,7 +67,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 @@ -107,6 +107,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: @@ -138,12 +139,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: @@ -152,72 +157,61 @@ def __init__( google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` and ``credentials_file`` are passed. """ + self._grpc_channel = None self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} + self._operations_client = None + + if api_mtls_endpoint: + warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning) + if client_cert_source: + warnings.warn("client_cert_source is deprecated", DeprecationWarning) if channel: - # Sanity check: Ensure that channel and credentials are not both - # provided. + # Ignore credentials if a channel was passed. credentials = False - # If a channel was explicitly provided, set it. self._grpc_channel = channel self._ssl_channel_credentials = None - elif api_mtls_endpoint: - warnings.warn( - "api_mtls_endpoint and client_cert_source are deprecated", - DeprecationWarning, - ) - host = ( - api_mtls_endpoint - if ":" in api_mtls_endpoint - else api_mtls_endpoint + ":443" - ) + else: + if api_mtls_endpoint: + host = api_mtls_endpoint + + # Create SSL credentials with client_cert_source or application + # default SSL credentials. + if client_cert_source: + cert, key = client_cert_source() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + else: + self._ssl_channel_credentials = SslCredentials().ssl_credentials - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) - - # Create SSL credentials with client_cert_source or application - # default SSL credentials. - if client_cert_source: - cert, key = client_cert_source() - ssl_credentials = grpc.ssl_channel_credentials( - certificate_chain=cert, private_key=key - ) else: - ssl_credentials = SslCredentials().ssl_credentials + if client_cert_source_for_mtls and not ssl_channel_credentials: + cert, key = client_cert_source_for_mtls() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) - # create a new channel. The provided one is ignored. - self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, - credentials_file=credentials_file, - ssl_credentials=ssl_credentials, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - options=[ - ("grpc.max_send_message_length", -1), - ("grpc.max_receive_message_length", -1), - ], - ) - self._ssl_channel_credentials = ssl_credentials - else: - host = host if ":" in host else host + ":443" - - if credentials is None: - credentials, _ = auth.default( - scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id - ) + # The base transport sets the host, credentials and scopes + super().__init__( + host=host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + client_info=client_info, + ) - # create a new channel. The provided one is ignored. + if not self._grpc_channel: self._grpc_channel = type(self).create_channel( - host, - credentials=credentials, + self._host, + credentials=self._credentials, credentials_file=credentials_file, - ssl_credentials=ssl_channel_credentials, - scopes=scopes or self.AUTH_SCOPES, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, quota_project_id=quota_project_id, options=[ ("grpc.max_send_message_length", -1), @@ -225,18 +219,8 @@ def __init__( ], ) - # Run the base constructor. - super().__init__( - host=host, - credentials=credentials, - credentials_file=credentials_file, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - client_info=client_info, - ) - - self._stubs = {} - self._operations_client = None + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) @property def grpc_channel(self) -> aio.Channel: diff --git a/google/cloud/talent_v4beta1/services/profile_service/async_client.py b/google/cloud/talent_v4beta1/services/profile_service/async_client.py index 914e2bf4..7c581cb8 100644 --- a/google/cloud/talent_v4beta1/services/profile_service/async_client.py +++ b/google/cloud/talent_v4beta1/services/profile_service/async_client.py @@ -86,7 +86,36 @@ class ProfileServiceAsyncClient: ProfileServiceClient.parse_common_location_path ) - from_service_account_file = ProfileServiceClient.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: + ProfileServiceAsyncClient: The constructed client. + """ + return ProfileServiceClient.from_service_account_info.__func__(ProfileServiceAsyncClient, 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: + ProfileServiceAsyncClient: The constructed client. + """ + return ProfileServiceClient.from_service_account_file.__func__(ProfileServiceAsyncClient, filename, *args, **kwargs) # type: ignore + from_service_account_json = from_service_account_file @property @@ -162,7 +191,7 @@ async def list_profiles( r"""Lists profiles by filter. The order is unspecified. Args: - request (:class:`~.profile_service.ListProfilesRequest`): + request (:class:`google.cloud.talent_v4beta1.types.ListProfilesRequest`): The request object. List profiles request. parent (:class:`str`): Required. The resource name of the tenant under which @@ -171,6 +200,7 @@ async def list_profiles( The format is "projects/{project_id}/tenants/{tenant_id}". For example, "projects/foo/tenants/bar". + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -182,7 +212,7 @@ async def list_profiles( sent along with the request as metadata. Returns: - ~.pagers.ListProfilesAsyncPager: + google.cloud.talent_v4beta1.services.profile_service.pagers.ListProfilesAsyncPager: The List profiles response object. Iterating over this object will yield results and resolve additional pages @@ -218,6 +248,7 @@ async def list_profiles( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=DEFAULT_CLIENT_INFO, @@ -254,7 +285,7 @@ async def create_profile( r"""Creates and returns a new profile. Args: - request (:class:`~.profile_service.CreateProfileRequest`): + request (:class:`google.cloud.talent_v4beta1.types.CreateProfileRequest`): The request object. Create profile request. parent (:class:`str`): Required. The name of the tenant this profile belongs @@ -263,10 +294,11 @@ async def create_profile( The format is "projects/{project_id}/tenants/{tenant_id}". For example, "projects/foo/tenants/bar". + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - profile (:class:`~.gct_profile.Profile`): + profile (:class:`google.cloud.talent_v4beta1.types.Profile`): Required. The profile to be created. This corresponds to the ``profile`` field on the ``request`` instance; if ``request`` is provided, this @@ -279,7 +311,7 @@ async def create_profile( sent along with the request as metadata. Returns: - ~.gct_profile.Profile: + google.cloud.talent_v4beta1.types.Profile: A resource that represents the profile for a job candidate (also referred to as a "single-source @@ -338,7 +370,7 @@ async def get_profile( r"""Gets the specified profile. Args: - request (:class:`~.profile_service.GetProfileRequest`): + request (:class:`google.cloud.talent_v4beta1.types.GetProfileRequest`): The request object. Get profile request. name (:class:`str`): Required. Resource name of the profile to get. @@ -346,6 +378,7 @@ async def get_profile( The format is "projects/{project_id}/tenants/{tenant_id}/profiles/{profile_id}". For example, "projects/foo/tenants/bar/profiles/baz". + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -357,7 +390,7 @@ async def get_profile( sent along with the request as metadata. Returns: - ~.profile.Profile: + google.cloud.talent_v4beta1.types.Profile: A resource that represents the profile for a job candidate (also referred to as a "single-source @@ -393,6 +426,7 @@ async def get_profile( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=DEFAULT_CLIENT_INFO, @@ -423,9 +457,9 @@ async def update_profile( result. Args: - request (:class:`~.profile_service.UpdateProfileRequest`): + request (:class:`google.cloud.talent_v4beta1.types.UpdateProfileRequest`): The request object. Update profile request - profile (:class:`~.gct_profile.Profile`): + profile (:class:`google.cloud.talent_v4beta1.types.Profile`): Required. Profile to be updated. This corresponds to the ``profile`` field on the ``request`` instance; if ``request`` is provided, this @@ -438,7 +472,7 @@ async def update_profile( sent along with the request as metadata. Returns: - ~.gct_profile.Profile: + google.cloud.talent_v4beta1.types.Profile: A resource that represents the profile for a job candidate (also referred to as a "single-source @@ -499,7 +533,7 @@ async def delete_profile( or assignments associated. Args: - request (:class:`~.profile_service.DeleteProfileRequest`): + request (:class:`google.cloud.talent_v4beta1.types.DeleteProfileRequest`): The request object. Delete profile request. name (:class:`str`): Required. Resource name of the profile to be deleted. @@ -507,6 +541,7 @@ async def delete_profile( The format is "projects/{project_id}/tenants/{tenant_id}/profiles/{profile_id}". For example, "projects/foo/tenants/bar/profiles/baz". + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -546,6 +581,7 @@ async def delete_profile( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=DEFAULT_CLIENT_INFO, @@ -581,7 +617,7 @@ async def search_profiles( for more information. Args: - request (:class:`~.profile_service.SearchProfilesRequest`): + request (:class:`google.cloud.talent_v4beta1.types.SearchProfilesRequest`): The request object. The request body of the `SearchProfiles` call. @@ -592,7 +628,7 @@ async def search_profiles( sent along with the request as metadata. Returns: - ~.pagers.SearchProfilesAsyncPager: + google.cloud.talent_v4beta1.services.profile_service.pagers.SearchProfilesAsyncPager: Response of SearchProfiles method. Iterating over this object will yield results and resolve additional pages diff --git a/google/cloud/talent_v4beta1/services/profile_service/client.py b/google/cloud/talent_v4beta1/services/profile_service/client.py index 4cef4bba..eb27801d 100644 --- a/google/cloud/talent_v4beta1/services/profile_service/client.py +++ b/google/cloud/talent_v4beta1/services/profile_service/client.py @@ -118,6 +118,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: + ProfileServiceClient: 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 @@ -130,7 +146,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. + ProfileServiceClient: The constructed client. """ credentials = service_account.Credentials.from_service_account_file(filename) kwargs["credentials"] = credentials @@ -251,10 +267,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, ~.ProfileServiceTransport]): The + transport (Union[str, ProfileServiceTransport]): 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 @@ -290,21 +306,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: @@ -347,7 +359,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, ) @@ -364,15 +376,16 @@ def list_profiles( r"""Lists profiles by filter. The order is unspecified. Args: - request (:class:`~.profile_service.ListProfilesRequest`): + request (google.cloud.talent_v4beta1.types.ListProfilesRequest): The request object. List profiles request. - parent (:class:`str`): + parent (str): Required. The resource name of the tenant under which the profile is created. The format is "projects/{project_id}/tenants/{tenant_id}". For example, "projects/foo/tenants/bar". + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -384,7 +397,7 @@ def list_profiles( sent along with the request as metadata. Returns: - ~.pagers.ListProfilesPager: + google.cloud.talent_v4beta1.services.profile_service.pagers.ListProfilesPager: The List profiles response object. Iterating over this object will yield results and resolve additional pages @@ -449,19 +462,20 @@ def create_profile( r"""Creates and returns a new profile. Args: - request (:class:`~.profile_service.CreateProfileRequest`): + request (google.cloud.talent_v4beta1.types.CreateProfileRequest): The request object. Create profile request. - parent (:class:`str`): + parent (str): Required. The name of the tenant this profile belongs to. The format is "projects/{project_id}/tenants/{tenant_id}". For example, "projects/foo/tenants/bar". + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - profile (:class:`~.gct_profile.Profile`): + profile (google.cloud.talent_v4beta1.types.Profile): Required. The profile to be created. This corresponds to the ``profile`` field on the ``request`` instance; if ``request`` is provided, this @@ -474,7 +488,7 @@ def create_profile( sent along with the request as metadata. Returns: - ~.gct_profile.Profile: + google.cloud.talent_v4beta1.types.Profile: A resource that represents the profile for a job candidate (also referred to as a "single-source @@ -534,14 +548,15 @@ def get_profile( r"""Gets the specified profile. Args: - request (:class:`~.profile_service.GetProfileRequest`): + request (google.cloud.talent_v4beta1.types.GetProfileRequest): The request object. Get profile request. - name (:class:`str`): + name (str): Required. Resource name of the profile to get. The format is "projects/{project_id}/tenants/{tenant_id}/profiles/{profile_id}". For example, "projects/foo/tenants/bar/profiles/baz". + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -553,7 +568,7 @@ def get_profile( sent along with the request as metadata. Returns: - ~.profile.Profile: + google.cloud.talent_v4beta1.types.Profile: A resource that represents the profile for a job candidate (also referred to as a "single-source @@ -612,9 +627,9 @@ def update_profile( result. Args: - request (:class:`~.profile_service.UpdateProfileRequest`): + request (google.cloud.talent_v4beta1.types.UpdateProfileRequest): The request object. Update profile request - profile (:class:`~.gct_profile.Profile`): + profile (google.cloud.talent_v4beta1.types.Profile): Required. Profile to be updated. This corresponds to the ``profile`` field on the ``request`` instance; if ``request`` is provided, this @@ -627,7 +642,7 @@ def update_profile( sent along with the request as metadata. Returns: - ~.gct_profile.Profile: + google.cloud.talent_v4beta1.types.Profile: A resource that represents the profile for a job candidate (also referred to as a "single-source @@ -689,14 +704,15 @@ def delete_profile( or assignments associated. Args: - request (:class:`~.profile_service.DeleteProfileRequest`): + request (google.cloud.talent_v4beta1.types.DeleteProfileRequest): The request object. Delete profile request. - name (:class:`str`): + name (str): Required. Resource name of the profile to be deleted. The format is "projects/{project_id}/tenants/{tenant_id}/profiles/{profile_id}". For example, "projects/foo/tenants/bar/profiles/baz". + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -764,7 +780,7 @@ def search_profiles( for more information. Args: - request (:class:`~.profile_service.SearchProfilesRequest`): + request (google.cloud.talent_v4beta1.types.SearchProfilesRequest): The request object. The request body of the `SearchProfiles` call. @@ -775,7 +791,7 @@ def search_profiles( sent along with the request as metadata. Returns: - ~.pagers.SearchProfilesPager: + google.cloud.talent_v4beta1.services.profile_service.pagers.SearchProfilesPager: Response of SearchProfiles method. Iterating over this object will yield results and resolve additional pages diff --git a/google/cloud/talent_v4beta1/services/profile_service/pagers.py b/google/cloud/talent_v4beta1/services/profile_service/pagers.py index c2f71326..1793730e 100644 --- a/google/cloud/talent_v4beta1/services/profile_service/pagers.py +++ b/google/cloud/talent_v4beta1/services/profile_service/pagers.py @@ -15,7 +15,16 @@ # limitations under the License. # -from typing import Any, AsyncIterable, Awaitable, Callable, Iterable, Sequence, Tuple +from typing import ( + Any, + AsyncIterable, + Awaitable, + Callable, + Iterable, + Sequence, + Tuple, + Optional, +) from google.cloud.talent_v4beta1.types import histogram from google.cloud.talent_v4beta1.types import profile @@ -26,7 +35,7 @@ class ListProfilesPager: """A pager for iterating through ``list_profiles`` requests. This class thinly wraps an initial - :class:`~.profile_service.ListProfilesResponse` object, and + :class:`google.cloud.talent_v4beta1.types.ListProfilesResponse` object, and provides an ``__iter__`` method to iterate through its ``profiles`` field. @@ -35,7 +44,7 @@ class ListProfilesPager: through the ``profiles`` field on the corresponding responses. - All the usual :class:`~.profile_service.ListProfilesResponse` + All the usual :class:`google.cloud.talent_v4beta1.types.ListProfilesResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -53,9 +62,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.profile_service.ListProfilesRequest`): + request (google.cloud.talent_v4beta1.types.ListProfilesRequest): The initial request object. - response (:class:`~.profile_service.ListProfilesResponse`): + response (google.cloud.talent_v4beta1.types.ListProfilesResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -88,7 +97,7 @@ class ListProfilesAsyncPager: """A pager for iterating through ``list_profiles`` requests. This class thinly wraps an initial - :class:`~.profile_service.ListProfilesResponse` object, and + :class:`google.cloud.talent_v4beta1.types.ListProfilesResponse` object, and provides an ``__aiter__`` method to iterate through its ``profiles`` field. @@ -97,7 +106,7 @@ class ListProfilesAsyncPager: through the ``profiles`` field on the corresponding responses. - All the usual :class:`~.profile_service.ListProfilesResponse` + All the usual :class:`google.cloud.talent_v4beta1.types.ListProfilesResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -115,9 +124,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.profile_service.ListProfilesRequest`): + request (google.cloud.talent_v4beta1.types.ListProfilesRequest): The initial request object. - response (:class:`~.profile_service.ListProfilesResponse`): + response (google.cloud.talent_v4beta1.types.ListProfilesResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -154,7 +163,7 @@ class SearchProfilesPager: """A pager for iterating through ``search_profiles`` requests. This class thinly wraps an initial - :class:`~.profile_service.SearchProfilesResponse` object, and + :class:`google.cloud.talent_v4beta1.types.SearchProfilesResponse` object, and provides an ``__iter__`` method to iterate through its ``histogram_query_results`` field. @@ -163,7 +172,7 @@ class SearchProfilesPager: through the ``histogram_query_results`` field on the corresponding responses. - All the usual :class:`~.profile_service.SearchProfilesResponse` + All the usual :class:`google.cloud.talent_v4beta1.types.SearchProfilesResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -181,9 +190,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.profile_service.SearchProfilesRequest`): + request (google.cloud.talent_v4beta1.types.SearchProfilesRequest): The initial request object. - response (:class:`~.profile_service.SearchProfilesResponse`): + response (google.cloud.talent_v4beta1.types.SearchProfilesResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -216,7 +225,7 @@ class SearchProfilesAsyncPager: """A pager for iterating through ``search_profiles`` requests. This class thinly wraps an initial - :class:`~.profile_service.SearchProfilesResponse` object, and + :class:`google.cloud.talent_v4beta1.types.SearchProfilesResponse` object, and provides an ``__aiter__`` method to iterate through its ``histogram_query_results`` field. @@ -225,7 +234,7 @@ class SearchProfilesAsyncPager: through the ``histogram_query_results`` field on the corresponding responses. - All the usual :class:`~.profile_service.SearchProfilesResponse` + All the usual :class:`google.cloud.talent_v4beta1.types.SearchProfilesResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -243,9 +252,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.profile_service.SearchProfilesRequest`): + request (google.cloud.talent_v4beta1.types.SearchProfilesRequest): The initial request object. - response (:class:`~.profile_service.SearchProfilesResponse`): + response (google.cloud.talent_v4beta1.types.SearchProfilesResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. diff --git a/google/cloud/talent_v4beta1/services/profile_service/transports/base.py b/google/cloud/talent_v4beta1/services/profile_service/transports/base.py index dbd36ea2..3a1c0f76 100644 --- a/google/cloud/talent_v4beta1/services/profile_service/transports/base.py +++ b/google/cloud/talent_v4beta1/services/profile_service/transports/base.py @@ -73,10 +73,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. @@ -84,6 +84,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: @@ -93,20 +96,17 @@ def __init__( if credentials_file is not None: credentials, _ = auth.load_credentials_from_file( - credentials_file, scopes=scopes, quota_project_id=quota_project_id + credentials_file, scopes=self._scopes, quota_project_id=quota_project_id ) elif credentials is None: credentials, _ = auth.default( - scopes=scopes, quota_project_id=quota_project_id + scopes=self._scopes, quota_project_id=quota_project_id ) # Save the credentials. self._credentials = credentials - # Lifted into its own function so it can be stubbed out during tests. - self._prep_wrapped_messages(client_info) - def _prep_wrapped_messages(self, client_info): # Precompute the wrapped methods. self._wrapped_methods = { @@ -119,6 +119,7 @@ def _prep_wrapped_messages(self, client_info): predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=client_info, @@ -135,6 +136,7 @@ def _prep_wrapped_messages(self, client_info): predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=client_info, @@ -151,6 +153,7 @@ def _prep_wrapped_messages(self, client_info): predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=client_info, diff --git a/google/cloud/talent_v4beta1/services/profile_service/transports/grpc.py b/google/cloud/talent_v4beta1/services/profile_service/transports/grpc.py index a0a0da7e..a3dbfe39 100644 --- a/google/cloud/talent_v4beta1/services/profile_service/transports/grpc.py +++ b/google/cloud/talent_v4beta1/services/profile_service/transports/grpc.py @@ -61,6 +61,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: @@ -91,6 +92,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): @@ -105,72 +110,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), @@ -178,17 +171,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( @@ -202,7 +186,7 @@ def create_channel( ) -> grpc.Channel: """Create and return a gRPC channel object. Args: - address (Optional[str]): The host for the channel to use. + host (Optional[str]): The host for the channel to use. credentials (Optional[~.Credentials]): The authorization credentials to attach to requests. These credentials identify this application to the service. If diff --git a/google/cloud/talent_v4beta1/services/profile_service/transports/grpc_asyncio.py b/google/cloud/talent_v4beta1/services/profile_service/transports/grpc_asyncio.py index 6db1ab4b..9c405dac 100644 --- a/google/cloud/talent_v4beta1/services/profile_service/transports/grpc_asyncio.py +++ b/google/cloud/talent_v4beta1/services/profile_service/transports/grpc_asyncio.py @@ -65,7 +65,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 @@ -105,6 +105,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: @@ -136,12 +137,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: @@ -150,72 +155,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), @@ -223,17 +216,8 @@ def __init__( ], ) - # Run the base constructor. - super().__init__( - host=host, - credentials=credentials, - credentials_file=credentials_file, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - client_info=client_info, - ) - - self._stubs = {} + # 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/talent_v4beta1/services/tenant_service/async_client.py b/google/cloud/talent_v4beta1/services/tenant_service/async_client.py index be6fce85..047dffe9 100644 --- a/google/cloud/talent_v4beta1/services/tenant_service/async_client.py +++ b/google/cloud/talent_v4beta1/services/tenant_service/async_client.py @@ -80,7 +80,36 @@ class TenantServiceAsyncClient: TenantServiceClient.parse_common_location_path ) - from_service_account_file = TenantServiceClient.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: + TenantServiceAsyncClient: The constructed client. + """ + return TenantServiceClient.from_service_account_info.__func__(TenantServiceAsyncClient, 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: + TenantServiceAsyncClient: The constructed client. + """ + return TenantServiceClient.from_service_account_file.__func__(TenantServiceAsyncClient, filename, *args, **kwargs) # type: ignore + from_service_account_json = from_service_account_file @property @@ -157,7 +186,7 @@ async def create_tenant( r"""Creates a new tenant entity. Args: - request (:class:`~.tenant_service.CreateTenantRequest`): + request (:class:`google.cloud.talent_v4beta1.types.CreateTenantRequest`): The request object. The Request of the CreateTenant method. parent (:class:`str`): @@ -166,10 +195,11 @@ async def create_tenant( The format is "projects/{project_id}", for example, "projects/foo". + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - tenant (:class:`~.gct_tenant.Tenant`): + tenant (:class:`google.cloud.talent_v4beta1.types.Tenant`): Required. The tenant to be created. This corresponds to the ``tenant`` field on the ``request`` instance; if ``request`` is provided, this @@ -182,7 +212,7 @@ async def create_tenant( sent along with the request as metadata. Returns: - ~.gct_tenant.Tenant: + google.cloud.talent_v4beta1.types.Tenant: A Tenant resource represents a tenant in the service. A tenant is a group or entity that shares common access with @@ -244,7 +274,7 @@ async def get_tenant( r"""Retrieves specified tenant. Args: - request (:class:`~.tenant_service.GetTenantRequest`): + request (:class:`google.cloud.talent_v4beta1.types.GetTenantRequest`): The request object. Request for getting a tenant by name. name (:class:`str`): @@ -254,6 +284,7 @@ async def get_tenant( The format is "projects/{project_id}/tenants/{tenant_id}", for example, "projects/foo/tenants/bar". + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -265,7 +296,7 @@ async def get_tenant( sent along with the request as metadata. Returns: - ~.tenant.Tenant: + google.cloud.talent_v4beta1.types.Tenant: A Tenant resource represents a tenant in the service. A tenant is a group or entity that shares common access with @@ -304,6 +335,7 @@ async def get_tenant( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=DEFAULT_CLIENT_INFO, @@ -333,13 +365,14 @@ async def update_tenant( r"""Updates specified tenant. Args: - request (:class:`~.tenant_service.UpdateTenantRequest`): + request (:class:`google.cloud.talent_v4beta1.types.UpdateTenantRequest`): The request object. Request for updating a specified tenant. - tenant (:class:`~.gct_tenant.Tenant`): + tenant (:class:`google.cloud.talent_v4beta1.types.Tenant`): Required. The tenant resource to replace the current resource in the system. + This corresponds to the ``tenant`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -351,7 +384,7 @@ async def update_tenant( sent along with the request as metadata. Returns: - ~.gct_tenant.Tenant: + google.cloud.talent_v4beta1.types.Tenant: A Tenant resource represents a tenant in the service. A tenant is a group or entity that shares common access with @@ -413,7 +446,7 @@ async def delete_tenant( r"""Deletes specified tenant. Args: - request (:class:`~.tenant_service.DeleteTenantRequest`): + request (:class:`google.cloud.talent_v4beta1.types.DeleteTenantRequest`): The request object. Request to delete a tenant. name (:class:`str`): Required. The resource name of the tenant to be deleted. @@ -421,6 +454,7 @@ async def delete_tenant( The format is "projects/{project_id}/tenants/{tenant_id}", for example, "projects/foo/tenants/bar". + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -460,6 +494,7 @@ async def delete_tenant( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=DEFAULT_CLIENT_INFO, @@ -488,7 +523,7 @@ async def list_tenants( r"""Lists all tenants associated with the project. Args: - request (:class:`~.tenant_service.ListTenantsRequest`): + request (:class:`google.cloud.talent_v4beta1.types.ListTenantsRequest`): The request object. List tenants for which the client has ACL visibility. parent (:class:`str`): @@ -497,6 +532,7 @@ async def list_tenants( The format is "projects/{project_id}", for example, "projects/foo". + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -508,7 +544,7 @@ async def list_tenants( sent along with the request as metadata. Returns: - ~.pagers.ListTenantsAsyncPager: + google.cloud.talent_v4beta1.services.tenant_service.pagers.ListTenantsAsyncPager: The List tenants response object. Iterating over this object will yield results and resolve additional pages @@ -544,6 +580,7 @@ async def list_tenants( predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=DEFAULT_CLIENT_INFO, diff --git a/google/cloud/talent_v4beta1/services/tenant_service/client.py b/google/cloud/talent_v4beta1/services/tenant_service/client.py index 52898cda..e0750d74 100644 --- a/google/cloud/talent_v4beta1/services/tenant_service/client.py +++ b/google/cloud/talent_v4beta1/services/tenant_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: + TenantServiceClient: 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. + TenantServiceClient: The constructed client. """ credentials = service_account.Credentials.from_service_account_file(filename) kwargs["credentials"] = credentials @@ -229,10 +245,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, ~.TenantServiceTransport]): The + transport (Union[str, TenantServiceTransport]): 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 @@ -268,21 +284,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: @@ -325,7 +337,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, ) @@ -343,19 +355,20 @@ def create_tenant( r"""Creates a new tenant entity. Args: - request (:class:`~.tenant_service.CreateTenantRequest`): + request (google.cloud.talent_v4beta1.types.CreateTenantRequest): The request object. The Request of the CreateTenant method. - parent (:class:`str`): + parent (str): Required. Resource name of the project under which the tenant is created. The format is "projects/{project_id}", for example, "projects/foo". + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - tenant (:class:`~.gct_tenant.Tenant`): + tenant (google.cloud.talent_v4beta1.types.Tenant): Required. The tenant to be created. This corresponds to the ``tenant`` field on the ``request`` instance; if ``request`` is provided, this @@ -368,7 +381,7 @@ def create_tenant( sent along with the request as metadata. Returns: - ~.gct_tenant.Tenant: + google.cloud.talent_v4beta1.types.Tenant: A Tenant resource represents a tenant in the service. A tenant is a group or entity that shares common access with @@ -431,16 +444,17 @@ def get_tenant( r"""Retrieves specified tenant. Args: - request (:class:`~.tenant_service.GetTenantRequest`): + request (google.cloud.talent_v4beta1.types.GetTenantRequest): The request object. Request for getting a tenant by name. - name (:class:`str`): + name (str): Required. The resource name of the tenant to be retrieved. The format is "projects/{project_id}/tenants/{tenant_id}", for example, "projects/foo/tenants/bar". + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -452,7 +466,7 @@ def get_tenant( sent along with the request as metadata. Returns: - ~.tenant.Tenant: + google.cloud.talent_v4beta1.types.Tenant: A Tenant resource represents a tenant in the service. A tenant is a group or entity that shares common access with @@ -513,13 +527,14 @@ def update_tenant( r"""Updates specified tenant. Args: - request (:class:`~.tenant_service.UpdateTenantRequest`): + request (google.cloud.talent_v4beta1.types.UpdateTenantRequest): The request object. Request for updating a specified tenant. - tenant (:class:`~.gct_tenant.Tenant`): + tenant (google.cloud.talent_v4beta1.types.Tenant): Required. The tenant resource to replace the current resource in the system. + This corresponds to the ``tenant`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -531,7 +546,7 @@ def update_tenant( sent along with the request as metadata. Returns: - ~.gct_tenant.Tenant: + google.cloud.talent_v4beta1.types.Tenant: A Tenant resource represents a tenant in the service. A tenant is a group or entity that shares common access with @@ -594,14 +609,15 @@ def delete_tenant( r"""Deletes specified tenant. Args: - request (:class:`~.tenant_service.DeleteTenantRequest`): + request (google.cloud.talent_v4beta1.types.DeleteTenantRequest): The request object. Request to delete a tenant. - name (:class:`str`): + name (str): Required. The resource name of the tenant to be deleted. The format is "projects/{project_id}/tenants/{tenant_id}", for example, "projects/foo/tenants/bar". + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -662,15 +678,16 @@ def list_tenants( r"""Lists all tenants associated with the project. Args: - request (:class:`~.tenant_service.ListTenantsRequest`): + request (google.cloud.talent_v4beta1.types.ListTenantsRequest): The request object. List tenants for which the client has ACL visibility. - parent (:class:`str`): + parent (str): Required. Resource name of the project under which the tenant is created. The format is "projects/{project_id}", for example, "projects/foo". + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -682,7 +699,7 @@ def list_tenants( sent along with the request as metadata. Returns: - ~.pagers.ListTenantsPager: + google.cloud.talent_v4beta1.services.tenant_service.pagers.ListTenantsPager: The List tenants response object. Iterating over this object will yield results and resolve additional pages diff --git a/google/cloud/talent_v4beta1/services/tenant_service/pagers.py b/google/cloud/talent_v4beta1/services/tenant_service/pagers.py index 99dfee65..5d402971 100644 --- a/google/cloud/talent_v4beta1/services/tenant_service/pagers.py +++ b/google/cloud/talent_v4beta1/services/tenant_service/pagers.py @@ -15,7 +15,16 @@ # limitations under the License. # -from typing import Any, AsyncIterable, Awaitable, Callable, Iterable, Sequence, Tuple +from typing import ( + Any, + AsyncIterable, + Awaitable, + Callable, + Iterable, + Sequence, + Tuple, + Optional, +) from google.cloud.talent_v4beta1.types import tenant from google.cloud.talent_v4beta1.types import tenant_service @@ -25,7 +34,7 @@ class ListTenantsPager: """A pager for iterating through ``list_tenants`` requests. This class thinly wraps an initial - :class:`~.tenant_service.ListTenantsResponse` object, and + :class:`google.cloud.talent_v4beta1.types.ListTenantsResponse` object, and provides an ``__iter__`` method to iterate through its ``tenants`` field. @@ -34,7 +43,7 @@ class ListTenantsPager: through the ``tenants`` field on the corresponding responses. - All the usual :class:`~.tenant_service.ListTenantsResponse` + All the usual :class:`google.cloud.talent_v4beta1.types.ListTenantsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -52,9 +61,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.tenant_service.ListTenantsRequest`): + request (google.cloud.talent_v4beta1.types.ListTenantsRequest): The initial request object. - response (:class:`~.tenant_service.ListTenantsResponse`): + response (google.cloud.talent_v4beta1.types.ListTenantsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -87,7 +96,7 @@ class ListTenantsAsyncPager: """A pager for iterating through ``list_tenants`` requests. This class thinly wraps an initial - :class:`~.tenant_service.ListTenantsResponse` object, and + :class:`google.cloud.talent_v4beta1.types.ListTenantsResponse` object, and provides an ``__aiter__`` method to iterate through its ``tenants`` field. @@ -96,7 +105,7 @@ class ListTenantsAsyncPager: through the ``tenants`` field on the corresponding responses. - All the usual :class:`~.tenant_service.ListTenantsResponse` + All the usual :class:`google.cloud.talent_v4beta1.types.ListTenantsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -114,9 +123,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.tenant_service.ListTenantsRequest`): + request (google.cloud.talent_v4beta1.types.ListTenantsRequest): The initial request object. - response (:class:`~.tenant_service.ListTenantsResponse`): + response (google.cloud.talent_v4beta1.types.ListTenantsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. diff --git a/google/cloud/talent_v4beta1/services/tenant_service/transports/base.py b/google/cloud/talent_v4beta1/services/tenant_service/transports/base.py index b0f77c0d..73ae1b06 100644 --- a/google/cloud/talent_v4beta1/services/tenant_service/transports/base.py +++ b/google/cloud/talent_v4beta1/services/tenant_service/transports/base.py @@ -73,10 +73,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. @@ -84,6 +84,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: @@ -93,20 +96,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 = { @@ -122,6 +122,7 @@ def _prep_wrapped_messages(self, client_info): predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=client_info, @@ -138,6 +139,7 @@ def _prep_wrapped_messages(self, client_info): predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=client_info, @@ -151,6 +153,7 @@ def _prep_wrapped_messages(self, client_info): predicate=retries.if_exception_type( exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, ), + deadline=30.0, ), default_timeout=30.0, client_info=client_info, diff --git a/google/cloud/talent_v4beta1/services/tenant_service/transports/grpc.py b/google/cloud/talent_v4beta1/services/tenant_service/transports/grpc.py index eae306f9..f187b6c1 100644 --- a/google/cloud/talent_v4beta1/services/tenant_service/transports/grpc.py +++ b/google/cloud/talent_v4beta1/services/tenant_service/transports/grpc.py @@ -61,6 +61,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: @@ -91,6 +92,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): @@ -105,72 +110,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), @@ -178,17 +171,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( @@ -202,7 +186,7 @@ def create_channel( ) -> grpc.Channel: """Create and return a gRPC channel object. Args: - address (Optional[str]): The host for the channel to use. + host (Optional[str]): The host for the channel to use. credentials (Optional[~.Credentials]): The authorization credentials to attach to requests. These credentials identify this application to the service. If diff --git a/google/cloud/talent_v4beta1/services/tenant_service/transports/grpc_asyncio.py b/google/cloud/talent_v4beta1/services/tenant_service/transports/grpc_asyncio.py index cec885b2..59aa7ff4 100644 --- a/google/cloud/talent_v4beta1/services/tenant_service/transports/grpc_asyncio.py +++ b/google/cloud/talent_v4beta1/services/tenant_service/transports/grpc_asyncio.py @@ -65,7 +65,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 @@ -105,6 +105,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: @@ -136,12 +137,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: @@ -150,72 +155,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), @@ -223,17 +216,8 @@ def __init__( ], ) - # Run the base constructor. - super().__init__( - host=host, - credentials=credentials, - credentials_file=credentials_file, - scopes=scopes or self.AUTH_SCOPES, - quota_project_id=quota_project_id, - client_info=client_info, - ) - - self._stubs = {} + # 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/talent_v4beta1/types/__init__.py b/google/cloud/talent_v4beta1/types/__init__.py index 3d326265..98bf50a7 100644 --- a/google/cloud/talent_v4beta1/types/__init__.py +++ b/google/cloud/talent_v4beta1/types/__init__.py @@ -15,52 +15,52 @@ # limitations under the License. # +from .application import Application +from .application_service import ( + CreateApplicationRequest, + DeleteApplicationRequest, + GetApplicationRequest, + ListApplicationsRequest, + ListApplicationsResponse, + UpdateApplicationRequest, +) from .common import ( - TimestampRange, + BatchOperationMetadata, + Certification, + CompensationInfo, + CustomAttribute, + DeviceInfo, + Interview, Location, + Rating, RequestMetadata, ResponseMetadata, - DeviceInfo, - CustomAttribute, - SpellingCorrection, - CompensationInfo, - Certification, Skill, - Interview, - Rating, - BatchOperationMetadata, + SpellingCorrection, + TimestampRange, + AvailabilitySignalType, + CommuteMethod, CompanySize, - JobBenefit, + ContactInfoUsage, DegreeType, EmploymentType, - JobLevel, + HtmlSanitization, + JobBenefit, JobCategory, + JobLevel, + Outcome, PostingRegion, - Visibility, - ContactInfoUsage, - HtmlSanitization, - CommuteMethod, SkillProficiencyLevel, - Outcome, - AvailabilitySignalType, -) -from .application import Application -from .application_service import ( - CreateApplicationRequest, - GetApplicationRequest, - UpdateApplicationRequest, - DeleteApplicationRequest, - ListApplicationsRequest, - ListApplicationsResponse, + Visibility, ) from .company import Company from .company_service import ( CreateCompanyRequest, - GetCompanyRequest, - UpdateCompanyRequest, DeleteCompanyRequest, + GetCompanyRequest, ListCompaniesRequest, ListCompaniesResponse, + UpdateCompanyRequest, ) from .completion_service import ( CompleteQueryRequest, @@ -73,23 +73,23 @@ ) from .event_service import CreateClientEventRequest from .filters import ( - JobQuery, - ProfileQuery, - LocationFilter, - CompensationFilter, - CommuteFilter, - JobTitleFilter, - SkillFilter, - EmployerFilter, - EducationFilter, - WorkExperienceFilter, ApplicationDateFilter, - ApplicationOutcomeNotesFilter, ApplicationJobFilter, - TimeFilter, - CandidateAvailabilityFilter, + ApplicationOutcomeNotesFilter, AvailabilityFilter, + CandidateAvailabilityFilter, + CommuteFilter, + CompensationFilter, + EducationFilter, + EmployerFilter, + JobQuery, + JobTitleFilter, + LocationFilter, PersonNameFilter, + ProfileQuery, + SkillFilter, + TimeFilter, + WorkExperienceFilter, ) from .histogram import ( HistogramQuery, @@ -97,168 +97,168 @@ ) from .job import Job from .job_service import ( + BatchCreateJobsRequest, + BatchDeleteJobsRequest, + BatchUpdateJobsRequest, CreateJobRequest, - GetJobRequest, - UpdateJobRequest, DeleteJobRequest, - BatchDeleteJobsRequest, + GetJobRequest, + JobOperationResult, ListJobsRequest, ListJobsResponse, SearchJobsRequest, SearchJobsResponse, - BatchCreateJobsRequest, - BatchUpdateJobsRequest, - JobOperationResult, + UpdateJobRequest, JobView, ) from .profile import ( - Profile, - AvailabilitySignal, - Resume, - PersonName, + Activity, + AdditionalContactInfo, Address, + AvailabilitySignal, + Degree, + EducationRecord, Email, - Phone, - PersonalUri, - AdditionalContactInfo, EmploymentRecord, - EducationRecord, - Degree, - Activity, - Publication, Patent, + PersonalUri, + PersonName, + Phone, + Profile, + Publication, + Resume, ) from .profile_service import ( - ListProfilesRequest, - ListProfilesResponse, CreateProfileRequest, - GetProfileRequest, - UpdateProfileRequest, DeleteProfileRequest, + GetProfileRequest, + ListProfilesRequest, + ListProfilesResponse, SearchProfilesRequest, SearchProfilesResponse, SummarizedProfile, + UpdateProfileRequest, ) from .tenant import Tenant from .tenant_service import ( CreateTenantRequest, - GetTenantRequest, - UpdateTenantRequest, DeleteTenantRequest, + GetTenantRequest, ListTenantsRequest, ListTenantsResponse, + UpdateTenantRequest, ) __all__ = ( - "TimestampRange", + "Application", + "CreateApplicationRequest", + "DeleteApplicationRequest", + "GetApplicationRequest", + "ListApplicationsRequest", + "ListApplicationsResponse", + "UpdateApplicationRequest", + "BatchOperationMetadata", + "Certification", + "CompensationInfo", + "CustomAttribute", + "DeviceInfo", + "Interview", "Location", + "Rating", "RequestMetadata", "ResponseMetadata", - "DeviceInfo", - "CustomAttribute", - "SpellingCorrection", - "CompensationInfo", - "Certification", "Skill", - "Interview", - "Rating", - "BatchOperationMetadata", + "SpellingCorrection", + "TimestampRange", + "AvailabilitySignalType", + "CommuteMethod", "CompanySize", - "JobBenefit", + "ContactInfoUsage", "DegreeType", "EmploymentType", - "JobLevel", + "HtmlSanitization", + "JobBenefit", "JobCategory", + "JobLevel", + "Outcome", "PostingRegion", - "Visibility", - "ContactInfoUsage", - "HtmlSanitization", - "CommuteMethod", "SkillProficiencyLevel", - "Outcome", - "AvailabilitySignalType", - "Application", - "CreateApplicationRequest", - "GetApplicationRequest", - "UpdateApplicationRequest", - "DeleteApplicationRequest", - "ListApplicationsRequest", - "ListApplicationsResponse", + "Visibility", "Company", "CreateCompanyRequest", - "GetCompanyRequest", - "UpdateCompanyRequest", "DeleteCompanyRequest", + "GetCompanyRequest", "ListCompaniesRequest", "ListCompaniesResponse", + "UpdateCompanyRequest", "CompleteQueryRequest", "CompleteQueryResponse", "ClientEvent", "JobEvent", "ProfileEvent", "CreateClientEventRequest", - "JobQuery", - "ProfileQuery", - "LocationFilter", - "CompensationFilter", - "CommuteFilter", - "JobTitleFilter", - "SkillFilter", - "EmployerFilter", - "EducationFilter", - "WorkExperienceFilter", "ApplicationDateFilter", - "ApplicationOutcomeNotesFilter", "ApplicationJobFilter", - "TimeFilter", - "CandidateAvailabilityFilter", + "ApplicationOutcomeNotesFilter", "AvailabilityFilter", + "CandidateAvailabilityFilter", + "CommuteFilter", + "CompensationFilter", + "EducationFilter", + "EmployerFilter", + "JobQuery", + "JobTitleFilter", + "LocationFilter", "PersonNameFilter", + "ProfileQuery", + "SkillFilter", + "TimeFilter", + "WorkExperienceFilter", "HistogramQuery", "HistogramQueryResult", "Job", + "BatchCreateJobsRequest", + "BatchDeleteJobsRequest", + "BatchUpdateJobsRequest", "CreateJobRequest", - "GetJobRequest", - "UpdateJobRequest", "DeleteJobRequest", - "BatchDeleteJobsRequest", + "GetJobRequest", + "JobOperationResult", "ListJobsRequest", "ListJobsResponse", "SearchJobsRequest", "SearchJobsResponse", - "BatchCreateJobsRequest", - "BatchUpdateJobsRequest", - "JobOperationResult", + "UpdateJobRequest", "JobView", - "Profile", - "AvailabilitySignal", - "Resume", - "PersonName", + "Activity", + "AdditionalContactInfo", "Address", + "AvailabilitySignal", + "Degree", + "EducationRecord", "Email", - "Phone", - "PersonalUri", - "AdditionalContactInfo", "EmploymentRecord", - "EducationRecord", - "Degree", - "Activity", - "Publication", "Patent", - "ListProfilesRequest", - "ListProfilesResponse", + "PersonalUri", + "PersonName", + "Phone", + "Profile", + "Publication", + "Resume", "CreateProfileRequest", - "GetProfileRequest", - "UpdateProfileRequest", "DeleteProfileRequest", + "GetProfileRequest", + "ListProfilesRequest", + "ListProfilesResponse", "SearchProfilesRequest", "SearchProfilesResponse", "SummarizedProfile", + "UpdateProfileRequest", "Tenant", "CreateTenantRequest", - "GetTenantRequest", - "UpdateTenantRequest", "DeleteTenantRequest", + "GetTenantRequest", "ListTenantsRequest", "ListTenantsResponse", + "UpdateTenantRequest", ) diff --git a/google/cloud/talent_v4beta1/types/application.py b/google/cloud/talent_v4beta1/types/application.py index c407b4bc..41eda976 100644 --- a/google/cloud/talent_v4beta1/types/application.py +++ b/google/cloud/talent_v4beta1/types/application.py @@ -69,9 +69,9 @@ class Application(proto.Message): The format is "projects/{project_id}/tenants/{tenant_id}/companies/{company_id}". For example, "projects/foo/tenants/bar/companies/baz". - application_date (~.date.Date): + application_date (google.type.date_pb2.Date): The application date. - stage (~.application.Application.ApplicationStage): + stage (google.cloud.talent_v4beta1.types.Application.ApplicationStage): Required. What is the most recent stage of the application (that is, new, screen, send cv, hired, finished work)? This field is @@ -79,19 +79,19 @@ class Application(proto.Message): possible status, but instead, represents statuses that would be used to indicate to the ML models good / bad matches. - state (~.application.Application.ApplicationState): + state (google.cloud.talent_v4beta1.types.Application.ApplicationState): The application state. - interviews (Sequence[~.common.Interview]): + interviews (Sequence[google.cloud.talent_v4beta1.types.Interview]): All interviews (screen, onsite, and so on) conducted as part of this application (includes details such as user conducting the interview, timestamp, feedback, and so on). - referral (~.wrappers.BoolValue): + referral (google.protobuf.wrappers_pb2.BoolValue): If the candidate is referred by a employee. - create_time (~.timestamp.Timestamp): + create_time (google.protobuf.timestamp_pb2.Timestamp): Required. Reflects the time that the application was created. - update_time (~.timestamp.Timestamp): + update_time (google.protobuf.timestamp_pb2.Timestamp): The last update timestamp. outcome_notes (str): Free text reason behind the recruitement @@ -99,10 +99,10 @@ class Application(proto.Message): reject, reason for an unsuccessful finish, and so on). Number of characters allowed is 100. - outcome (~.common.Outcome): + outcome (google.cloud.talent_v4beta1.types.Outcome): Outcome positiveness shows how positive the outcome is. - is_match (~.wrappers.BoolValue): + is_match (google.protobuf.wrappers_pb2.BoolValue): Output only. Indicates whether this job application is a match to application related filters. This value is only applicable in diff --git a/google/cloud/talent_v4beta1/types/application_service.py b/google/cloud/talent_v4beta1/types/application_service.py index 8c906e91..81a0bae8 100644 --- a/google/cloud/talent_v4beta1/types/application_service.py +++ b/google/cloud/talent_v4beta1/types/application_service.py @@ -47,7 +47,7 @@ class CreateApplicationRequest(proto.Message): The format is "projects/{project_id}/tenants/{tenant_id}/profiles/{profile_id}". For example, "projects/foo/tenants/bar/profiles/baz". - application (~.gct_application.Application): + application (google.cloud.talent_v4beta1.types.Application): Required. The application to be created. """ @@ -79,10 +79,10 @@ class UpdateApplicationRequest(proto.Message): r"""Request for updating a specified application. Attributes: - application (~.gct_application.Application): + application (google.cloud.talent_v4beta1.types.Application): Required. The application resource to replace the current resource in the system. - update_mask (~.field_mask.FieldMask): + update_mask (google.protobuf.field_mask_pb2.FieldMask): Strongly recommended for the best service experience. If @@ -152,11 +152,11 @@ class ListApplicationsResponse(proto.Message): r"""The List applications response object. Attributes: - applications (Sequence[~.gct_application.Application]): + applications (Sequence[google.cloud.talent_v4beta1.types.Application]): Applications for the current client. next_page_token (str): A token to retrieve the next page of results. - metadata (~.common.ResponseMetadata): + metadata (google.cloud.talent_v4beta1.types.ResponseMetadata): Additional information for the API invocation, such as the request tracking id. """ diff --git a/google/cloud/talent_v4beta1/types/common.py b/google/cloud/talent_v4beta1/types/common.py index 61614a0a..3d6d81ba 100644 --- a/google/cloud/talent_v4beta1/types/common.py +++ b/google/cloud/talent_v4beta1/types/common.py @@ -187,6 +187,7 @@ class Visibility(proto.Enum): r"""Deprecated. All resources are only visible to the owner. An enum that represents who has view access to the resource. """ + _pb_options = {"deprecated": True} VISIBILITY_UNSPECIFIED = 0 ACCOUNT_ONLY = 1 SHARED_WITH_GOOGLE = 2 @@ -254,9 +255,9 @@ class TimestampRange(proto.Message): r"""Message representing a period of time between two timestamps. Attributes: - start_time (~.timestamp.Timestamp): + start_time (google.protobuf.timestamp_pb2.Timestamp): Begin of the period (inclusive). - end_time (~.timestamp.Timestamp): + end_time (google.protobuf.timestamp_pb2.Timestamp): End of the period (exclusive). """ @@ -270,7 +271,7 @@ class Location(proto.Message): information. Attributes: - location_type (~.common.Location.LocationType): + location_type (google.cloud.talent_v4beta1.types.Location.LocationType): The type of a location, which corresponds to the address lines field of [google.type.PostalAddress][google.type.PostalAddress]. For @@ -278,13 +279,13 @@ class Location(proto.Message): [LocationType.NEIGHBORHOOD][google.cloud.talent.v4beta1.Location.LocationType.NEIGHBORHOOD], and "Kansas City, KS, USA" has a type of [LocationType.LOCALITY][google.cloud.talent.v4beta1.Location.LocationType.LOCALITY]. - postal_address (~.gt_postal_address.PostalAddress): + postal_address (google.type.postal_address_pb2.PostalAddress): Postal address of the location that includes human readable information, such as postal delivery and payments addresses. Given a postal address, a postal service can deliver items to a premises, P.O. Box, or other delivery location. - lat_lng (~.latlng.LatLng): + lat_lng (google.type.latlng_pb2.LatLng): An object representing a latitude/longitude pair. radius_miles (float): @@ -390,7 +391,7 @@ class RequestMetadata(proto.Message): and [user_id][google.cloud.talent.v4beta1.RequestMetadata.user_id] for the best service experience. - device_info (~.common.DeviceInfo): + device_info (google.cloud.talent_v4beta1.types.DeviceInfo): The type of device used by the job seeker at the time of the call to the service. """ @@ -426,7 +427,7 @@ class DeviceInfo(proto.Message): devices. Attributes: - device_type (~.common.DeviceInfo.DeviceType): + device_type (google.cloud.talent_v4beta1.types.DeviceInfo.DeviceType): Type of the device. id (str): A device-specific ID. The ID must be a unique @@ -532,14 +533,14 @@ class CompensationInfo(proto.Message): r"""Job compensation details. Attributes: - entries (Sequence[~.common.CompensationInfo.CompensationEntry]): + entries (Sequence[google.cloud.talent_v4beta1.types.CompensationInfo.CompensationEntry]): Job compensation information. At most one entry can be of type [CompensationInfo.CompensationType.BASE][google.cloud.talent.v4beta1.CompensationInfo.CompensationType.BASE], which is referred as **base compensation entry** for the job. - annualized_base_compensation_range (~.common.CompensationInfo.CompensationRange): + annualized_base_compensation_range (google.cloud.talent_v4beta1.types.CompensationInfo.CompensationRange): Output only. Annualized base compensation range. Computed as base compensation entry's [CompensationEntry.amount][google.cloud.talent.v4beta1.CompensationInfo.CompensationEntry.amount] @@ -549,7 +550,7 @@ class CompensationInfo(proto.Message): See [CompensationEntry][google.cloud.talent.v4beta1.CompensationInfo.CompensationEntry] for explanation on compensation annualization. - annualized_total_compensation_range (~.common.CompensationInfo.CompensationRange): + annualized_total_compensation_range (google.cloud.talent_v4beta1.types.CompensationInfo.CompensationRange): Output only. Annualized total compensation range. Computed as all compensation entries' [CompensationEntry.amount][google.cloud.talent.v4beta1.CompensationInfo.CompensationEntry.amount] @@ -631,25 +632,25 @@ class CompensationEntry(proto.Message): [expected_units_per_year][google.cloud.talent.v4beta1.CompensationInfo.CompensationEntry.expected_units_per_year]. Attributes: - type_ (~.common.CompensationInfo.CompensationType): + type_ (google.cloud.talent_v4beta1.types.CompensationInfo.CompensationType): Compensation type. Default is [CompensationType.COMPENSATION_TYPE_UNSPECIFIED][google.cloud.talent.v4beta1.CompensationInfo.CompensationType.COMPENSATION_TYPE_UNSPECIFIED]. - unit (~.common.CompensationInfo.CompensationUnit): + unit (google.cloud.talent_v4beta1.types.CompensationInfo.CompensationUnit): Frequency of the specified amount. Default is [CompensationUnit.COMPENSATION_UNIT_UNSPECIFIED][google.cloud.talent.v4beta1.CompensationInfo.CompensationUnit.COMPENSATION_UNIT_UNSPECIFIED]. - amount (~.money.Money): + amount (google.type.money_pb2.Money): Compensation amount. - range_ (~.common.CompensationInfo.CompensationRange): + range_ (google.cloud.talent_v4beta1.types.CompensationInfo.CompensationRange): Compensation range. description (str): Compensation description. For example, could indicate equity terms or provide additional context to an estimated bonus. - expected_units_per_year (~.wrappers.DoubleValue): + expected_units_per_year (google.protobuf.wrappers_pb2.DoubleValue): Expected number of units paid each year. If not specified, when [Job.employment_types][google.cloud.talent.v4beta1.Job.employment_types] @@ -693,12 +694,12 @@ class CompensationRange(proto.Message): r"""Compensation range. Attributes: - max_compensation (~.money.Money): + max_compensation (google.type.money_pb2.Money): The maximum amount of compensation. If left empty, the value is set to a maximal compensation value and the currency code is set to match the [currency code][google.type.Money.currency_code] of min_compensation. - min_compensation (~.money.Money): + min_compensation (google.type.money_pb2.Money): The minimum amount of compensation. If left empty, the value is set to zero and the currency code is set to match the [currency code][google.type.Money.currency_code] of @@ -727,10 +728,10 @@ class Certification(proto.Message): display_name (str): Name of license or certification. Number of characters allowed is 100. - acquire_date (~.date.Date): + acquire_date (google.type.date_pb2.Date): Acquisition date or effective date of license or certification. - expire_date (~.date.Date): + expire_date (google.type.date_pb2.Date): Expiration date of license of certification. authority (str): Authority of license, such as government. @@ -760,9 +761,9 @@ class Skill(proto.Message): For example, "Java", "Python". Number of characters allowed is 100. - last_used_date (~.date.Date): + last_used_date (google.type.date_pb2.Date): The last time this skill was used. - level (~.common.SkillProficiencyLevel): + level (google.cloud.talent_v4beta1.types.SkillProficiencyLevel): Skill proficiency level which indicates how proficient the candidate is at this skill. context (str): @@ -791,9 +792,9 @@ class Interview(proto.Message): r"""Details of an interview. Attributes: - rating (~.common.Rating): + rating (google.cloud.talent_v4beta1.types.Rating): The rating on this interview. - outcome (~.common.Outcome): + outcome (google.cloud.talent_v4beta1.types.Outcome): Required. The overall decision resulting from this interview (positive, negative, nuetral). """ @@ -835,7 +836,7 @@ class BatchOperationMetadata(proto.Message): [google.longrunning.Operation.metadata][google.longrunning.Operation.metadata]. Attributes: - state (~.common.BatchOperationMetadata.State): + state (google.cloud.talent_v4beta1.types.BatchOperationMetadata.State): The state of a long running operation. state_description (str): More detailed information about operation @@ -847,14 +848,14 @@ class BatchOperationMetadata(proto.Message): Count of failed item(s) inside an operation. total_count (int): Count of total item(s) inside an operation. - create_time (~.timestamp.Timestamp): + create_time (google.protobuf.timestamp_pb2.Timestamp): The time when the batch operation is created. - update_time (~.timestamp.Timestamp): + update_time (google.protobuf.timestamp_pb2.Timestamp): The time when the batch operation status is updated. The metadata and the [update_time][google.cloud.talent.v4beta1.BatchOperationMetadata.update_time] is refreshed every minute otherwise cached data is returned. - end_time (~.timestamp.Timestamp): + end_time (google.protobuf.timestamp_pb2.Timestamp): The time when the batch operation is finished and [google.longrunning.Operation.done][google.longrunning.Operation.done] is set to ``true``. diff --git a/google/cloud/talent_v4beta1/types/company.py b/google/cloud/talent_v4beta1/types/company.py index ac333e29..ed091608 100644 --- a/google/cloud/talent_v4beta1/types/company.py +++ b/google/cloud/talent_v4beta1/types/company.py @@ -53,7 +53,7 @@ class Company(proto.Message): used to uniquely identify the company. The maximum number of allowed characters is 255. - size (~.common.CompanySize): + size (google.cloud.talent_v4beta1.types.CompanySize): The employer's company size. headquarters_address (str): The street address of the company's main headquarters, which @@ -92,7 +92,7 @@ class Company(proto.Message): search keyword. Custom field values with parenthesis, brackets and special symbols are not searchable as-is, and those keyword queries must be surrounded by quotes. - derived_info (~.company.Company.DerivedInfo): + derived_info (google.cloud.talent_v4beta1.types.Company.DerivedInfo): Output only. Derived details about the company. suspended (bool): @@ -106,7 +106,7 @@ class DerivedInfo(proto.Message): r"""Derived details about the company. Attributes: - headquarters_location (~.common.Location): + headquarters_location (google.cloud.talent_v4beta1.types.Location): A structured headquarters location of the company, resolved from [Company.headquarters_address][google.cloud.talent.v4beta1.Company.headquarters_address] diff --git a/google/cloud/talent_v4beta1/types/company_service.py b/google/cloud/talent_v4beta1/types/company_service.py index 960ab39c..ab1de2b8 100644 --- a/google/cloud/talent_v4beta1/types/company_service.py +++ b/google/cloud/talent_v4beta1/types/company_service.py @@ -48,7 +48,7 @@ class CreateCompanyRequest(proto.Message): for example, "projects/foo/tenant/bar". If tenant id is unspecified, a default tenant is created, for example, "projects/foo". - company (~.gct_company.Company): + company (google.cloud.talent_v4beta1.types.Company): Required. The company to be created. """ @@ -80,10 +80,10 @@ class UpdateCompanyRequest(proto.Message): r"""Request for updating a specified company. Attributes: - company (~.gct_company.Company): + company (google.cloud.talent_v4beta1.types.Company): Required. The company resource to replace the current resource in the system. - update_mask (~.field_mask.FieldMask): + update_mask (google.protobuf.field_mask_pb2.FieldMask): Strongly recommended for the best service experience. If @@ -165,11 +165,11 @@ class ListCompaniesResponse(proto.Message): r"""The List companies response object. Attributes: - companies (Sequence[~.gct_company.Company]): + companies (Sequence[google.cloud.talent_v4beta1.types.Company]): Companies for the current client. next_page_token (str): A token to retrieve the next page of results. - metadata (~.common.ResponseMetadata): + metadata (google.cloud.talent_v4beta1.types.ResponseMetadata): Additional information for the API invocation, such as the request tracking id. """ diff --git a/google/cloud/talent_v4beta1/types/completion_service.py b/google/cloud/talent_v4beta1/types/completion_service.py index 69f4882a..1b53f07e 100644 --- a/google/cloud/talent_v4beta1/types/completion_service.py +++ b/google/cloud/talent_v4beta1/types/completion_service.py @@ -63,10 +63,10 @@ class CompleteQueryRequest(proto.Message): If tenant id is unspecified, the default tenant is used, for example, "projects/foo". - scope (~.completion_service.CompleteQueryRequest.CompletionScope): + scope (google.cloud.talent_v4beta1.types.CompleteQueryRequest.CompletionScope): The scope of the completion. The defaults is [CompletionScope.PUBLIC][google.cloud.talent.v4beta1.CompleteQueryRequest.CompletionScope.PUBLIC]. - type_ (~.completion_service.CompleteQueryRequest.CompletionType): + type_ (google.cloud.talent_v4beta1.types.CompleteQueryRequest.CompletionType): The completion topic. The default is [CompletionType.COMBINED][google.cloud.talent.v4beta1.CompleteQueryRequest.CompletionType.COMBINED]. """ @@ -103,10 +103,10 @@ class CompleteQueryResponse(proto.Message): r"""Response of auto-complete query. Attributes: - completion_results (Sequence[~.completion_service.CompleteQueryResponse.CompletionResult]): + completion_results (Sequence[google.cloud.talent_v4beta1.types.CompleteQueryResponse.CompletionResult]): Results of the matching job/company candidates. - metadata (~.common.ResponseMetadata): + metadata (google.cloud.talent_v4beta1.types.ResponseMetadata): Additional information for the API invocation, such as the request tracking id. """ @@ -117,7 +117,7 @@ class CompletionResult(proto.Message): Attributes: suggestion (str): The suggestion for the query. - type_ (~.completion_service.CompleteQueryRequest.CompletionType): + type_ (google.cloud.talent_v4beta1.types.CompleteQueryRequest.CompletionType): The completion topic. image_uri (str): The URI of the company image for diff --git a/google/cloud/talent_v4beta1/types/event.py b/google/cloud/talent_v4beta1/types/event.py index 4583b654..70cec508 100644 --- a/google/cloud/talent_v4beta1/types/event.py +++ b/google/cloud/talent_v4beta1/types/event.py @@ -45,13 +45,13 @@ class ClientEvent(proto.Message): event_id (str): Required. A unique identifier, generated by the client application. - create_time (~.timestamp.Timestamp): + create_time (google.protobuf.timestamp_pb2.Timestamp): Required. The timestamp of the event. - job_event (~.event.JobEvent): + job_event (google.cloud.talent_v4beta1.types.JobEvent): An event issued when a job seeker interacts with the application that implements Cloud Talent Solution. - profile_event (~.event.ProfileEvent): + profile_event (google.cloud.talent_v4beta1.types.ProfileEvent): An event issued when a profile searcher interacts with the application that implements Cloud Talent Solution. @@ -81,7 +81,7 @@ class JobEvent(proto.Message): application that implements Cloud Talent Solution. Attributes: - type_ (~.event.JobEvent.JobEventType): + type_ (google.cloud.talent_v4beta1.types.JobEvent.JobEventType): Required. The type of the event (see [JobEventType][google.cloud.talent.v4beta1.JobEvent.JobEventType]). jobs (Sequence[str]): @@ -139,7 +139,7 @@ class ProfileEvent(proto.Message): application that implements Cloud Talent Solution. Attributes: - type_ (~.event.ProfileEvent.ProfileEventType): + type_ (google.cloud.talent_v4beta1.types.ProfileEvent.ProfileEventType): Required. Type of event. profiles (Sequence[str]): Required. The [profile diff --git a/google/cloud/talent_v4beta1/types/event_service.py b/google/cloud/talent_v4beta1/types/event_service.py index dad4a639..d389c18f 100644 --- a/google/cloud/talent_v4beta1/types/event_service.py +++ b/google/cloud/talent_v4beta1/types/event_service.py @@ -38,7 +38,7 @@ class CreateClientEventRequest(proto.Message): for example, "projects/foo/tenant/bar". If tenant id is unspecified, a default tenant is created, for example, "projects/foo". - client_event (~.event.ClientEvent): + client_event (google.cloud.talent_v4beta1.types.ClientEvent): Required. Events issued when end user interacts with customer's application that uses Cloud Talent Solution. diff --git a/google/cloud/talent_v4beta1/types/filters.py b/google/cloud/talent_v4beta1/types/filters.py index 48d631b4..70f87f90 100644 --- a/google/cloud/talent_v4beta1/types/filters.py +++ b/google/cloud/talent_v4beta1/types/filters.py @@ -90,7 +90,7 @@ class JobQuery(proto.Message): example, "projects/foo/companies/bar". At most 20 company filters are allowed. - location_filters (Sequence[~.filters.LocationFilter]): + location_filters (Sequence[google.cloud.talent_v4beta1.types.LocationFilter]): The location filter specifies geo-regions containing the jobs to search against. See [LocationFilter][google.cloud.talent.v4beta1.LocationFilter] @@ -108,7 +108,7 @@ class JobQuery(proto.Message): locations. At most 5 location filters are allowed. - job_categories (Sequence[~.common.JobCategory]): + job_categories (Sequence[google.cloud.talent_v4beta1.types.JobCategory]): The category filter specifies the categories of jobs to search against. See [JobCategory][google.cloud.talent.v4beta1.JobCategory] for @@ -119,7 +119,7 @@ class JobQuery(proto.Message): If multiple values are specified, jobs from any of the specified categories are searched against. - commute_filter (~.filters.CommuteFilter): + commute_filter (google.cloud.talent_v4beta1.types.CommuteFilter): Allows filtering jobs by commute time with different travel methods (for example, driving or public transit). @@ -143,7 +143,7 @@ class JobQuery(proto.Message): companies. At most 20 company display name filters are allowed. - compensation_filter (~.filters.CompensationFilter): + compensation_filter (google.cloud.talent_v4beta1.types.CompensationFilter): This search filter is applied only to [Job.compensation_info][google.cloud.talent.v4beta1.Job.compensation_info]. For example, if the filter is specified as "Hourly job with @@ -182,7 +182,7 @@ class JobQuery(proto.Message): misspelled query, for example, "enginee" is corrected to "engineer". Defaults to false: a spell check is performed. - employment_types (Sequence[~.common.EmploymentType]): + employment_types (Sequence[google.cloud.talent_v4beta1.types.EmploymentType]): The employment type filter specifies the employment type of jobs to search against, such as [EmploymentType.FULL_TIME][google.cloud.talent.v4beta1.EmploymentType.FULL_TIME]. @@ -205,7 +205,7 @@ class JobQuery(proto.Message): Languages `__. At most 10 language code filters are allowed. - publish_time_range (~.common.TimestampRange): + publish_time_range (google.cloud.talent_v4beta1.types.TimestampRange): Jobs published within a range specified by this filter are searched against. excluded_jobs (Sequence[str]): @@ -259,7 +259,7 @@ class ProfileQuery(proto.Message): Keywords to match any text fields of profiles. For example, "software engineer in Palo Alto". - location_filters (Sequence[~.filters.LocationFilter]): + location_filters (Sequence[google.cloud.talent_v4beta1.types.LocationFilter]): The location filter specifies geo-regions containing the profiles to search against. @@ -379,7 +379,7 @@ class ProfileQuery(proto.Message): If [LocationFilter.distance_in_miles][google.cloud.talent.v4beta1.LocationFilter.distance_in_miles] is negative, an error is thrown. - job_title_filters (Sequence[~.filters.JobTitleFilter]): + job_title_filters (Sequence[google.cloud.talent_v4beta1.types.JobTitleFilter]): Job title filter specifies job titles of profiles to match on. @@ -396,7 +396,7 @@ class ProfileQuery(proto.Message): For example, search for profiles with a job title "Product Manager". - employer_filters (Sequence[~.filters.EmployerFilter]): + employer_filters (Sequence[google.cloud.talent_v4beta1.types.EmployerFilter]): Employer filter specifies employers of profiles to match on. If an employer filter isn't specified, profiles with any @@ -412,7 +412,7 @@ class ProfileQuery(proto.Message): For example, search for profiles that have working experience at "Google LLC". - education_filters (Sequence[~.filters.EducationFilter]): + education_filters (Sequence[google.cloud.talent_v4beta1.types.EducationFilter]): Education filter specifies education of profiles to match on. @@ -428,7 +428,7 @@ class ProfileQuery(proto.Message): the educations. For example, search for profiles with a master degree. - skill_filters (Sequence[~.filters.SkillFilter]): + skill_filters (Sequence[google.cloud.talent_v4beta1.types.SkillFilter]): Skill filter specifies skill of profiles to match on. If a skill filter isn't specified, profiles with any skills @@ -444,7 +444,7 @@ class ProfileQuery(proto.Message): For example, search for profiles that have "Java" and "Python" in skill list. - work_experience_filter (Sequence[~.filters.WorkExperienceFilter]): + work_experience_filter (Sequence[google.cloud.talent_v4beta1.types.WorkExperienceFilter]): Work experience filter specifies the total working experience of profiles to match on. @@ -458,23 +458,23 @@ class ProfileQuery(proto.Message): For example, search for profiles with 10 years of work experience. - time_filters (Sequence[~.filters.TimeFilter]): + time_filters (Sequence[google.cloud.talent_v4beta1.types.TimeFilter]): Time filter specifies the create/update timestamp of the profiles to match on. For example, search for profiles created since "2018-1-1". - hirable_filter (~.wrappers.BoolValue): + hirable_filter (google.protobuf.wrappers_pb2.BoolValue): The hirable filter specifies the profile's hirable status to match on. - application_date_filters (Sequence[~.filters.ApplicationDateFilter]): + application_date_filters (Sequence[google.cloud.talent_v4beta1.types.ApplicationDateFilter]): The application date filters specify application date ranges to match on. - application_outcome_notes_filters (Sequence[~.filters.ApplicationOutcomeNotesFilter]): + application_outcome_notes_filters (Sequence[google.cloud.talent_v4beta1.types.ApplicationOutcomeNotesFilter]): The application outcome notes filters specify the notes for the outcome of the job application. - application_job_filters (Sequence[~.filters.ApplicationJobFilter]): + application_job_filters (Sequence[google.cloud.talent_v4beta1.types.ApplicationJobFilter]): The application job filters specify the job applied for in the application. custom_attribute_filter (str): @@ -507,7 +507,7 @@ class ProfileQuery(proto.Message): Sample Query: (key1 = "TEST" OR LOWER(key1)="test" OR NOT EMPTY(key1)) - candidate_availability_filter (~.filters.CandidateAvailabilityFilter): + candidate_availability_filter (google.cloud.talent_v4beta1.types.CandidateAvailabilityFilter): Deprecated. Use availability_filters instead. The candidate availability filter which filters based on @@ -528,7 +528,7 @@ class ProfileQuery(proto.Message): signals. Specifically, the intent is NOT to indicate the candidate's potential qualification / interest / close ability for a specific job. - availability_filters (Sequence[~.filters.AvailabilityFilter]): + availability_filters (Sequence[google.cloud.talent_v4beta1.types.AvailabilityFilter]): The availability filter which filters based on [Profile.availability_signals][google.cloud.talent.v4beta1.Profile.availability_signals]. @@ -548,7 +548,7 @@ class ProfileQuery(proto.Message): for a [signal_type][google.cloud.talent.v4beta1.AvailabilityFilter.signal_type], an error is thrown. - person_name_filters (Sequence[~.filters.PersonNameFilter]): + person_name_filters (Sequence[google.cloud.talent_v4beta1.types.PersonNameFilter]): Person name filter specifies person name of profiles to match on. If multiple person name filters are specified, @@ -635,7 +635,7 @@ class LocationFilter(proto.Message): https://www.unicode.org/cldr/charts/30/supplemental/territory_information.html for details. Example: "CH" for Switzerland. Note that this filter is not applicable for Profile Search related queries. - lat_lng (~.latlng.LatLng): + lat_lng (google.type.latlng_pb2.LatLng): The latitude and longitude of the geographic center to search from. This field is ignored if ``address`` is provided. @@ -644,7 +644,7 @@ class LocationFilter(proto.Message): searched for is identified as a city or smaller. This field is ignored if the location being searched for is a state or larger. - telecommute_preference (~.filters.LocationFilter.TelecommutePreference): + telecommute_preference (google.cloud.talent_v4beta1.types.LocationFilter.TelecommutePreference): Allows the client to return jobs without a set location, specifically, telecommuting jobs (telecommuting is considered by the service as a special location. @@ -701,12 +701,12 @@ class CompensationFilter(proto.Message): r"""Filter on job compensation type and amount. Attributes: - type_ (~.filters.CompensationFilter.FilterType): + type_ (google.cloud.talent_v4beta1.types.CompensationFilter.FilterType): Required. Type of filter. - units (Sequence[~.common.CompensationInfo.CompensationUnit]): + units (Sequence[google.cloud.talent_v4beta1.types.CompensationInfo.CompensationUnit]): Required. Specify desired ``base compensation entry's`` [CompensationInfo.CompensationUnit][google.cloud.talent.v4beta1.CompensationInfo.CompensationUnit]. - range_ (~.common.CompensationInfo.CompensationRange): + range_ (google.cloud.talent_v4beta1.types.CompensationInfo.CompensationRange): Compensation range. include_jobs_with_unspecified_compensation_range (bool): If set to true, jobs with unspecified @@ -738,13 +738,13 @@ class CommuteFilter(proto.Message): r"""Parameters needed for commute search. Attributes: - commute_method (~.common.CommuteMethod): + commute_method (google.cloud.talent_v4beta1.types.CommuteMethod): Required. The method of transportation to calculate the commute time for. - start_coordinates (~.latlng.LatLng): + start_coordinates (google.type.latlng_pb2.LatLng): Required. The latitude and longitude of the location to calculate the commute time from. - travel_duration (~.duration.Duration): + travel_duration (google.protobuf.duration_pb2.Duration): Required. The maximum travel time in seconds. The maximum allowed value is ``3600s`` (one hour). Format is ``123s``. allow_imprecise_addresses (bool): @@ -754,10 +754,10 @@ class CommuteFilter(proto.Message): used. If this field is set to ``false`` or isn't specified, only jobs that include street level addresses will be returned by commute search. - road_traffic (~.filters.CommuteFilter.RoadTraffic): + road_traffic (google.cloud.talent_v4beta1.types.CommuteFilter.RoadTraffic): Specifies the traffic density to use when calculating commute time. - departure_time (~.timeofday.TimeOfDay): + departure_time (google.type.timeofday_pb2.TimeOfDay): The departure time used to calculate traffic impact, represented as [google.type.TimeOfDay][google.type.TimeOfDay] in local time @@ -831,7 +831,7 @@ class EmployerFilter(proto.Message): employer (str): Required. The name of the employer, for example "Google", "Alphabet". - mode (~.filters.EmployerFilter.EmployerFilterMode): + mode (google.cloud.talent_v4beta1.types.EmployerFilter.EmployerFilterMode): Define set of [EmploymentRecord][google.cloud.talent.v4beta1.EmploymentRecord]s to search against. @@ -872,7 +872,7 @@ class EducationFilter(proto.Message): in [Degree.fields_of_study][google.cloud.talent.v4beta1.Degree.fields_of_study]. For example "Computer Science", "Mathematics". - degree_type (~.common.DegreeType): + degree_type (google.cloud.talent_v4beta1.types.DegreeType): Education degree in ISCED code. Each value in degree covers a specific level of education, without any expansion to upper nor lower levels @@ -901,10 +901,10 @@ class WorkExperienceFilter(proto.Message): [max_experience][google.cloud.talent.v4beta1.WorkExperienceFilter.max_experience]. Attributes: - min_experience (~.duration.Duration): + min_experience (google.protobuf.duration_pb2.Duration): The minimum duration of the work experience (inclusive). - max_experience (~.duration.Duration): + max_experience (google.protobuf.duration_pb2.Duration): The maximum duration of the work experience (exclusive). """ @@ -927,11 +927,11 @@ class ApplicationDateFilter(proto.Message): are missing. Attributes: - start_date (~.date.Date): + start_date (google.type.date_pb2.Date): Start date. If it's missing, The API matches profiles with application date not after the end date. - end_date (~.date.Date): + end_date (google.type.date_pb2.Date): End date. If it's missing, The API matches profiles with application date not before the start date. @@ -996,17 +996,17 @@ class TimeFilter(proto.Message): r"""Filter on create timestamp or update timestamp of profiles. Attributes: - start_time (~.timestamp.Timestamp): + start_time (google.protobuf.timestamp_pb2.Timestamp): Start timestamp, matching profiles with the start time. If this field missing, The API matches profiles with create / update timestamp before the end timestamp. - end_time (~.timestamp.Timestamp): + end_time (google.protobuf.timestamp_pb2.Timestamp): End timestamp, matching profiles with the end time. If this field missing, The API matches profiles with create / update timestamp after the start timestamp. - time_field (~.filters.TimeFilter.TimeField): + time_field (google.cloud.talent_v4beta1.types.TimeFilter.TimeField): Specifies which time field to filter profiles. Defaults to @@ -1043,9 +1043,9 @@ class AvailabilityFilter(proto.Message): r"""Filter on availability signals. Attributes: - signal_type (~.common.AvailabilitySignalType): + signal_type (google.cloud.talent_v4beta1.types.AvailabilitySignalType): Required. Type of signal to apply filter on. - range_ (~.common.TimestampRange): + range_ (google.cloud.talent_v4beta1.types.TimestampRange): Required. Range of times to filter candidate signals by. required (bool): diff --git a/google/cloud/talent_v4beta1/types/histogram.py b/google/cloud/talent_v4beta1/types/histogram.py index 6c72e53e..b809ac0b 100644 --- a/google/cloud/talent_v4beta1/types/histogram.py +++ b/google/cloud/talent_v4beta1/types/histogram.py @@ -50,7 +50,7 @@ class HistogramQueryResult(proto.Message): Attributes: histogram_query (str): Requested histogram expression. - histogram (Sequence[~.gct_histogram.HistogramQueryResult.HistogramEntry]): + histogram (Sequence[google.cloud.talent_v4beta1.types.HistogramQueryResult.HistogramEntry]): A map from the values of the facet associated with distinct values to the number of matching entries with corresponding value. diff --git a/google/cloud/talent_v4beta1/types/job.py b/google/cloud/talent_v4beta1/types/job.py index 147fbe55..a378bbd5 100644 --- a/google/cloud/talent_v4beta1/types/job.py +++ b/google/cloud/talent_v4beta1/types/job.py @@ -117,15 +117,15 @@ class Job(proto.Message): experience. The maximum number of allowed characters is 500. - application_info (~.job.Job.ApplicationInfo): + application_info (google.cloud.talent_v4beta1.types.Job.ApplicationInfo): Job application information. - job_benefits (Sequence[~.common.JobBenefit]): + job_benefits (Sequence[google.cloud.talent_v4beta1.types.JobBenefit]): The benefits included with the job. - compensation_info (~.common.CompensationInfo): + compensation_info (google.cloud.talent_v4beta1.types.CompensationInfo): Job compensation information (a.k.a. "pay rate") i.e., the compensation that will paid to the employee. - custom_attributes (Sequence[~.job.Job.CustomAttributesEntry]): + custom_attributes (Sequence[google.cloud.talent_v4beta1.types.Job.CustomAttributesEntry]): A map of fields to hold both filterable and non-filterable custom job attributes that are not covered by the provided structured fields. @@ -140,7 +140,7 @@ class Job(proto.Message): than 255 characters. For unfilterable ``string_values``, the maximum total size of ``string_values`` across all keys is 50KB. - degree_types (Sequence[~.common.DegreeType]): + degree_types (Sequence[google.cloud.talent_v4beta1.types.DegreeType]): The desired education degrees for the job, such as Bachelors, Masters. department (str): @@ -148,7 +148,7 @@ class Job(proto.Message): company with the open position. The maximum number of allowed characters is 255. - employment_types (Sequence[~.common.EmploymentType]): + employment_types (Sequence[google.cloud.talent_v4beta1.types.EmploymentType]): The employment type(s) of a job, for example, [full time][google.cloud.talent.v4beta1.EmploymentType.FULL_TIME] or [part @@ -173,7 +173,7 @@ class Job(proto.Message): is present, detected language code based on [Job.description][google.cloud.talent.v4beta1.Job.description] is assigned, otherwise defaults to 'en_US'. - job_level (~.common.JobLevel): + job_level (google.cloud.talent_v4beta1.types.JobLevel): The experience level associated with the job, such as "Entry Level". promotion_value (int): @@ -208,7 +208,7 @@ class Job(proto.Message): markup tags. The maximum number of allowed characters is 10,000. - posting_region (~.common.PostingRegion): + posting_region (google.cloud.talent_v4beta1.types.PostingRegion): The job [PostingRegion][google.cloud.talent.v4beta1.PostingRegion] (for example, state, country) throughout which the job is @@ -224,7 +224,7 @@ class Job(proto.Message): [Job.addresses][google.cloud.talent.v4beta1.Job.addresses] to the same location level as this field is strongly recommended. - visibility (~.common.Visibility): + visibility (google.cloud.talent_v4beta1.types.Visibility): Deprecated. The job is only visible to the owner. The visibility of the job. @@ -232,21 +232,21 @@ class Job(proto.Message): Defaults to [Visibility.ACCOUNT_ONLY][google.cloud.talent.v4beta1.Visibility.ACCOUNT_ONLY] if not specified. - job_start_time (~.timestamp.Timestamp): + job_start_time (google.protobuf.timestamp_pb2.Timestamp): The start timestamp of the job in UTC time zone. Typically this field is used for contracting engagements. Invalid timestamps are ignored. - job_end_time (~.timestamp.Timestamp): + job_end_time (google.protobuf.timestamp_pb2.Timestamp): The end timestamp of the job. Typically this field is used for contracting engagements. Invalid timestamps are ignored. - posting_publish_time (~.timestamp.Timestamp): + posting_publish_time (google.protobuf.timestamp_pb2.Timestamp): The timestamp this job posting was most recently published. The default value is the time the request arrives at the server. Invalid timestamps are ignored. - posting_expire_time (~.timestamp.Timestamp): + posting_expire_time (google.protobuf.timestamp_pb2.Timestamp): Strongly recommended for the best service experience. The expiration timestamp of the job. After this timestamp, @@ -304,19 +304,19 @@ class Job(proto.Message): or the masks are empty meaning that every field is updated, the job posting expires after 30 days from the job's last update time. Otherwise the expiration date isn't updated. - posting_create_time (~.timestamp.Timestamp): + posting_create_time (google.protobuf.timestamp_pb2.Timestamp): Output only. The timestamp when this job posting was created. - posting_update_time (~.timestamp.Timestamp): + posting_update_time (google.protobuf.timestamp_pb2.Timestamp): Output only. The timestamp when this job posting was last updated. company_display_name (str): Output only. Display name of the company listing the job. - derived_info (~.job.Job.DerivedInfo): + derived_info (google.cloud.talent_v4beta1.types.Job.DerivedInfo): Output only. Derived details about the job posting. - processing_options (~.job.Job.ProcessingOptions): + processing_options (google.cloud.talent_v4beta1.types.Job.ProcessingOptions): Options for job processing. """ @@ -356,7 +356,7 @@ class DerivedInfo(proto.Message): r"""Derived details about the job posting. Attributes: - locations (Sequence[~.common.Location]): + locations (Sequence[google.cloud.talent_v4beta1.types.Location]): Structured locations of the job, resolved from [Job.addresses][google.cloud.talent.v4beta1.Job.addresses]. @@ -364,7 +364,7 @@ class DerivedInfo(proto.Message): are exactly matched to [Job.addresses][google.cloud.talent.v4beta1.Job.addresses] in the same order. - job_categories (Sequence[~.common.JobCategory]): + job_categories (Sequence[google.cloud.talent_v4beta1.types.JobCategory]): Job categories derived from [Job.title][google.cloud.talent.v4beta1.Job.title] and [Job.description][google.cloud.talent.v4beta1.Job.description]. @@ -385,7 +385,7 @@ class ProcessingOptions(proto.Message): disable_street_address_resolution (bool): If set to ``true``, the service does not attempt to resolve a more precise address for the job. - html_sanitization (~.common.HtmlSanitization): + html_sanitization (google.cloud.talent_v4beta1.types.HtmlSanitization): Option for job HTML content sanitization. Applied fields are: diff --git a/google/cloud/talent_v4beta1/types/job_service.py b/google/cloud/talent_v4beta1/types/job_service.py index 5cad2836..8ee4d6fa 100644 --- a/google/cloud/talent_v4beta1/types/job_service.py +++ b/google/cloud/talent_v4beta1/types/job_service.py @@ -73,7 +73,7 @@ class CreateJobRequest(proto.Message): For example, "projects/foo/tenant/bar". If tenant id is unspecified a default tenant is created. For example, "projects/foo". - job (~.gct_job.Job): + job (google.cloud.talent_v4beta1.types.Job): Required. The Job to be created. """ @@ -104,9 +104,9 @@ class UpdateJobRequest(proto.Message): r"""Update job request. Attributes: - job (~.gct_job.Job): + job (google.cloud.talent_v4beta1.types.Job): Required. The Job to be updated. - update_mask (~.field_mask.FieldMask): + update_mask (google.protobuf.field_mask_pb2.FieldMask): Strongly recommended for the best service experience. If @@ -221,7 +221,7 @@ class ListJobsRequest(proto.Message): maximum allowed page size is 100. Default is 100 if empty or a number < 1 is specified. - job_view (~.job_service.JobView): + job_view (google.cloud.talent_v4beta1.types.JobView): The desired job attributes returned for jobs in the search response. Defaults to [JobView.JOB_VIEW_FULL][google.cloud.talent.v4beta1.JobView.JOB_VIEW_FULL] @@ -243,13 +243,13 @@ class ListJobsResponse(proto.Message): r"""List jobs response. Attributes: - jobs (Sequence[~.gct_job.Job]): + jobs (Sequence[google.cloud.talent_v4beta1.types.Job]): The Jobs for a given company. The maximum number of items returned is based on the limit field provided in the request. next_page_token (str): A token to retrieve the next page of results. - metadata (~.common.ResponseMetadata): + metadata (google.cloud.talent_v4beta1.types.ResponseMetadata): Additional information for the API invocation, such as the request tracking id. """ @@ -276,17 +276,17 @@ class SearchJobsRequest(proto.Message): For example, "projects/foo/tenant/bar". If tenant id is unspecified, a default tenant is created. For example, "projects/foo". - search_mode (~.job_service.SearchJobsRequest.SearchMode): + search_mode (google.cloud.talent_v4beta1.types.SearchJobsRequest.SearchMode): Mode of a search. Defaults to [SearchMode.JOB_SEARCH][google.cloud.talent.v4beta1.SearchJobsRequest.SearchMode.JOB_SEARCH]. - request_metadata (~.common.RequestMetadata): + request_metadata (google.cloud.talent_v4beta1.types.RequestMetadata): Required. The meta information collected about the job searcher, used to improve the search quality of the service. The identifiers (such as ``user_id``) are provided by users, and must be unique and consistent. - job_query (~.filters.JobQuery): + job_query (google.cloud.talent_v4beta1.types.JobQuery): Query used to search against jobs, such as keyword, location filters, etc. enable_broadening (bool): @@ -307,7 +307,7 @@ class SearchJobsRequest(proto.Message): Enabling this flag may adversely impact performance. Defaults to false. - histogram_queries (Sequence[~.histogram.HistogramQuery]): + histogram_queries (Sequence[google.cloud.talent_v4beta1.types.HistogramQuery]): An expression specifies a histogram request against matching jobs. @@ -420,7 +420,7 @@ class SearchJobsRequest(proto.Message): - ``count(base_compensation, [bucket(1000, 10000), bucket(10000, 100000), bucket(100000, MAX)])`` - ``count(string_custom_attribute["some-string-custom-attribute"])`` - ``count(numeric_custom_attribute["some-numeric-custom-attribute"], [bucket(MIN, 0, "negative"), bucket(0, MAX, "non-negative"])`` - job_view (~.job_service.JobView): + job_view (google.cloud.talent_v4beta1.types.JobView): The desired job attributes returned for jobs in the search response. Defaults to [JobView.JOB_VIEW_SMALL][google.cloud.talent.v4beta1.JobView.JOB_VIEW_SMALL] @@ -512,7 +512,7 @@ class SearchJobsRequest(proto.Message): (37.4 feet). Diversification strategy is still applied unless explicitly disabled in [diversification_level][google.cloud.talent.v4beta1.SearchJobsRequest.diversification_level]. - diversification_level (~.job_service.SearchJobsRequest.DiversificationLevel): + diversification_level (google.cloud.talent_v4beta1.types.SearchJobsRequest.DiversificationLevel): Controls whether highly similar jobs are returned next to each other in the search results. Jobs are identified as highly similar based on their titles, job categories, and @@ -524,7 +524,7 @@ class SearchJobsRequest(proto.Message): Defaults to [DiversificationLevel.SIMPLE][google.cloud.talent.v4beta1.SearchJobsRequest.DiversificationLevel.SIMPLE] if no value is specified. - custom_ranking_info (~.job_service.SearchJobsRequest.CustomRankingInfo): + custom_ranking_info (google.cloud.talent_v4beta1.types.SearchJobsRequest.CustomRankingInfo): Controls over how job documents get ranked on top of existing relevance score (determined by API algorithm). @@ -582,7 +582,7 @@ class CustomRankingInfo(proto.Message): [SearchJobsRequest][google.cloud.talent.v4beta1.SearchJobsRequest]. Attributes: - importance_level (~.job_service.SearchJobsRequest.CustomRankingInfo.ImportanceLevel): + importance_level (google.cloud.talent_v4beta1.types.SearchJobsRequest.CustomRankingInfo.ImportanceLevel): Required. Controls over how important the score of [CustomRankingInfo.ranking_expression][google.cloud.talent.v4beta1.SearchJobsRequest.CustomRankingInfo.ranking_expression] gets applied to job's final ranking position. @@ -679,17 +679,17 @@ class SearchJobsResponse(proto.Message): r"""Response for SearchJob method. Attributes: - matching_jobs (Sequence[~.job_service.SearchJobsResponse.MatchingJob]): + matching_jobs (Sequence[google.cloud.talent_v4beta1.types.SearchJobsResponse.MatchingJob]): The Job entities that match the specified [SearchJobsRequest][google.cloud.talent.v4beta1.SearchJobsRequest]. - histogram_query_results (Sequence[~.histogram.HistogramQueryResult]): + histogram_query_results (Sequence[google.cloud.talent_v4beta1.types.HistogramQueryResult]): The histogram results that match with specified [SearchJobsRequest.histogram_queries][google.cloud.talent.v4beta1.SearchJobsRequest.histogram_queries]. next_page_token (str): The token that specifies the starting position of the next page of results. This field is empty if there are no more results. - location_filters (Sequence[~.common.Location]): + location_filters (Sequence[google.cloud.talent_v4beta1.types.Location]): The location filters that the service applied to the specified query. If any filters are lat-lng based, the [Location.location_type][google.cloud.talent.v4beta1.Location.location_type] @@ -708,7 +708,7 @@ class SearchJobsResponse(proto.Message): [SearchJobsRequest.require_precise_result_size][google.cloud.talent.v4beta1.SearchJobsRequest.require_precise_result_size] to ``true``, or if the response is the last page of results. Otherwise, the value is ``-1``. - metadata (~.common.ResponseMetadata): + metadata (google.cloud.talent_v4beta1.types.ResponseMetadata): Additional information for the API invocation, such as the request tracking id. broadened_query_jobs_count (int): @@ -723,7 +723,7 @@ class SearchJobsResponse(proto.Message): broadening) query. If this field is non-zero, subsequent requests with offset after this result set should contain all broadened results. - spell_correction (~.common.SpellingCorrection): + spell_correction (google.cloud.talent_v4beta1.types.SpellingCorrection): The spell checking result, and correction. """ @@ -732,7 +732,7 @@ class MatchingJob(proto.Message): [SearchJobsResponse][google.cloud.talent.v4beta1.SearchJobsResponse]. Attributes: - job (~.gct_job.Job): + job (google.cloud.talent_v4beta1.types.Job): Job resource that matches the specified [SearchJobsRequest][google.cloud.talent.v4beta1.SearchJobsRequest]. job_summary (str): @@ -752,7 +752,7 @@ class MatchingJob(proto.Message): keywords, if available. All HTML tags in the original fields are stripped when returned in this field, and matching query keywords are enclosed in HTML bold tags. - commute_info (~.job_service.SearchJobsResponse.CommuteInfo): + commute_info (google.cloud.talent_v4beta1.types.SearchJobsResponse.CommuteInfo): Commute information which is generated based on specified [CommuteFilter][google.cloud.talent.v4beta1.CommuteFilter]. """ @@ -773,10 +773,10 @@ class CommuteInfo(proto.Message): r"""Commute details related to this job. Attributes: - job_location (~.common.Location): + job_location (google.cloud.talent_v4beta1.types.Location): Location used as the destination in the commute calculation. - travel_duration (~.duration.Duration): + travel_duration (google.protobuf.duration_pb2.Duration): The number of seconds required to travel to the job location from the query location. A duration of 0 seconds indicates that the job @@ -831,7 +831,7 @@ class BatchCreateJobsRequest(proto.Message): For example, "projects/foo/tenant/bar". If tenant id is unspecified, a default tenant is created. For example, "projects/foo". - jobs (Sequence[~.gct_job.Job]): + jobs (Sequence[google.cloud.talent_v4beta1.types.Job]): Required. The jobs to be created. """ @@ -852,9 +852,9 @@ class BatchUpdateJobsRequest(proto.Message): For example, "projects/foo/tenant/bar". If tenant id is unspecified, a default tenant is created. For example, "projects/foo". - jobs (Sequence[~.gct_job.Job]): + jobs (Sequence[google.cloud.talent_v4beta1.types.Job]): Required. The jobs to be updated. - update_mask (~.field_mask.FieldMask): + update_mask (google.protobuf.field_mask_pb2.FieldMask): Strongly recommended for the best service experience. Be aware that it will also increase latency when checking the status of a batch operation. @@ -897,7 +897,7 @@ class JobOperationResult(proto.Message): in case of success. Attributes: - job_results (Sequence[~.job_service.JobOperationResult.JobResult]): + job_results (Sequence[google.cloud.talent_v4beta1.types.JobOperationResult.JobResult]): List of job mutation results from a batch mutate operation. It can change until operation status is FINISHED, FAILED or CANCELLED. @@ -907,7 +907,7 @@ class JobResult(proto.Message): r"""Mutation result of a job. Attributes: - job (~.gct_job.Job): + job (google.cloud.talent_v4beta1.types.Job): Here [Job][google.cloud.talent.v4beta1.Job] only contains basic information including [name][google.cloud.talent.v4beta1.Job.name], @@ -917,7 +917,7 @@ class JobResult(proto.Message): [requisition_id][google.cloud.talent.v4beta1.Job.requisition_id], use getJob method to retrieve detailed information of the created/updated job. - status (~.gr_status.Status): + status (google.rpc.status_pb2.Status): The status of the job processed. This field is populated if the processing of the [job][google.cloud.talent.v4beta1.JobOperationResult.JobResult.job] diff --git a/google/cloud/talent_v4beta1/types/profile.py b/google/cloud/talent_v4beta1/types/profile.py index 38428498..33c9a31f 100644 --- a/google/cloud/talent_v4beta1/types/profile.py +++ b/google/cloud/talent_v4beta1/types/profile.py @@ -95,16 +95,16 @@ class Profile(proto.Message): [group_id][google.cloud.talent.v4beta1.Profile.group_id], and assign it when the second profile is created, indicating these two profiles are referring to the same candidate. - is_hirable (~.wrappers.BoolValue): + is_hirable (google.protobuf.wrappers_pb2.BoolValue): Indicates the hirable status of the candidate. - create_time (~.timestamp.Timestamp): + create_time (google.protobuf.timestamp_pb2.Timestamp): The timestamp when the profile was first created at this source. - update_time (~.timestamp.Timestamp): + update_time (google.protobuf.timestamp_pb2.Timestamp): The timestamp when the profile was last updated at this source. - candidate_update_time (~.timestamp.Timestamp): + candidate_update_time (google.protobuf.timestamp_pb2.Timestamp): The timestamp when the profile was last updated as a result of a direct or indirect action by a candidate. @@ -130,7 +130,7 @@ class Profile(proto.Message): must be greater than or equal to [resume_update_time][google.cloud.talent.v4beta1.Profile.resume_update_time] or an error is thrown. - resume_update_time (~.timestamp.Timestamp): + resume_update_time (google.protobuf.timestamp_pb2.Timestamp): The timestamp when the candidate's resume was added or updated on the candidate's profile. Whether that resume was directly uploaded by a candidate, pulled from a 3rd party @@ -139,13 +139,13 @@ class Profile(proto.Message): If this field is updated, it's expected that [resume][google.cloud.talent.v4beta1.Profile.resume] is provided in the create or update calls. - resume (~.profile.Resume): + resume (google.cloud.talent_v4beta1.types.Resume): The resume representing this profile. - person_names (Sequence[~.profile.PersonName]): + person_names (Sequence[google.cloud.talent_v4beta1.types.PersonName]): The names of the candidate this profile references. Currently only one person name is supported. - addresses (Sequence[~.profile.Address]): + addresses (Sequence[google.cloud.talent_v4beta1.types.Address]): The candidate's postal addresses. It's highly recommended to input this information as accurately as possible to help improve search quality. Here are some recommendations: @@ -183,13 +183,13 @@ class Profile(proto.Message): is CONTACT_INFO_USAGE_UNSPECIFIED and [Address.current][google.cloud.talent.v4beta1.Address.current] is false or not set. - email_addresses (Sequence[~.profile.Email]): + email_addresses (Sequence[google.cloud.talent_v4beta1.types.Email]): The candidate's email addresses. - phone_numbers (Sequence[~.profile.Phone]): + phone_numbers (Sequence[google.cloud.talent_v4beta1.types.Phone]): The candidate's phone number(s). - personal_uris (Sequence[~.profile.PersonalUri]): + personal_uris (Sequence[google.cloud.talent_v4beta1.types.PersonalUri]): The candidate's personal URIs. - additional_contact_info (Sequence[~.profile.AdditionalContactInfo]): + additional_contact_info (Sequence[google.cloud.talent_v4beta1.types.AdditionalContactInfo]): Available contact information besides [addresses][google.cloud.talent.v4beta1.Profile.addresses], [email_addresses][google.cloud.talent.v4beta1.Profile.email_addresses], @@ -197,7 +197,7 @@ class Profile(proto.Message): and [personal_uris][google.cloud.talent.v4beta1.Profile.personal_uris]. For example, Hang-out, Skype. - employment_records (Sequence[~.profile.EmploymentRecord]): + employment_records (Sequence[google.cloud.talent_v4beta1.types.EmploymentRecord]): The employment history records of the candidate. It's highly recommended to input this information as accurately as possible to help improve search quality. Here are some @@ -215,7 +215,7 @@ class Profile(proto.Message): inferred from user inputs. The limitation for max number of employment records is 100. - education_records (Sequence[~.profile.EducationRecord]): + education_records (Sequence[google.cloud.talent_v4beta1.types.EducationRecord]): The education history record of the candidate. It's highly recommended to input this information as accurately as possible to help improve search quality. Here are some @@ -232,25 +232,25 @@ class Profile(proto.Message): inferred from user inputs. The limitation for max number of education records is 100. - skills (Sequence[~.common.Skill]): + skills (Sequence[google.cloud.talent_v4beta1.types.Skill]): The skill set of the candidate. It's highly recommended to provide as much information as possible to help improve the search quality. The limitation for max number of skills is 500. - activities (Sequence[~.profile.Activity]): + activities (Sequence[google.cloud.talent_v4beta1.types.Activity]): The individual or collaborative activities which the candidate has participated in, for example, open-source projects, class assignments that aren't listed in [employment_records][google.cloud.talent.v4beta1.Profile.employment_records]. The limitation for max number of activities is 50. - publications (Sequence[~.profile.Publication]): + publications (Sequence[google.cloud.talent_v4beta1.types.Publication]): The publications published by the candidate. The limitation for max number of publications is 50. - patents (Sequence[~.profile.Patent]): + patents (Sequence[google.cloud.talent_v4beta1.types.Patent]): The patents acquired by the candidate. - certifications (Sequence[~.common.Certification]): + certifications (Sequence[google.cloud.talent_v4beta1.types.Certification]): The certifications acquired by the candidate. applications (Sequence[str]): Output only. The resource names of the @@ -258,7 +258,7 @@ class Profile(proto.Message): assignments (Sequence[str]): Output only. The resource names of the candidate's assignments. - custom_attributes (Sequence[~.profile.Profile.CustomAttributesEntry]): + custom_attributes (Sequence[google.cloud.talent_v4beta1.types.Profile.CustomAttributesEntry]): A map of fields to hold both filterable and non-filterable custom profile attributes that aren't covered by the provided structured fields. See @@ -290,10 +290,10 @@ class Profile(proto.Message): Output only. Keyword snippet shows how the search result is related to a search query. This is only returned in [SearchProfilesResponse][google.cloud.talent.v4beta1.SearchProfilesResponse]. - availability_signals (Sequence[~.profile.AvailabilitySignal]): + availability_signals (Sequence[google.cloud.talent_v4beta1.types.AvailabilitySignal]): Output only. Candidate's availability signals. - derived_addresses (Sequence[~.common.Location]): + derived_addresses (Sequence[google.cloud.talent_v4beta1.types.Location]): Output only. Derived locations of the profile, resolved from [Profile.addresses][google.cloud.talent.v4beta1.Profile.addresses]. @@ -390,12 +390,12 @@ class AvailabilitySignal(proto.Message): r"""Candidate availability signal. Attributes: - type_ (~.common.AvailabilitySignalType): + type_ (google.cloud.talent_v4beta1.types.AvailabilitySignalType): Type of signal. - last_update_time (~.timestamp.Timestamp): + last_update_time (google.protobuf.timestamp_pb2.Timestamp): Timestamp of when the given availability activity last happened. - filter_satisfied (~.wrappers.BoolValue): + filter_satisfied (google.protobuf.wrappers_pb2.BoolValue): Indicates if the [last_update_time][google.cloud.talent.v4beta1.AvailabilitySignal.last_update_time] is within @@ -439,7 +439,7 @@ class Resume(proto.Message): Note that the use of the functionality offered by this field to extract data from resumes is an Alpha feature and as such is not covered by any SLA. - resume_type (~.profile.Resume.ResumeType): + resume_type (google.cloud.talent_v4beta1.types.Resume.ResumeType): The format of [structured_resume][google.cloud.talent.v4beta1.Resume.structured_resume]. """ @@ -463,7 +463,7 @@ class PersonName(proto.Message): A string represents a person's full name. For example, "Dr. John Smith". Number of characters allowed is 100. - structured_name (~.profile.PersonName.PersonStructuredName): + structured_name (google.cloud.talent_v4beta1.types.PersonName.PersonStructuredName): A person's name in a structured way (last name, first name, suffix, and so on.) preferred_name (str): @@ -538,7 +538,7 @@ class Address(proto.Message): r"""Resource that represents a address. Attributes: - usage (~.common.ContactInfoUsage): + usage (google.cloud.talent_v4beta1.types.ContactInfoUsage): The usage of the address. For example, SCHOOL, WORK, PERSONAL. unstructured_address (str): @@ -547,10 +547,10 @@ class Address(proto.Message): View, CA 94043", "Sunnyvale, California". Number of characters allowed is 100. - structured_address (~.postal_address.PostalAddress): + structured_address (google.type.postal_address_pb2.PostalAddress): Structured address that contains street address, city, state, country, and so on. - current (~.wrappers.BoolValue): + current (google.protobuf.wrappers_pb2.BoolValue): Indicates if it's the person's current address. """ @@ -570,7 +570,7 @@ class Email(proto.Message): r"""Resource that represents a person's email address. Attributes: - usage (~.common.ContactInfoUsage): + usage (google.cloud.talent_v4beta1.types.ContactInfoUsage): The usage of the email address. For example, SCHOOL, WORK, PERSONAL. email_address (str): @@ -587,10 +587,10 @@ class Phone(proto.Message): r"""Resource that represents a person's telephone number. Attributes: - usage (~.common.ContactInfoUsage): + usage (google.cloud.talent_v4beta1.types.ContactInfoUsage): The usage of the phone. For example, SCHOOL, WORK, PERSONAL. - type_ (~.profile.Phone.PhoneType): + type_ (google.cloud.talent_v4beta1.types.Phone.PhoneType): The phone type. For example, LANDLINE, MOBILE, FAX. number (str): @@ -647,7 +647,7 @@ class AdditionalContactInfo(proto.Message): phone, email, URI and addresses. Attributes: - usage (~.common.ContactInfoUsage): + usage (google.cloud.talent_v4beta1.types.ContactInfoUsage): The usage of this contact method. For example, SCHOOL, WORK, PERSONAL. name (str): @@ -671,9 +671,9 @@ class EmploymentRecord(proto.Message): r"""Resource that represents an employment record of a candidate. Attributes: - start_date (~.date.Date): + start_date (google.type.date_pb2.Date): Start date of the employment. - end_date (~.date.Date): + end_date (google.type.date_pb2.Date): End date of the employment. employer_name (str): The name of the employer @@ -685,7 +685,7 @@ class EmploymentRecord(proto.Message): For example, division, department, client, and so on. Number of characters allowed is 100. - address (~.profile.Address): + address (google.cloud.talent_v4beta1.types.Address): The physical address of the employer. job_title (str): The job title of the employment. @@ -695,11 +695,11 @@ class EmploymentRecord(proto.Message): job_description (str): The description of job content. Number of characters allowed is 100,000. - is_supervisor (~.wrappers.BoolValue): + is_supervisor (google.protobuf.wrappers_pb2.BoolValue): If the jobs is a supervisor position. - is_self_employed (~.wrappers.BoolValue): + is_self_employed (google.protobuf.wrappers_pb2.BoolValue): If this employment is self-employed. - is_current (~.wrappers.BoolValue): + is_current (google.protobuf.wrappers_pb2.BoolValue): If this employment is current. job_title_snippet (str): Output only. The job title snippet shows how the @@ -752,11 +752,11 @@ class EducationRecord(proto.Message): r"""Resource that represents an education record of a candidate. Attributes: - start_date (~.date.Date): + start_date (google.type.date_pb2.Date): The start date of the education. - end_date (~.date.Date): + end_date (google.type.date_pb2.Date): The end date of the education. - expected_graduation_date (~.date.Date): + expected_graduation_date (google.type.date_pb2.Date): The expected graduation date if currently pursuing a degree. school_name (str): @@ -764,7 +764,7 @@ class EducationRecord(proto.Message): For example, "Stanford University", "UC Berkeley", and so on. Number of characters allowed is 250. - address (~.profile.Address): + address (google.cloud.talent_v4beta1.types.Address): The physical address of the education institution. degree_description (str): @@ -772,12 +772,12 @@ class EducationRecord(proto.Message): For example, "Master of Science in Computer Science", "B.S in Math". Number of characters allowed is 100. - structured_degree (~.profile.Degree): + structured_degree (google.cloud.talent_v4beta1.types.Degree): The structured notation of the degree. description (str): The description of the education. Number of characters allowed is 100,000. - is_current (~.wrappers.BoolValue): + is_current (google.protobuf.wrappers_pb2.BoolValue): If this education is current. school_name_snippet (str): Output only. The school name snippet shows how the @@ -824,7 +824,7 @@ class Degree(proto.Message): candidate. Attributes: - degree_type (~.common.DegreeType): + degree_type (google.cloud.talent_v4beta1.types.DegreeType): ISCED degree type. degree_name (str): Full Degree name. @@ -859,9 +859,9 @@ class Activity(proto.Message): uri (str): Activity URI. Number of characters allowed is 4,000. - create_date (~.date.Date): + create_date (google.type.date_pb2.Date): The first creation date of the activity. - update_date (~.date.Date): + update_date (google.type.date_pb2.Date): The last update date of the activity. team_members (Sequence[str]): A list of team members involved in this @@ -870,7 +870,7 @@ class Activity(proto.Message): The limitation for max number of team members is 50. - skills_used (Sequence[~.common.Skill]): + skills_used (Sequence[google.cloud.talent_v4beta1.types.Skill]): A list of skills used in this activity. The limitation for max number of skills used is 50. @@ -939,7 +939,7 @@ class Publication(proto.Message): publisher (str): The publisher of the journal. Number of characters allowed is 100. - publication_date (~.date.Date): + publication_date (google.type.date_pb2.Date): The publication date. publication_type (str): The publication type. @@ -981,10 +981,10 @@ class Patent(proto.Message): patent_status (str): The status of the patent. Number of characters allowed is 100. - patent_status_date (~.date.Date): + patent_status_date (google.type.date_pb2.Date): The date the last time the status of the patent was checked. - patent_filing_date (~.date.Date): + patent_filing_date (google.type.date_pb2.Date): The date that the patent was filed. patent_office (str): The name of the patent office. @@ -995,7 +995,7 @@ class Patent(proto.Message): patent_description (str): The description of the patent. Number of characters allowed is 100,000. - skills_used (Sequence[~.common.Skill]): + skills_used (Sequence[google.cloud.talent_v4beta1.types.Skill]): The skills used in this patent. """ diff --git a/google/cloud/talent_v4beta1/types/profile_service.py b/google/cloud/talent_v4beta1/types/profile_service.py index 1214e0ab..c64b7c3d 100644 --- a/google/cloud/talent_v4beta1/types/profile_service.py +++ b/google/cloud/talent_v4beta1/types/profile_service.py @@ -81,7 +81,7 @@ class ListProfilesRequest(proto.Message): returned, at most 100. Default is 100 unless a positive number smaller than 100 is specified. - read_mask (~.field_mask.FieldMask): + read_mask (google.protobuf.field_mask_pb2.FieldMask): A field mask to specify the profile fields to be listed in response. All fields are listed if it is unset. @@ -105,7 +105,7 @@ class ListProfilesResponse(proto.Message): r"""The List profiles response object. Attributes: - profiles (Sequence[~.gct_profile.Profile]): + profiles (Sequence[google.cloud.talent_v4beta1.types.Profile]): Profiles for the specific tenant. next_page_token (str): A token to retrieve the next page of results. @@ -132,7 +132,7 @@ class CreateProfileRequest(proto.Message): The format is "projects/{project_id}/tenants/{tenant_id}". For example, "projects/foo/tenants/bar". - profile (~.gct_profile.Profile): + profile (google.cloud.talent_v4beta1.types.Profile): Required. The profile to be created. """ @@ -160,9 +160,9 @@ class UpdateProfileRequest(proto.Message): r"""Update profile request Attributes: - profile (~.gct_profile.Profile): + profile (google.cloud.talent_v4beta1.types.Profile): Required. Profile to be updated. - update_mask (~.field_mask.FieldMask): + update_mask (google.protobuf.field_mask_pb2.FieldMask): A field mask to specify the profile fields to update. A full update is performed if it is unset. @@ -197,13 +197,13 @@ class SearchProfilesRequest(proto.Message): The format is "projects/{project_id}/tenants/{tenant_id}". For example, "projects/foo/tenants/bar". - request_metadata (~.common.RequestMetadata): + request_metadata (google.cloud.talent_v4beta1.types.RequestMetadata): Required. The meta information collected about the profile search user. This is used to improve the search quality of the service. These values are provided by users, and must be precise and consistent. - profile_query (~.filters.ProfileQuery): + profile_query (google.cloud.talent_v4beta1.types.ProfileQuery): Search query to execute. See [ProfileQuery][google.cloud.talent.v4beta1.ProfileQuery] for more details. @@ -273,7 +273,7 @@ class SearchProfilesRequest(proto.Message): order, sort values case sensitively (based on ASCII) when the value is set to true. Default value is case in-sensitive sort (false). - histogram_queries (Sequence[~.histogram.HistogramQuery]): + histogram_queries (Sequence[google.cloud.talent_v4beta1.types.HistogramQuery]): A list of expressions specifies histogram requests against matching profiles for [SearchProfilesRequest][google.cloud.talent.v4beta1.SearchProfilesRequest]. @@ -463,18 +463,18 @@ class SearchProfilesResponse(proto.Message): An estimation of the number of profiles that match the specified query. This number isn't guaranteed to be accurate. - spell_correction (~.common.SpellingCorrection): + spell_correction (google.cloud.talent_v4beta1.types.SpellingCorrection): The spell checking result, and correction. - metadata (~.common.ResponseMetadata): + metadata (google.cloud.talent_v4beta1.types.ResponseMetadata): Additional information for the API invocation, such as the request tracking id. next_page_token (str): A token to retrieve the next page of results. This is empty if there are no more results. - histogram_query_results (Sequence[~.histogram.HistogramQueryResult]): + histogram_query_results (Sequence[google.cloud.talent_v4beta1.types.HistogramQueryResult]): The histogram results that match with specified [SearchProfilesRequest.histogram_queries][google.cloud.talent.v4beta1.SearchProfilesRequest.histogram_queries]. - summarized_profiles (Sequence[~.profile_service.SummarizedProfile]): + summarized_profiles (Sequence[google.cloud.talent_v4beta1.types.SummarizedProfile]): The profile entities that match the specified [SearchProfilesRequest][google.cloud.talent.v4beta1.SearchProfilesRequest]. result_set_id (str): @@ -513,10 +513,10 @@ class SummarizedProfile(proto.Message): [SearchProfilesResponse][google.cloud.talent.v4beta1.SearchProfilesResponse]. Attributes: - profiles (Sequence[~.gct_profile.Profile]): + profiles (Sequence[google.cloud.talent_v4beta1.types.Profile]): A list of profiles that are linked by [Profile.group_id][google.cloud.talent.v4beta1.Profile.group_id]. - summary (~.gct_profile.Profile): + summary (google.cloud.talent_v4beta1.types.Profile): A profile summary shows the profile summary and how the profile matches the search query. diff --git a/google/cloud/talent_v4beta1/types/tenant.py b/google/cloud/talent_v4beta1/types/tenant.py index c7d1974d..c399eba2 100644 --- a/google/cloud/talent_v4beta1/types/tenant.py +++ b/google/cloud/talent_v4beta1/types/tenant.py @@ -43,7 +43,7 @@ class Tenant(proto.Message): Required. Client side tenant identifier, used to uniquely identify the tenant. The maximum number of allowed characters is 255. - usage_type (~.tenant.Tenant.DataUsageType): + usage_type (google.cloud.talent_v4beta1.types.Tenant.DataUsageType): Indicates whether data owned by this tenant may be used to provide product improvements across other tenants. diff --git a/google/cloud/talent_v4beta1/types/tenant_service.py b/google/cloud/talent_v4beta1/types/tenant_service.py index 505da6f7..104c43c7 100644 --- a/google/cloud/talent_v4beta1/types/tenant_service.py +++ b/google/cloud/talent_v4beta1/types/tenant_service.py @@ -46,7 +46,7 @@ class CreateTenantRequest(proto.Message): The format is "projects/{project_id}", for example, "projects/foo". - tenant (~.gct_tenant.Tenant): + tenant (google.cloud.talent_v4beta1.types.Tenant): Required. The tenant to be created. """ @@ -73,10 +73,10 @@ class UpdateTenantRequest(proto.Message): r"""Request for updating a specified tenant. Attributes: - tenant (~.gct_tenant.Tenant): + tenant (google.cloud.talent_v4beta1.types.Tenant): Required. The tenant resource to replace the current resource in the system. - update_mask (~.field_mask.FieldMask): + update_mask (google.protobuf.field_mask_pb2.FieldMask): Strongly recommended for the best service experience. If @@ -139,11 +139,11 @@ class ListTenantsResponse(proto.Message): r"""The List tenants response object. Attributes: - tenants (Sequence[~.gct_tenant.Tenant]): + tenants (Sequence[google.cloud.talent_v4beta1.types.Tenant]): Tenants for the current client. next_page_token (str): A token to retrieve the next page of results. - metadata (~.common.ResponseMetadata): + metadata (google.cloud.talent_v4beta1.types.ResponseMetadata): Additional information for the API invocation, such as the request tracking id. """ diff --git a/noxfile.py b/noxfile.py index 41eeb037..d2747a77 100644 --- a/noxfile.py +++ b/noxfile.py @@ -18,6 +18,7 @@ from __future__ import absolute_import import os +import pathlib import shutil import nox @@ -30,6 +31,22 @@ SYSTEM_TEST_PYTHON_VERSIONS = ["3.8"] UNIT_TEST_PYTHON_VERSIONS = ["3.6", "3.7", "3.8", "3.9"] +CURRENT_DIRECTORY = pathlib.Path(__file__).parent.absolute() + +# 'docfx' is excluded since it only needs to run in 'docs-presubmit' +nox.options.sessions = [ + "unit", + "system", + "cover", + "lint", + "lint_setup_py", + "blacken", + "docs", +] + +# Error if a python version is missing +nox.options.error_on_missing_interpreters = True + @nox.session(python=DEFAULT_PYTHON_VERSION) def lint(session): @@ -70,17 +87,21 @@ def lint_setup_py(session): def default(session): # Install all test dependencies, then install this package in-place. - session.install("asyncmock", "pytest-asyncio") - session.install( - "mock", "pytest", "pytest-cov", + constraints_path = str( + CURRENT_DIRECTORY / "testing" / f"constraints-{session.python}.txt" ) - session.install("-e", ".") + session.install("asyncmock", "pytest-asyncio", "-c", constraints_path) + + session.install("mock", "pytest", "pytest-cov", "-c", constraints_path) + + session.install("-e", ".", "-c", constraints_path) # Run py.test against the unit tests. session.run( "py.test", "--quiet", + f"--junitxml=unit_{session.python}_sponge_log.xml", "--cov=google/cloud", "--cov=tests/unit", "--cov-append", @@ -101,6 +122,9 @@ def unit(session): @nox.session(python=SYSTEM_TEST_PYTHON_VERSIONS) def system(session): """Run the system test suite.""" + constraints_path = str( + CURRENT_DIRECTORY / "testing" / f"constraints-{session.python}.txt" + ) system_test_path = os.path.join("tests", "system.py") system_test_folder_path = os.path.join("tests", "system") @@ -110,6 +134,9 @@ def system(session): # Sanity check: Only run tests if the environment variable is set. if not os.environ.get("GOOGLE_APPLICATION_CREDENTIALS", ""): session.skip("Credentials must be set via environment variable") + # Install pyopenssl for mTLS testing. + if os.environ.get("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false") == "true": + session.install("pyopenssl") system_test_exists = os.path.exists(system_test_path) system_test_folder_exists = os.path.exists(system_test_folder_path) @@ -122,16 +149,26 @@ def system(session): # Install all test dependencies, then install this package into the # virtualenv's dist-packages. - session.install( - "mock", "pytest", "google-cloud-testutils", - ) - session.install("-e", ".") + session.install("mock", "pytest", "google-cloud-testutils", "-c", constraints_path) + session.install("-e", ".", "-c", constraints_path) # Run py.test against the system tests. if system_test_exists: - session.run("py.test", "--quiet", system_test_path, *session.posargs) + session.run( + "py.test", + "--quiet", + f"--junitxml=system_{session.python}_sponge_log.xml", + system_test_path, + *session.posargs, + ) if system_test_folder_exists: - session.run("py.test", "--quiet", system_test_folder_path, *session.posargs) + session.run( + "py.test", + "--quiet", + f"--junitxml=system_{session.python}_sponge_log.xml", + system_test_folder_path, + *session.posargs, + ) @nox.session(python=DEFAULT_PYTHON_VERSION) @@ -142,7 +179,7 @@ def cover(session): test runs (not system test runs), and then erases coverage data. """ session.install("coverage", "pytest-cov") - session.run("coverage", "report", "--show-missing", "--fail-under=99") + session.run("coverage", "report", "--show-missing", "--fail-under=98") session.run("coverage", "erase") diff --git a/renovate.json b/renovate.json index 4fa94931..f08bc22c 100644 --- a/renovate.json +++ b/renovate.json @@ -1,5 +1,6 @@ { "extends": [ "config:base", ":preserveSemverRanges" - ] + ], + "ignorePaths": [".pre-commit-config.yaml"] } diff --git a/samples/snippets/noxfile.py b/samples/snippets/noxfile.py index bca0522e..97bf7da8 100644 --- a/samples/snippets/noxfile.py +++ b/samples/snippets/noxfile.py @@ -85,7 +85,7 @@ def get_pytest_env_vars() -> Dict[str, str]: # DO NOT EDIT - automatically generated. # All versions used to tested samples. -ALL_VERSIONS = ["2.7", "3.6", "3.7", "3.8"] +ALL_VERSIONS = ["2.7", "3.6", "3.7", "3.8", "3.9"] # Any default versions that should be ignored. IGNORED_VERSIONS = TEST_CONFIG['ignored_versions'] diff --git a/setup.py b/setup.py index 6cd77735..1dc00641 100644 --- a/setup.py +++ b/setup.py @@ -29,11 +29,10 @@ # 'Development Status :: 5 - Production/Stable' release_status = "Development Status :: 4 - Beta" dependencies = [ - "google-api-core[grpc] >= 1.22.0, < 2.0.0dev", - "proto-plus >= 1.4.0", - "libcst >= 0.2.5", + "google-api-core[grpc] >= 1.22.2, < 2.0.0dev", + "proto-plus >= 1.15.0", ] -extras = {} +extras = {"libcst": "libcst >= 0.2.5"} # Setup boilerplate below this line. diff --git a/synth.metadata b/synth.metadata index 83804676..7fbfc295 100644 --- a/synth.metadata +++ b/synth.metadata @@ -3,30 +3,30 @@ { "git": { "name": ".", - "remote": "https://github.com/googleapis/python-talent.git", - "sha": "8a53830a77532e25ff0794e9fb5400e4ec01d4f5" + "remote": "git@github.com:googleapis/python-talent", + "sha": "8a12124259ca87c5064fabe9f058ed966eea2d56" } }, { "git": { "name": "googleapis", "remote": "https://github.com/googleapis/googleapis.git", - "sha": "8a6f4d9acb1620af2156b42b37b54eae257b7cad", - "internalRef": "348696929" + "sha": "ef705a6d9fd6dcd8f0b13e012cb284332734785b", + "internalRef": "365856330" } }, { "git": { "name": "synthtool", "remote": "https://github.com/googleapis/synthtool.git", - "sha": "41a4e56982620d3edcf110d76f4fcdfdec471ac8" + "sha": "572ef8f70edd9041f5bcfa71511aed6aecfc2098" } }, { "git": { "name": "synthtool", "remote": "https://github.com/googleapis/synthtool.git", - "sha": "41a4e56982620d3edcf110d76f4fcdfdec471ac8" + "sha": "572ef8f70edd9041f5bcfa71511aed6aecfc2098" } } ], @@ -49,255 +49,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/talent_v4/services.rst", - "docs/talent_v4/types.rst", - "docs/talent_v4beta1/services.rst", - "docs/talent_v4beta1/types.rst", - "google/cloud/talent/__init__.py", - "google/cloud/talent/py.typed", - "google/cloud/talent_v4/__init__.py", - "google/cloud/talent_v4/proto/common.proto", - "google/cloud/talent_v4/proto/company.proto", - "google/cloud/talent_v4/proto/company_service.proto", - "google/cloud/talent_v4/proto/completion_service.proto", - "google/cloud/talent_v4/proto/event.proto", - "google/cloud/talent_v4/proto/event_service.proto", - "google/cloud/talent_v4/proto/filters.proto", - "google/cloud/talent_v4/proto/histogram.proto", - "google/cloud/talent_v4/proto/job.proto", - "google/cloud/talent_v4/proto/job_service.proto", - "google/cloud/talent_v4/proto/tenant.proto", - "google/cloud/talent_v4/proto/tenant_service.proto", - "google/cloud/talent_v4/py.typed", - "google/cloud/talent_v4/services/__init__.py", - "google/cloud/talent_v4/services/company_service/__init__.py", - "google/cloud/talent_v4/services/company_service/async_client.py", - "google/cloud/talent_v4/services/company_service/client.py", - "google/cloud/talent_v4/services/company_service/pagers.py", - "google/cloud/talent_v4/services/company_service/transports/__init__.py", - "google/cloud/talent_v4/services/company_service/transports/base.py", - "google/cloud/talent_v4/services/company_service/transports/grpc.py", - "google/cloud/talent_v4/services/company_service/transports/grpc_asyncio.py", - "google/cloud/talent_v4/services/completion/__init__.py", - "google/cloud/talent_v4/services/completion/async_client.py", - "google/cloud/talent_v4/services/completion/client.py", - "google/cloud/talent_v4/services/completion/transports/__init__.py", - "google/cloud/talent_v4/services/completion/transports/base.py", - "google/cloud/talent_v4/services/completion/transports/grpc.py", - "google/cloud/talent_v4/services/completion/transports/grpc_asyncio.py", - "google/cloud/talent_v4/services/event_service/__init__.py", - "google/cloud/talent_v4/services/event_service/async_client.py", - "google/cloud/talent_v4/services/event_service/client.py", - "google/cloud/talent_v4/services/event_service/transports/__init__.py", - "google/cloud/talent_v4/services/event_service/transports/base.py", - "google/cloud/talent_v4/services/event_service/transports/grpc.py", - "google/cloud/talent_v4/services/event_service/transports/grpc_asyncio.py", - "google/cloud/talent_v4/services/job_service/__init__.py", - "google/cloud/talent_v4/services/job_service/async_client.py", - "google/cloud/talent_v4/services/job_service/client.py", - "google/cloud/talent_v4/services/job_service/pagers.py", - "google/cloud/talent_v4/services/job_service/transports/__init__.py", - "google/cloud/talent_v4/services/job_service/transports/base.py", - "google/cloud/talent_v4/services/job_service/transports/grpc.py", - "google/cloud/talent_v4/services/job_service/transports/grpc_asyncio.py", - "google/cloud/talent_v4/services/tenant_service/__init__.py", - "google/cloud/talent_v4/services/tenant_service/async_client.py", - "google/cloud/talent_v4/services/tenant_service/client.py", - "google/cloud/talent_v4/services/tenant_service/pagers.py", - "google/cloud/talent_v4/services/tenant_service/transports/__init__.py", - "google/cloud/talent_v4/services/tenant_service/transports/base.py", - "google/cloud/talent_v4/services/tenant_service/transports/grpc.py", - "google/cloud/talent_v4/services/tenant_service/transports/grpc_asyncio.py", - "google/cloud/talent_v4/types/__init__.py", - "google/cloud/talent_v4/types/common.py", - "google/cloud/talent_v4/types/company.py", - "google/cloud/talent_v4/types/company_service.py", - "google/cloud/talent_v4/types/completion_service.py", - "google/cloud/talent_v4/types/event.py", - "google/cloud/talent_v4/types/event_service.py", - "google/cloud/talent_v4/types/filters.py", - "google/cloud/talent_v4/types/histogram.py", - "google/cloud/talent_v4/types/job.py", - "google/cloud/talent_v4/types/job_service.py", - "google/cloud/talent_v4/types/tenant.py", - "google/cloud/talent_v4/types/tenant_service.py", - "google/cloud/talent_v4beta1/__init__.py", - "google/cloud/talent_v4beta1/proto/application.proto", - "google/cloud/talent_v4beta1/proto/application_service.proto", - "google/cloud/talent_v4beta1/proto/batch.proto", - "google/cloud/talent_v4beta1/proto/common.proto", - "google/cloud/talent_v4beta1/proto/company.proto", - "google/cloud/talent_v4beta1/proto/company_service.proto", - "google/cloud/talent_v4beta1/proto/completion_service.proto", - "google/cloud/talent_v4beta1/proto/event.proto", - "google/cloud/talent_v4beta1/proto/event_service.proto", - "google/cloud/talent_v4beta1/proto/filters.proto", - "google/cloud/talent_v4beta1/proto/histogram.proto", - "google/cloud/talent_v4beta1/proto/job.proto", - "google/cloud/talent_v4beta1/proto/job_service.proto", - "google/cloud/talent_v4beta1/proto/profile.proto", - "google/cloud/talent_v4beta1/proto/profile_service.proto", - "google/cloud/talent_v4beta1/proto/tenant.proto", - "google/cloud/talent_v4beta1/proto/tenant_service.proto", - "google/cloud/talent_v4beta1/py.typed", - "google/cloud/talent_v4beta1/services/__init__.py", - "google/cloud/talent_v4beta1/services/application_service/__init__.py", - "google/cloud/talent_v4beta1/services/application_service/async_client.py", - "google/cloud/talent_v4beta1/services/application_service/client.py", - "google/cloud/talent_v4beta1/services/application_service/pagers.py", - "google/cloud/talent_v4beta1/services/application_service/transports/__init__.py", - "google/cloud/talent_v4beta1/services/application_service/transports/base.py", - "google/cloud/talent_v4beta1/services/application_service/transports/grpc.py", - "google/cloud/talent_v4beta1/services/application_service/transports/grpc_asyncio.py", - "google/cloud/talent_v4beta1/services/company_service/__init__.py", - "google/cloud/talent_v4beta1/services/company_service/async_client.py", - "google/cloud/talent_v4beta1/services/company_service/client.py", - "google/cloud/talent_v4beta1/services/company_service/pagers.py", - "google/cloud/talent_v4beta1/services/company_service/transports/__init__.py", - "google/cloud/talent_v4beta1/services/company_service/transports/base.py", - "google/cloud/talent_v4beta1/services/company_service/transports/grpc.py", - "google/cloud/talent_v4beta1/services/company_service/transports/grpc_asyncio.py", - "google/cloud/talent_v4beta1/services/completion/__init__.py", - "google/cloud/talent_v4beta1/services/completion/async_client.py", - "google/cloud/talent_v4beta1/services/completion/client.py", - "google/cloud/talent_v4beta1/services/completion/transports/__init__.py", - "google/cloud/talent_v4beta1/services/completion/transports/base.py", - "google/cloud/talent_v4beta1/services/completion/transports/grpc.py", - "google/cloud/talent_v4beta1/services/completion/transports/grpc_asyncio.py", - "google/cloud/talent_v4beta1/services/event_service/__init__.py", - "google/cloud/talent_v4beta1/services/event_service/async_client.py", - "google/cloud/talent_v4beta1/services/event_service/client.py", - "google/cloud/talent_v4beta1/services/event_service/transports/__init__.py", - "google/cloud/talent_v4beta1/services/event_service/transports/base.py", - "google/cloud/talent_v4beta1/services/event_service/transports/grpc.py", - "google/cloud/talent_v4beta1/services/event_service/transports/grpc_asyncio.py", - "google/cloud/talent_v4beta1/services/job_service/__init__.py", - "google/cloud/talent_v4beta1/services/job_service/async_client.py", - "google/cloud/talent_v4beta1/services/job_service/client.py", - "google/cloud/talent_v4beta1/services/job_service/pagers.py", - "google/cloud/talent_v4beta1/services/job_service/transports/__init__.py", - "google/cloud/talent_v4beta1/services/job_service/transports/base.py", - "google/cloud/talent_v4beta1/services/job_service/transports/grpc.py", - "google/cloud/talent_v4beta1/services/job_service/transports/grpc_asyncio.py", - "google/cloud/talent_v4beta1/services/profile_service/__init__.py", - "google/cloud/talent_v4beta1/services/profile_service/async_client.py", - "google/cloud/talent_v4beta1/services/profile_service/client.py", - "google/cloud/talent_v4beta1/services/profile_service/pagers.py", - "google/cloud/talent_v4beta1/services/profile_service/transports/__init__.py", - "google/cloud/talent_v4beta1/services/profile_service/transports/base.py", - "google/cloud/talent_v4beta1/services/profile_service/transports/grpc.py", - "google/cloud/talent_v4beta1/services/profile_service/transports/grpc_asyncio.py", - "google/cloud/talent_v4beta1/services/tenant_service/__init__.py", - "google/cloud/talent_v4beta1/services/tenant_service/async_client.py", - "google/cloud/talent_v4beta1/services/tenant_service/client.py", - "google/cloud/talent_v4beta1/services/tenant_service/pagers.py", - "google/cloud/talent_v4beta1/services/tenant_service/transports/__init__.py", - "google/cloud/talent_v4beta1/services/tenant_service/transports/base.py", - "google/cloud/talent_v4beta1/services/tenant_service/transports/grpc.py", - "google/cloud/talent_v4beta1/services/tenant_service/transports/grpc_asyncio.py", - "google/cloud/talent_v4beta1/types/__init__.py", - "google/cloud/talent_v4beta1/types/application.py", - "google/cloud/talent_v4beta1/types/application_service.py", - "google/cloud/talent_v4beta1/types/batch.py", - "google/cloud/talent_v4beta1/types/common.py", - "google/cloud/talent_v4beta1/types/company.py", - "google/cloud/talent_v4beta1/types/company_service.py", - "google/cloud/talent_v4beta1/types/completion_service.py", - "google/cloud/talent_v4beta1/types/event.py", - "google/cloud/talent_v4beta1/types/event_service.py", - "google/cloud/talent_v4beta1/types/filters.py", - "google/cloud/talent_v4beta1/types/histogram.py", - "google/cloud/talent_v4beta1/types/job.py", - "google/cloud/talent_v4beta1/types/job_service.py", - "google/cloud/talent_v4beta1/types/profile.py", - "google/cloud/talent_v4beta1/types/profile_service.py", - "google/cloud/talent_v4beta1/types/tenant.py", - "google/cloud/talent_v4beta1/types/tenant_service.py", - "mypy.ini", - "noxfile.py", - "renovate.json", - "samples/AUTHORING_GUIDE.md", - "samples/CONTRIBUTING.md", - "samples/snippets/noxfile.py", - "scripts/decrypt-secrets.sh", - "scripts/fixup_talent_v4_keywords.py", - "scripts/fixup_talent_v4beta1_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/talent_v4/__init__.py", - "tests/unit/gapic/talent_v4/test_company_service.py", - "tests/unit/gapic/talent_v4/test_completion.py", - "tests/unit/gapic/talent_v4/test_event_service.py", - "tests/unit/gapic/talent_v4/test_job_service.py", - "tests/unit/gapic/talent_v4/test_tenant_service.py", - "tests/unit/gapic/talent_v4beta1/__init__.py", - "tests/unit/gapic/talent_v4beta1/test_application_service.py", - "tests/unit/gapic/talent_v4beta1/test_company_service.py", - "tests/unit/gapic/talent_v4beta1/test_completion.py", - "tests/unit/gapic/talent_v4beta1/test_event_service.py", - "tests/unit/gapic/talent_v4beta1/test_job_service.py", - "tests/unit/gapic/talent_v4beta1/test_profile_service.py", - "tests/unit/gapic/talent_v4beta1/test_tenant_service.py" ] } \ No newline at end of file diff --git a/synth.py b/synth.py index bc3d5083..a8573b62 100644 --- a/synth.py +++ b/synth.py @@ -48,7 +48,7 @@ templated_files = common.py_library( samples=True, # set to True only if there are samples microgenerator=True, - cov_level=99, + cov_level=98, ) s.move(templated_files, excludes=[".coveragerc"]) # microgenerator has a good .coveragerc file diff --git a/testing/constraints-3.6.txt b/testing/constraints-3.6.txt index 2923be13..cc205f2a 100644 --- a/testing/constraints-3.6.txt +++ b/testing/constraints-3.6.txt @@ -5,6 +5,5 @@ # # e.g., if setup.py has "foo >= 1.14.0, < 2.0.0dev", # Then this file should have foo==1.14.0 -google-api-core==1.22.0 -proto-plus==1.4.0 -libcst==0.2.5 \ No newline at end of file +google-api-core==1.22.2 +proto-plus==1.15.0 diff --git a/tests/unit/gapic/talent_v4/__init__.py b/tests/unit/gapic/talent_v4/__init__.py index 8b137891..42ffdf2b 100644 --- a/tests/unit/gapic/talent_v4/__init__.py +++ b/tests/unit/gapic/talent_v4/__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/talent_v4/test_company_service.py b/tests/unit/gapic/talent_v4/test_company_service.py index bcb62811..eaa1a863 100644 --- a/tests/unit/gapic/talent_v4/test_company_service.py +++ b/tests/unit/gapic/talent_v4/test_company_service.py @@ -91,7 +91,24 @@ def test__get_default_mtls_endpoint(): @pytest.mark.parametrize( - "client_class", [CompanyServiceClient, CompanyServiceAsyncClient] + "client_class", [CompanyServiceClient, CompanyServiceAsyncClient,] +) +def test_company_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 == "jobs.googleapis.com:443" + + +@pytest.mark.parametrize( + "client_class", [CompanyServiceClient, CompanyServiceAsyncClient,] ) def test_company_service_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() @@ -101,16 +118,21 @@ def test_company_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 == "jobs.googleapis.com:443" def test_company_service_client_get_transport_class(): transport = CompanyServiceClient.get_transport_class() - assert transport == transports.CompanyServiceGrpcTransport + available_transports = [ + transports.CompanyServiceGrpcTransport, + ] + assert transport in available_transports transport = CompanyServiceClient.get_transport_class("grpc") assert transport == transports.CompanyServiceGrpcTransport @@ -161,7 +183,7 @@ def test_company_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, ) @@ -177,7 +199,7 @@ def test_company_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, ) @@ -193,7 +215,7 @@ def test_company_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, ) @@ -221,7 +243,7 @@ def test_company_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, ) @@ -272,29 +294,25 @@ def test_company_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. @@ -303,66 +321,53 @@ def test_company_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", @@ -388,7 +393,7 @@ def test_company_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, ) @@ -418,7 +423,7 @@ def test_company_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, ) @@ -437,7 +442,7 @@ def test_company_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, ) @@ -517,6 +522,22 @@ def test_create_company_from_dict(): test_create_company(request_type=dict) +def test_create_company_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 = CompanyServiceClient( + 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_company), "__call__") as call: + client.create_company() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == company_service.CreateCompanyRequest() + + @pytest.mark.asyncio async def test_create_company_async( transport: str = "grpc_asyncio", request_type=company_service.CreateCompanyRequest @@ -794,6 +815,22 @@ def test_get_company_from_dict(): test_get_company(request_type=dict) +def test_get_company_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 = CompanyServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_company), "__call__") as call: + client.get_company() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == company_service.GetCompanyRequest() + + @pytest.mark.asyncio async def test_get_company_async( transport: str = "grpc_asyncio", request_type=company_service.GetCompanyRequest @@ -1059,6 +1096,22 @@ def test_update_company_from_dict(): test_update_company(request_type=dict) +def test_update_company_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 = CompanyServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.update_company), "__call__") as call: + client.update_company() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == company_service.UpdateCompanyRequest() + + @pytest.mark.asyncio async def test_update_company_async( transport: str = "grpc_asyncio", request_type=company_service.UpdateCompanyRequest @@ -1300,6 +1353,22 @@ def test_delete_company_from_dict(): test_delete_company(request_type=dict) +def test_delete_company_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 = CompanyServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_company), "__call__") as call: + client.delete_company() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == company_service.DeleteCompanyRequest() + + @pytest.mark.asyncio async def test_delete_company_async( transport: str = "grpc_asyncio", request_type=company_service.DeleteCompanyRequest @@ -1485,6 +1554,22 @@ def test_list_companies_from_dict(): test_list_companies(request_type=dict) +def test_list_companies_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 = CompanyServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_companies), "__call__") as call: + client.list_companies() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == company_service.ListCompaniesRequest() + + @pytest.mark.asyncio async def test_list_companies_async( transport: str = "grpc_asyncio", request_type=company_service.ListCompaniesRequest @@ -1937,6 +2022,54 @@ def test_company_service_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [ + transports.CompanyServiceGrpcTransport, + transports.CompanyServiceGrpcAsyncIOTransport, + ], +) +def test_company_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", + "https://www.googleapis.com/auth/jobs", + ), + 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_company_service_host_no_port(): client = CompanyServiceClient( credentials=credentials.AnonymousCredentials(), @@ -1956,7 +2089,7 @@ def test_company_service_host_with_port(): def test_company_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.CompanyServiceGrpcTransport( @@ -1968,7 +2101,7 @@ def test_company_service_grpc_transport_channel(): def test_company_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.CompanyServiceGrpcAsyncIOTransport( @@ -1979,6 +2112,8 @@ def test_company_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", [ @@ -1993,7 +2128,7 @@ def test_company_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 @@ -2034,6 +2169,8 @@ def test_company_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", [ @@ -2049,7 +2186,7 @@ def test_company_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/talent_v4/test_completion.py b/tests/unit/gapic/talent_v4/test_completion.py index cafd4bc5..e4ed8c02 100644 --- a/tests/unit/gapic/talent_v4/test_completion.py +++ b/tests/unit/gapic/talent_v4/test_completion.py @@ -81,7 +81,22 @@ def test__get_default_mtls_endpoint(): assert CompletionClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi -@pytest.mark.parametrize("client_class", [CompletionClient, CompletionAsyncClient]) +@pytest.mark.parametrize("client_class", [CompletionClient, CompletionAsyncClient,]) +def test_completion_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 == "jobs.googleapis.com:443" + + +@pytest.mark.parametrize("client_class", [CompletionClient, CompletionAsyncClient,]) def test_completion_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() with mock.patch.object( @@ -90,16 +105,21 @@ def test_completion_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 == "jobs.googleapis.com:443" def test_completion_client_get_transport_class(): transport = CompletionClient.get_transport_class() - assert transport == transports.CompletionGrpcTransport + available_transports = [ + transports.CompletionGrpcTransport, + ] + assert transport in available_transports transport = CompletionClient.get_transport_class("grpc") assert transport == transports.CompletionGrpcTransport @@ -148,7 +168,7 @@ def test_completion_client_client_options( credentials_file=None, host="squid.clam.whelk", scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -164,7 +184,7 @@ def test_completion_client_client_options( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -180,7 +200,7 @@ def test_completion_client_client_options( credentials_file=None, host=client.DEFAULT_MTLS_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -208,7 +228,7 @@ def test_completion_client_client_options( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id="octopus", client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -257,29 +277,25 @@ def test_completion_client_mtls_env_auto( client_cert_source=client_cert_source_callback ) with mock.patch.object(transport_class, "__init__") as patched: - ssl_channel_creds = mock.Mock() - with mock.patch( - "grpc.ssl_channel_credentials", return_value=ssl_channel_creds - ): - patched.return_value = None - client = client_class(client_options=options) + patched.return_value = None + client = client_class(client_options=options) - if use_client_cert_env == "false": - expected_ssl_channel_creds = None - expected_host = client.DEFAULT_ENDPOINT - else: - expected_ssl_channel_creds = ssl_channel_creds - expected_host = client.DEFAULT_MTLS_ENDPOINT + if use_client_cert_env == "false": + expected_client_cert_source = None + expected_host = client.DEFAULT_ENDPOINT + else: + expected_client_cert_source = client_cert_source_callback + expected_host = client.DEFAULT_MTLS_ENDPOINT - patched.assert_called_once_with( - credentials=None, - credentials_file=None, - host=expected_host, - scopes=None, - ssl_channel_credentials=expected_ssl_channel_creds, - quota_project_id=None, - client_info=transports.base.DEFAULT_CLIENT_INFO, - ) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=expected_host, + scopes=None, + client_cert_source_for_mtls=expected_client_cert_source, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) # Check the case ADC client cert is provided. Whether client cert is used depends on # GOOGLE_API_USE_CLIENT_CERTIFICATE value. @@ -288,66 +304,53 @@ def test_completion_client_mtls_env_auto( ): with mock.patch.object(transport_class, "__init__") as patched: with mock.patch( - "google.auth.transport.grpc.SslCredentials.__init__", return_value=None + "google.auth.transport.mtls.has_default_client_cert_source", + return_value=True, ): with mock.patch( - "google.auth.transport.grpc.SslCredentials.is_mtls", - new_callable=mock.PropertyMock, - ) as is_mtls_mock: - with mock.patch( - "google.auth.transport.grpc.SslCredentials.ssl_credentials", - new_callable=mock.PropertyMock, - ) as ssl_credentials_mock: - if use_client_cert_env == "false": - is_mtls_mock.return_value = False - ssl_credentials_mock.return_value = None - expected_host = client.DEFAULT_ENDPOINT - expected_ssl_channel_creds = None - else: - is_mtls_mock.return_value = True - ssl_credentials_mock.return_value = mock.Mock() - expected_host = client.DEFAULT_MTLS_ENDPOINT - expected_ssl_channel_creds = ( - ssl_credentials_mock.return_value - ) - - patched.return_value = None - client = client_class() - patched.assert_called_once_with( - credentials=None, - credentials_file=None, - host=expected_host, - scopes=None, - ssl_channel_credentials=expected_ssl_channel_creds, - quota_project_id=None, - client_info=transports.base.DEFAULT_CLIENT_INFO, - ) + "google.auth.transport.mtls.default_client_cert_source", + return_value=client_cert_source_callback, + ): + if use_client_cert_env == "false": + expected_host = client.DEFAULT_ENDPOINT + expected_client_cert_source = None + else: + expected_host = client.DEFAULT_MTLS_ENDPOINT + expected_client_cert_source = client_cert_source_callback - # Check the case client_cert_source and ADC client cert are not provided. - with mock.patch.dict( - os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env} - ): - with mock.patch.object(transport_class, "__init__") as patched: - with mock.patch( - "google.auth.transport.grpc.SslCredentials.__init__", return_value=None - ): - with mock.patch( - "google.auth.transport.grpc.SslCredentials.is_mtls", - new_callable=mock.PropertyMock, - ) as is_mtls_mock: - is_mtls_mock.return_value = False patched.return_value = None client = client_class() patched.assert_called_once_with( credentials=None, credentials_file=None, - host=client.DEFAULT_ENDPOINT, + host=expected_host, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=expected_client_cert_source, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) + # Check the case client_cert_source and ADC client cert are not provided. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env} + ): + with mock.patch.object(transport_class, "__init__") as patched: + with mock.patch( + "google.auth.transport.mtls.has_default_client_cert_source", + return_value=False, + ): + patched.return_value = None + client = client_class() + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) + @pytest.mark.parametrize( "client_class,transport_class,transport_name", @@ -373,7 +376,7 @@ def test_completion_client_client_options_scopes( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=["1", "2"], - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -403,7 +406,7 @@ def test_completion_client_client_options_credentials_file( credentials_file="credentials.json", host=client.DEFAULT_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -420,7 +423,7 @@ def test_completion_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, ) @@ -459,6 +462,22 @@ def test_complete_query_from_dict(): test_complete_query(request_type=dict) +def test_complete_query_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 = CompletionClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.complete_query), "__call__") as call: + client.complete_query() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == completion_service.CompleteQueryRequest() + + @pytest.mark.asyncio async def test_complete_query_async( transport: str = "grpc_asyncio", @@ -603,7 +622,7 @@ def test_transport_get_channel(): @pytest.mark.parametrize( "transport_class", - [transports.CompletionGrpcTransport, transports.CompletionGrpcAsyncIOTransport], + [transports.CompletionGrpcTransport, transports.CompletionGrpcAsyncIOTransport,], ) def test_transport_adc(transport_class): # Test default credentials are used if not provided. @@ -710,6 +729,51 @@ def test_completion_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [transports.CompletionGrpcTransport, transports.CompletionGrpcAsyncIOTransport], +) +def test_completion_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", + "https://www.googleapis.com/auth/jobs", + ), + 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_completion_host_no_port(): client = CompletionClient( credentials=credentials.AnonymousCredentials(), @@ -729,7 +793,7 @@ def test_completion_host_with_port(): def test_completion_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.CompletionGrpcTransport( @@ -741,7 +805,7 @@ def test_completion_grpc_transport_channel(): def test_completion_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.CompletionGrpcAsyncIOTransport( @@ -752,6 +816,8 @@ def test_completion_grpc_asyncio_transport_channel(): assert transport._ssl_channel_credentials == None +# Remove this test when deprecated arguments (api_mtls_endpoint, client_cert_source) are +# removed from grpc/grpc_asyncio transport constructor. @pytest.mark.parametrize( "transport_class", [transports.CompletionGrpcTransport, transports.CompletionGrpcAsyncIOTransport], @@ -761,7 +827,7 @@ def test_completion_transport_channel_mtls_with_client_cert_source(transport_cla "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 @@ -802,6 +868,8 @@ def test_completion_transport_channel_mtls_with_client_cert_source(transport_cla assert transport._ssl_channel_credentials == mock_ssl_cred +# Remove this test when deprecated arguments (api_mtls_endpoint, client_cert_source) are +# removed from grpc/grpc_asyncio transport constructor. @pytest.mark.parametrize( "transport_class", [transports.CompletionGrpcTransport, transports.CompletionGrpcAsyncIOTransport], @@ -814,7 +882,7 @@ def test_completion_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/talent_v4/test_event_service.py b/tests/unit/gapic/talent_v4/test_event_service.py index dcf80843..e28dd92b 100644 --- a/tests/unit/gapic/talent_v4/test_event_service.py +++ b/tests/unit/gapic/talent_v4/test_event_service.py @@ -82,7 +82,22 @@ def test__get_default_mtls_endpoint(): assert EventServiceClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi -@pytest.mark.parametrize("client_class", [EventServiceClient, EventServiceAsyncClient]) +@pytest.mark.parametrize("client_class", [EventServiceClient, EventServiceAsyncClient,]) +def test_event_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 == "jobs.googleapis.com:443" + + +@pytest.mark.parametrize("client_class", [EventServiceClient, EventServiceAsyncClient,]) def test_event_service_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() with mock.patch.object( @@ -91,16 +106,21 @@ def test_event_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 == "jobs.googleapis.com:443" def test_event_service_client_get_transport_class(): transport = EventServiceClient.get_transport_class() - assert transport == transports.EventServiceGrpcTransport + available_transports = [ + transports.EventServiceGrpcTransport, + ] + assert transport in available_transports transport = EventServiceClient.get_transport_class("grpc") assert transport == transports.EventServiceGrpcTransport @@ -149,7 +169,7 @@ def test_event_service_client_client_options( credentials_file=None, host="squid.clam.whelk", scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -165,7 +185,7 @@ def test_event_service_client_client_options( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -181,7 +201,7 @@ def test_event_service_client_client_options( credentials_file=None, host=client.DEFAULT_MTLS_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -209,7 +229,7 @@ def test_event_service_client_client_options( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id="octopus", client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -258,29 +278,25 @@ def test_event_service_client_mtls_env_auto( client_cert_source=client_cert_source_callback ) with mock.patch.object(transport_class, "__init__") as patched: - ssl_channel_creds = mock.Mock() - with mock.patch( - "grpc.ssl_channel_credentials", return_value=ssl_channel_creds - ): - patched.return_value = None - client = client_class(client_options=options) + patched.return_value = None + client = client_class(client_options=options) - if use_client_cert_env == "false": - expected_ssl_channel_creds = None - expected_host = client.DEFAULT_ENDPOINT - else: - expected_ssl_channel_creds = ssl_channel_creds - expected_host = client.DEFAULT_MTLS_ENDPOINT + if use_client_cert_env == "false": + expected_client_cert_source = None + expected_host = client.DEFAULT_ENDPOINT + else: + expected_client_cert_source = client_cert_source_callback + expected_host = client.DEFAULT_MTLS_ENDPOINT - patched.assert_called_once_with( - credentials=None, - credentials_file=None, - host=expected_host, - scopes=None, - ssl_channel_credentials=expected_ssl_channel_creds, - quota_project_id=None, - client_info=transports.base.DEFAULT_CLIENT_INFO, - ) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=expected_host, + scopes=None, + client_cert_source_for_mtls=expected_client_cert_source, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) # Check the case ADC client cert is provided. Whether client cert is used depends on # GOOGLE_API_USE_CLIENT_CERTIFICATE value. @@ -289,66 +305,53 @@ def test_event_service_client_mtls_env_auto( ): with mock.patch.object(transport_class, "__init__") as patched: with mock.patch( - "google.auth.transport.grpc.SslCredentials.__init__", return_value=None + "google.auth.transport.mtls.has_default_client_cert_source", + return_value=True, ): with mock.patch( - "google.auth.transport.grpc.SslCredentials.is_mtls", - new_callable=mock.PropertyMock, - ) as is_mtls_mock: - with mock.patch( - "google.auth.transport.grpc.SslCredentials.ssl_credentials", - new_callable=mock.PropertyMock, - ) as ssl_credentials_mock: - if use_client_cert_env == "false": - is_mtls_mock.return_value = False - ssl_credentials_mock.return_value = None - expected_host = client.DEFAULT_ENDPOINT - expected_ssl_channel_creds = None - else: - is_mtls_mock.return_value = True - ssl_credentials_mock.return_value = mock.Mock() - expected_host = client.DEFAULT_MTLS_ENDPOINT - expected_ssl_channel_creds = ( - ssl_credentials_mock.return_value - ) - - patched.return_value = None - client = client_class() - patched.assert_called_once_with( - credentials=None, - credentials_file=None, - host=expected_host, - scopes=None, - ssl_channel_credentials=expected_ssl_channel_creds, - quota_project_id=None, - client_info=transports.base.DEFAULT_CLIENT_INFO, - ) + "google.auth.transport.mtls.default_client_cert_source", + return_value=client_cert_source_callback, + ): + if use_client_cert_env == "false": + expected_host = client.DEFAULT_ENDPOINT + expected_client_cert_source = None + else: + expected_host = client.DEFAULT_MTLS_ENDPOINT + expected_client_cert_source = client_cert_source_callback - # Check the case client_cert_source and ADC client cert are not provided. - with mock.patch.dict( - os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env} - ): - with mock.patch.object(transport_class, "__init__") as patched: - with mock.patch( - "google.auth.transport.grpc.SslCredentials.__init__", return_value=None - ): - with mock.patch( - "google.auth.transport.grpc.SslCredentials.is_mtls", - new_callable=mock.PropertyMock, - ) as is_mtls_mock: - is_mtls_mock.return_value = False patched.return_value = None client = client_class() patched.assert_called_once_with( credentials=None, credentials_file=None, - host=client.DEFAULT_ENDPOINT, + host=expected_host, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=expected_client_cert_source, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) + # Check the case client_cert_source and ADC client cert are not provided. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env} + ): + with mock.patch.object(transport_class, "__init__") as patched: + with mock.patch( + "google.auth.transport.mtls.has_default_client_cert_source", + return_value=False, + ): + patched.return_value = None + client = client_class() + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) + @pytest.mark.parametrize( "client_class,transport_class,transport_name", @@ -374,7 +377,7 @@ def test_event_service_client_client_options_scopes( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=["1", "2"], - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -404,7 +407,7 @@ def test_event_service_client_client_options_credentials_file( credentials_file="credentials.json", host=client.DEFAULT_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -421,7 +424,7 @@ def test_event_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, ) @@ -473,6 +476,24 @@ def test_create_client_event_from_dict(): test_create_client_event(request_type=dict) +def test_create_client_event_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 = EventServiceClient( + 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_client_event), "__call__" + ) as call: + client.create_client_event() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == event_service.CreateClientEventRequest() + + @pytest.mark.asyncio async def test_create_client_event_async( transport: str = "grpc_asyncio", request_type=event_service.CreateClientEventRequest @@ -713,7 +734,10 @@ def test_transport_get_channel(): @pytest.mark.parametrize( "transport_class", - [transports.EventServiceGrpcTransport, transports.EventServiceGrpcAsyncIOTransport], + [ + transports.EventServiceGrpcTransport, + transports.EventServiceGrpcAsyncIOTransport, + ], ) def test_transport_adc(transport_class): # Test default credentials are used if not provided. @@ -820,6 +844,51 @@ def test_event_service_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [transports.EventServiceGrpcTransport, transports.EventServiceGrpcAsyncIOTransport], +) +def test_event_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", + "https://www.googleapis.com/auth/jobs", + ), + 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_event_service_host_no_port(): client = EventServiceClient( credentials=credentials.AnonymousCredentials(), @@ -839,7 +908,7 @@ def test_event_service_host_with_port(): def test_event_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.EventServiceGrpcTransport( @@ -851,7 +920,7 @@ def test_event_service_grpc_transport_channel(): def test_event_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.EventServiceGrpcAsyncIOTransport( @@ -862,6 +931,8 @@ def test_event_service_grpc_asyncio_transport_channel(): assert transport._ssl_channel_credentials == None +# Remove this test when deprecated arguments (api_mtls_endpoint, client_cert_source) are +# removed from grpc/grpc_asyncio transport constructor. @pytest.mark.parametrize( "transport_class", [transports.EventServiceGrpcTransport, transports.EventServiceGrpcAsyncIOTransport], @@ -871,7 +942,7 @@ def test_event_service_transport_channel_mtls_with_client_cert_source(transport_ "grpc.ssl_channel_credentials", autospec=True ) as grpc_ssl_channel_cred: with mock.patch.object( - transport_class, "create_channel", autospec=True + transport_class, "create_channel" ) as grpc_create_channel: mock_ssl_cred = mock.Mock() grpc_ssl_channel_cred.return_value = mock_ssl_cred @@ -912,6 +983,8 @@ def test_event_service_transport_channel_mtls_with_client_cert_source(transport_ assert transport._ssl_channel_credentials == mock_ssl_cred +# Remove this test when deprecated arguments (api_mtls_endpoint, client_cert_source) are +# removed from grpc/grpc_asyncio transport constructor. @pytest.mark.parametrize( "transport_class", [transports.EventServiceGrpcTransport, transports.EventServiceGrpcAsyncIOTransport], @@ -924,7 +997,7 @@ def test_event_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/talent_v4/test_job_service.py b/tests/unit/gapic/talent_v4/test_job_service.py index 208347d4..d0254e33 100644 --- a/tests/unit/gapic/talent_v4/test_job_service.py +++ b/tests/unit/gapic/talent_v4/test_job_service.py @@ -98,7 +98,22 @@ def test__get_default_mtls_endpoint(): assert JobServiceClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi -@pytest.mark.parametrize("client_class", [JobServiceClient, JobServiceAsyncClient]) +@pytest.mark.parametrize("client_class", [JobServiceClient, JobServiceAsyncClient,]) +def test_job_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 == "jobs.googleapis.com:443" + + +@pytest.mark.parametrize("client_class", [JobServiceClient, JobServiceAsyncClient,]) def test_job_service_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() with mock.patch.object( @@ -107,16 +122,21 @@ def test_job_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 == "jobs.googleapis.com:443" def test_job_service_client_get_transport_class(): transport = JobServiceClient.get_transport_class() - assert transport == transports.JobServiceGrpcTransport + available_transports = [ + transports.JobServiceGrpcTransport, + ] + assert transport in available_transports transport = JobServiceClient.get_transport_class("grpc") assert transport == transports.JobServiceGrpcTransport @@ -165,7 +185,7 @@ def test_job_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, ) @@ -181,7 +201,7 @@ def test_job_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, ) @@ -197,7 +217,7 @@ def test_job_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, ) @@ -225,7 +245,7 @@ def test_job_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, ) @@ -274,29 +294,25 @@ def test_job_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. @@ -305,66 +321,53 @@ def test_job_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", @@ -390,7 +393,7 @@ def test_job_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, ) @@ -420,7 +423,7 @@ def test_job_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, ) @@ -437,7 +440,7 @@ def test_job_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, ) @@ -532,6 +535,22 @@ def test_create_job_from_dict(): test_create_job(request_type=dict) +def test_create_job_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = JobServiceClient( + 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_job), "__call__") as call: + client.create_job() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == job_service.CreateJobRequest() + + @pytest.mark.asyncio async def test_create_job_async( transport: str = "grpc_asyncio", request_type=job_service.CreateJobRequest @@ -786,6 +805,24 @@ def test_batch_create_jobs_from_dict(): test_batch_create_jobs(request_type=dict) +def test_batch_create_jobs_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = JobServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.batch_create_jobs), "__call__" + ) as call: + client.batch_create_jobs() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == job_service.BatchCreateJobsRequest() + + @pytest.mark.asyncio async def test_batch_create_jobs_async( transport: str = "grpc_asyncio", request_type=job_service.BatchCreateJobsRequest @@ -1051,6 +1088,22 @@ def test_get_job_from_dict(): test_get_job(request_type=dict) +def test_get_job_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = JobServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_job), "__call__") as call: + client.get_job() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == job_service.GetJobRequest() + + @pytest.mark.asyncio async def test_get_job_async( transport: str = "grpc_asyncio", request_type=job_service.GetJobRequest @@ -1348,6 +1401,22 @@ def test_update_job_from_dict(): test_update_job(request_type=dict) +def test_update_job_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = JobServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.update_job), "__call__") as call: + client.update_job() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == job_service.UpdateJobRequest() + + @pytest.mark.asyncio async def test_update_job_async( transport: str = "grpc_asyncio", request_type=job_service.UpdateJobRequest @@ -1604,6 +1673,24 @@ def test_batch_update_jobs_from_dict(): test_batch_update_jobs(request_type=dict) +def test_batch_update_jobs_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = JobServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.batch_update_jobs), "__call__" + ) as call: + client.batch_update_jobs() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == job_service.BatchUpdateJobsRequest() + + @pytest.mark.asyncio async def test_batch_update_jobs_async( transport: str = "grpc_asyncio", request_type=job_service.BatchUpdateJobsRequest @@ -1810,6 +1897,22 @@ def test_delete_job_from_dict(): test_delete_job(request_type=dict) +def test_delete_job_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = JobServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_job), "__call__") as call: + client.delete_job() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == job_service.DeleteJobRequest() + + @pytest.mark.asyncio async def test_delete_job_async( transport: str = "grpc_asyncio", request_type=job_service.DeleteJobRequest @@ -1992,6 +2095,24 @@ def test_batch_delete_jobs_from_dict(): test_batch_delete_jobs(request_type=dict) +def test_batch_delete_jobs_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = JobServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.batch_delete_jobs), "__call__" + ) as call: + client.batch_delete_jobs() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == job_service.BatchDeleteJobsRequest() + + @pytest.mark.asyncio async def test_batch_delete_jobs_async( transport: str = "grpc_asyncio", request_type=job_service.BatchDeleteJobsRequest @@ -2203,6 +2324,22 @@ def test_list_jobs_from_dict(): test_list_jobs(request_type=dict) +def test_list_jobs_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = JobServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_jobs), "__call__") as call: + client.list_jobs() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == job_service.ListJobsRequest() + + @pytest.mark.asyncio async def test_list_jobs_async( transport: str = "grpc_asyncio", request_type=job_service.ListJobsRequest @@ -2512,6 +2649,22 @@ def test_search_jobs_from_dict(): test_search_jobs(request_type=dict) +def test_search_jobs_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = JobServiceClient( + 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_jobs), "__call__") as call: + client.search_jobs() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == job_service.SearchJobsRequest() + + @pytest.mark.asyncio async def test_search_jobs_async( transport: str = "grpc_asyncio", request_type=job_service.SearchJobsRequest @@ -2656,6 +2809,24 @@ def test_search_jobs_for_alert_from_dict(): test_search_jobs_for_alert(request_type=dict) +def test_search_jobs_for_alert_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 = JobServiceClient( + 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_jobs_for_alert), "__call__" + ) as call: + client.search_jobs_for_alert() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == job_service.SearchJobsRequest() + + @pytest.mark.asyncio async def test_search_jobs_for_alert_async( transport: str = "grpc_asyncio", request_type=job_service.SearchJobsRequest @@ -2815,7 +2986,7 @@ def test_transport_get_channel(): @pytest.mark.parametrize( "transport_class", - [transports.JobServiceGrpcTransport, transports.JobServiceGrpcAsyncIOTransport], + [transports.JobServiceGrpcTransport, transports.JobServiceGrpcAsyncIOTransport,], ) def test_transport_adc(transport_class): # Test default credentials are used if not provided. @@ -2938,6 +3109,51 @@ def test_job_service_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [transports.JobServiceGrpcTransport, transports.JobServiceGrpcAsyncIOTransport], +) +def test_job_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", + "https://www.googleapis.com/auth/jobs", + ), + 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_job_service_host_no_port(): client = JobServiceClient( credentials=credentials.AnonymousCredentials(), @@ -2957,7 +3173,7 @@ def test_job_service_host_with_port(): def test_job_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.JobServiceGrpcTransport( @@ -2969,7 +3185,7 @@ def test_job_service_grpc_transport_channel(): def test_job_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.JobServiceGrpcAsyncIOTransport( @@ -2980,6 +3196,8 @@ def test_job_service_grpc_asyncio_transport_channel(): assert transport._ssl_channel_credentials == None +# Remove this test when deprecated arguments (api_mtls_endpoint, client_cert_source) are +# removed from grpc/grpc_asyncio transport constructor. @pytest.mark.parametrize( "transport_class", [transports.JobServiceGrpcTransport, transports.JobServiceGrpcAsyncIOTransport], @@ -2989,7 +3207,7 @@ def test_job_service_transport_channel_mtls_with_client_cert_source(transport_cl "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 @@ -3030,6 +3248,8 @@ def test_job_service_transport_channel_mtls_with_client_cert_source(transport_cl assert transport._ssl_channel_credentials == mock_ssl_cred +# Remove this test when deprecated arguments (api_mtls_endpoint, client_cert_source) are +# removed from grpc/grpc_asyncio transport constructor. @pytest.mark.parametrize( "transport_class", [transports.JobServiceGrpcTransport, transports.JobServiceGrpcAsyncIOTransport], @@ -3042,7 +3262,7 @@ def test_job_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/talent_v4/test_tenant_service.py b/tests/unit/gapic/talent_v4/test_tenant_service.py index 32438832..64e5cbbb 100644 --- a/tests/unit/gapic/talent_v4/test_tenant_service.py +++ b/tests/unit/gapic/talent_v4/test_tenant_service.py @@ -88,7 +88,24 @@ def test__get_default_mtls_endpoint(): @pytest.mark.parametrize( - "client_class", [TenantServiceClient, TenantServiceAsyncClient] + "client_class", [TenantServiceClient, TenantServiceAsyncClient,] +) +def test_tenant_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 == "jobs.googleapis.com:443" + + +@pytest.mark.parametrize( + "client_class", [TenantServiceClient, TenantServiceAsyncClient,] ) def test_tenant_service_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() @@ -98,16 +115,21 @@ def test_tenant_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 == "jobs.googleapis.com:443" def test_tenant_service_client_get_transport_class(): transport = TenantServiceClient.get_transport_class() - assert transport == transports.TenantServiceGrpcTransport + available_transports = [ + transports.TenantServiceGrpcTransport, + ] + assert transport in available_transports transport = TenantServiceClient.get_transport_class("grpc") assert transport == transports.TenantServiceGrpcTransport @@ -158,7 +180,7 @@ def test_tenant_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, ) @@ -174,7 +196,7 @@ def test_tenant_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, ) @@ -190,7 +212,7 @@ def test_tenant_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, ) @@ -218,7 +240,7 @@ def test_tenant_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, ) @@ -269,29 +291,25 @@ def test_tenant_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. @@ -300,66 +318,53 @@ def test_tenant_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", @@ -385,7 +390,7 @@ def test_tenant_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, ) @@ -415,7 +420,7 @@ def test_tenant_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, ) @@ -434,7 +439,7 @@ def test_tenant_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, ) @@ -479,6 +484,22 @@ def test_create_tenant_from_dict(): test_create_tenant(request_type=dict) +def test_create_tenant_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 = TenantServiceClient( + 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_tenant), "__call__") as call: + client.create_tenant() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == tenant_service.CreateTenantRequest() + + @pytest.mark.asyncio async def test_create_tenant_async( transport: str = "grpc_asyncio", request_type=tenant_service.CreateTenantRequest @@ -684,6 +705,22 @@ def test_get_tenant_from_dict(): test_get_tenant(request_type=dict) +def test_get_tenant_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 = TenantServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_tenant), "__call__") as call: + client.get_tenant() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == tenant_service.GetTenantRequest() + + @pytest.mark.asyncio async def test_get_tenant_async( transport: str = "grpc_asyncio", request_type=tenant_service.GetTenantRequest @@ -877,6 +914,22 @@ def test_update_tenant_from_dict(): test_update_tenant(request_type=dict) +def test_update_tenant_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 = TenantServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.update_tenant), "__call__") as call: + client.update_tenant() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == tenant_service.UpdateTenantRequest() + + @pytest.mark.asyncio async def test_update_tenant_async( transport: str = "grpc_asyncio", request_type=tenant_service.UpdateTenantRequest @@ -1077,6 +1130,22 @@ def test_delete_tenant_from_dict(): test_delete_tenant(request_type=dict) +def test_delete_tenant_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 = TenantServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_tenant), "__call__") as call: + client.delete_tenant() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == tenant_service.DeleteTenantRequest() + + @pytest.mark.asyncio async def test_delete_tenant_async( transport: str = "grpc_asyncio", request_type=tenant_service.DeleteTenantRequest @@ -1262,6 +1331,22 @@ def test_list_tenants_from_dict(): test_list_tenants(request_type=dict) +def test_list_tenants_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 = TenantServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_tenants), "__call__") as call: + client.list_tenants() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == tenant_service.ListTenantsRequest() + + @pytest.mark.asyncio async def test_list_tenants_async( transport: str = "grpc_asyncio", request_type=tenant_service.ListTenantsRequest @@ -1712,6 +1797,54 @@ def test_tenant_service_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [ + transports.TenantServiceGrpcTransport, + transports.TenantServiceGrpcAsyncIOTransport, + ], +) +def test_tenant_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", + "https://www.googleapis.com/auth/jobs", + ), + 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_tenant_service_host_no_port(): client = TenantServiceClient( credentials=credentials.AnonymousCredentials(), @@ -1731,7 +1864,7 @@ def test_tenant_service_host_with_port(): def test_tenant_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.TenantServiceGrpcTransport( @@ -1743,7 +1876,7 @@ def test_tenant_service_grpc_transport_channel(): def test_tenant_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.TenantServiceGrpcAsyncIOTransport( @@ -1754,6 +1887,8 @@ def test_tenant_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", [ @@ -1766,7 +1901,7 @@ def test_tenant_service_transport_channel_mtls_with_client_cert_source(transport "grpc.ssl_channel_credentials", autospec=True ) as grpc_ssl_channel_cred: with mock.patch.object( - transport_class, "create_channel", autospec=True + transport_class, "create_channel" ) as grpc_create_channel: mock_ssl_cred = mock.Mock() grpc_ssl_channel_cred.return_value = mock_ssl_cred @@ -1807,6 +1942,8 @@ def test_tenant_service_transport_channel_mtls_with_client_cert_source(transport assert transport._ssl_channel_credentials == mock_ssl_cred +# Remove this test when deprecated arguments (api_mtls_endpoint, client_cert_source) are +# removed from grpc/grpc_asyncio transport constructor. @pytest.mark.parametrize( "transport_class", [ @@ -1822,7 +1959,7 @@ def test_tenant_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/talent_v4beta1/__init__.py b/tests/unit/gapic/talent_v4beta1/__init__.py index 8b137891..42ffdf2b 100644 --- a/tests/unit/gapic/talent_v4beta1/__init__.py +++ b/tests/unit/gapic/talent_v4beta1/__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/talent_v4beta1/test_application_service.py b/tests/unit/gapic/talent_v4beta1/test_application_service.py index 9504a896..68c75313 100644 --- a/tests/unit/gapic/talent_v4beta1/test_application_service.py +++ b/tests/unit/gapic/talent_v4beta1/test_application_service.py @@ -97,7 +97,24 @@ def test__get_default_mtls_endpoint(): @pytest.mark.parametrize( - "client_class", [ApplicationServiceClient, ApplicationServiceAsyncClient] + "client_class", [ApplicationServiceClient, ApplicationServiceAsyncClient,] +) +def test_application_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 == "jobs.googleapis.com:443" + + +@pytest.mark.parametrize( + "client_class", [ApplicationServiceClient, ApplicationServiceAsyncClient,] ) def test_application_service_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() @@ -107,16 +124,21 @@ def test_application_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 == "jobs.googleapis.com:443" def test_application_service_client_get_transport_class(): transport = ApplicationServiceClient.get_transport_class() - assert transport == transports.ApplicationServiceGrpcTransport + available_transports = [ + transports.ApplicationServiceGrpcTransport, + ] + assert transport in available_transports transport = ApplicationServiceClient.get_transport_class("grpc") assert transport == transports.ApplicationServiceGrpcTransport @@ -167,7 +189,7 @@ def test_application_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, ) @@ -183,7 +205,7 @@ def test_application_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, ) @@ -199,7 +221,7 @@ def test_application_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, ) @@ -227,7 +249,7 @@ def test_application_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, ) @@ -288,29 +310,25 @@ def test_application_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. @@ -319,66 +337,53 @@ def test_application_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", @@ -404,7 +409,7 @@ def test_application_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, ) @@ -434,7 +439,7 @@ def test_application_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, ) @@ -453,7 +458,7 @@ def test_application_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, ) @@ -525,6 +530,24 @@ def test_create_application_from_dict(): test_create_application(request_type=dict) +def test_create_application_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 = ApplicationServiceClient( + 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_application), "__call__" + ) as call: + client.create_application() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == application_service.CreateApplicationRequest() + + @pytest.mark.asyncio async def test_create_application_async( transport: str = "grpc_asyncio", @@ -805,6 +828,22 @@ def test_get_application_from_dict(): test_get_application(request_type=dict) +def test_get_application_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 = ApplicationServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_application), "__call__") as call: + client.get_application() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == application_service.GetApplicationRequest() + + @pytest.mark.asyncio async def test_get_application_async( transport: str = "grpc_asyncio", @@ -1063,6 +1102,24 @@ def test_update_application_from_dict(): test_update_application(request_type=dict) +def test_update_application_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 = ApplicationServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.update_application), "__call__" + ) as call: + client.update_application() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == application_service.UpdateApplicationRequest() + + @pytest.mark.asyncio async def test_update_application_async( transport: str = "grpc_asyncio", @@ -1309,6 +1366,24 @@ def test_delete_application_from_dict(): test_delete_application(request_type=dict) +def test_delete_application_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 = ApplicationServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.delete_application), "__call__" + ) as call: + client.delete_application() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == application_service.DeleteApplicationRequest() + + @pytest.mark.asyncio async def test_delete_application_async( transport: str = "grpc_asyncio", @@ -1513,6 +1588,24 @@ def test_list_applications_from_dict(): test_list_applications(request_type=dict) +def test_list_applications_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 = ApplicationServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_applications), "__call__" + ) as call: + client.list_applications() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == application_service.ListApplicationsRequest() + + @pytest.mark.asyncio async def test_list_applications_async( transport: str = "grpc_asyncio", @@ -2018,6 +2111,56 @@ def test_application_service_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [ + transports.ApplicationServiceGrpcTransport, + transports.ApplicationServiceGrpcAsyncIOTransport, + ], +) +def test_application_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", + "https://www.googleapis.com/auth/jobs", + ), + 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_application_service_host_no_port(): client = ApplicationServiceClient( credentials=credentials.AnonymousCredentials(), @@ -2037,7 +2180,7 @@ def test_application_service_host_with_port(): def test_application_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.ApplicationServiceGrpcTransport( @@ -2049,7 +2192,7 @@ def test_application_service_grpc_transport_channel(): def test_application_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.ApplicationServiceGrpcAsyncIOTransport( @@ -2060,6 +2203,8 @@ def test_application_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", [ @@ -2074,7 +2219,7 @@ def test_application_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 @@ -2115,6 +2260,8 @@ def test_application_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", [ @@ -2130,7 +2277,7 @@ def test_application_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/talent_v4beta1/test_company_service.py b/tests/unit/gapic/talent_v4beta1/test_company_service.py index 603a1904..973e425a 100644 --- a/tests/unit/gapic/talent_v4beta1/test_company_service.py +++ b/tests/unit/gapic/talent_v4beta1/test_company_service.py @@ -93,7 +93,24 @@ def test__get_default_mtls_endpoint(): @pytest.mark.parametrize( - "client_class", [CompanyServiceClient, CompanyServiceAsyncClient] + "client_class", [CompanyServiceClient, CompanyServiceAsyncClient,] +) +def test_company_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 == "jobs.googleapis.com:443" + + +@pytest.mark.parametrize( + "client_class", [CompanyServiceClient, CompanyServiceAsyncClient,] ) def test_company_service_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() @@ -103,16 +120,21 @@ def test_company_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 == "jobs.googleapis.com:443" def test_company_service_client_get_transport_class(): transport = CompanyServiceClient.get_transport_class() - assert transport == transports.CompanyServiceGrpcTransport + available_transports = [ + transports.CompanyServiceGrpcTransport, + ] + assert transport in available_transports transport = CompanyServiceClient.get_transport_class("grpc") assert transport == transports.CompanyServiceGrpcTransport @@ -163,7 +185,7 @@ def test_company_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, ) @@ -179,7 +201,7 @@ def test_company_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, ) @@ -195,7 +217,7 @@ def test_company_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, ) @@ -223,7 +245,7 @@ def test_company_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, ) @@ -274,29 +296,25 @@ def test_company_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. @@ -305,66 +323,53 @@ def test_company_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", @@ -390,7 +395,7 @@ def test_company_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, ) @@ -420,7 +425,7 @@ def test_company_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, ) @@ -439,7 +444,7 @@ def test_company_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, ) @@ -519,6 +524,22 @@ def test_create_company_from_dict(): test_create_company(request_type=dict) +def test_create_company_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 = CompanyServiceClient( + 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_company), "__call__") as call: + client.create_company() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == company_service.CreateCompanyRequest() + + @pytest.mark.asyncio async def test_create_company_async( transport: str = "grpc_asyncio", request_type=company_service.CreateCompanyRequest @@ -796,6 +817,22 @@ def test_get_company_from_dict(): test_get_company(request_type=dict) +def test_get_company_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 = CompanyServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_company), "__call__") as call: + client.get_company() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == company_service.GetCompanyRequest() + + @pytest.mark.asyncio async def test_get_company_async( transport: str = "grpc_asyncio", request_type=company_service.GetCompanyRequest @@ -1061,6 +1098,22 @@ def test_update_company_from_dict(): test_update_company(request_type=dict) +def test_update_company_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 = CompanyServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.update_company), "__call__") as call: + client.update_company() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == company_service.UpdateCompanyRequest() + + @pytest.mark.asyncio async def test_update_company_async( transport: str = "grpc_asyncio", request_type=company_service.UpdateCompanyRequest @@ -1292,6 +1345,22 @@ def test_delete_company_from_dict(): test_delete_company(request_type=dict) +def test_delete_company_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 = CompanyServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_company), "__call__") as call: + client.delete_company() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == company_service.DeleteCompanyRequest() + + @pytest.mark.asyncio async def test_delete_company_async( transport: str = "grpc_asyncio", request_type=company_service.DeleteCompanyRequest @@ -1477,6 +1546,22 @@ def test_list_companies_from_dict(): test_list_companies(request_type=dict) +def test_list_companies_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 = CompanyServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_companies), "__call__") as call: + client.list_companies() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == company_service.ListCompaniesRequest() + + @pytest.mark.asyncio async def test_list_companies_async( transport: str = "grpc_asyncio", request_type=company_service.ListCompaniesRequest @@ -1929,6 +2014,54 @@ def test_company_service_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [ + transports.CompanyServiceGrpcTransport, + transports.CompanyServiceGrpcAsyncIOTransport, + ], +) +def test_company_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", + "https://www.googleapis.com/auth/jobs", + ), + 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_company_service_host_no_port(): client = CompanyServiceClient( credentials=credentials.AnonymousCredentials(), @@ -1948,7 +2081,7 @@ def test_company_service_host_with_port(): def test_company_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.CompanyServiceGrpcTransport( @@ -1960,7 +2093,7 @@ def test_company_service_grpc_transport_channel(): def test_company_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.CompanyServiceGrpcAsyncIOTransport( @@ -1971,6 +2104,8 @@ def test_company_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", [ @@ -1985,7 +2120,7 @@ def test_company_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 @@ -2026,6 +2161,8 @@ def test_company_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", [ @@ -2041,7 +2178,7 @@ def test_company_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/talent_v4beta1/test_completion.py b/tests/unit/gapic/talent_v4beta1/test_completion.py index b03a7da9..48f3e828 100644 --- a/tests/unit/gapic/talent_v4beta1/test_completion.py +++ b/tests/unit/gapic/talent_v4beta1/test_completion.py @@ -81,7 +81,22 @@ def test__get_default_mtls_endpoint(): assert CompletionClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi -@pytest.mark.parametrize("client_class", [CompletionClient, CompletionAsyncClient]) +@pytest.mark.parametrize("client_class", [CompletionClient, CompletionAsyncClient,]) +def test_completion_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 == "jobs.googleapis.com:443" + + +@pytest.mark.parametrize("client_class", [CompletionClient, CompletionAsyncClient,]) def test_completion_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() with mock.patch.object( @@ -90,16 +105,21 @@ def test_completion_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 == "jobs.googleapis.com:443" def test_completion_client_get_transport_class(): transport = CompletionClient.get_transport_class() - assert transport == transports.CompletionGrpcTransport + available_transports = [ + transports.CompletionGrpcTransport, + ] + assert transport in available_transports transport = CompletionClient.get_transport_class("grpc") assert transport == transports.CompletionGrpcTransport @@ -148,7 +168,7 @@ def test_completion_client_client_options( credentials_file=None, host="squid.clam.whelk", scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -164,7 +184,7 @@ def test_completion_client_client_options( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -180,7 +200,7 @@ def test_completion_client_client_options( credentials_file=None, host=client.DEFAULT_MTLS_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -208,7 +228,7 @@ def test_completion_client_client_options( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id="octopus", client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -257,29 +277,25 @@ def test_completion_client_mtls_env_auto( client_cert_source=client_cert_source_callback ) with mock.patch.object(transport_class, "__init__") as patched: - ssl_channel_creds = mock.Mock() - with mock.patch( - "grpc.ssl_channel_credentials", return_value=ssl_channel_creds - ): - patched.return_value = None - client = client_class(client_options=options) + patched.return_value = None + client = client_class(client_options=options) - if use_client_cert_env == "false": - expected_ssl_channel_creds = None - expected_host = client.DEFAULT_ENDPOINT - else: - expected_ssl_channel_creds = ssl_channel_creds - expected_host = client.DEFAULT_MTLS_ENDPOINT + if use_client_cert_env == "false": + expected_client_cert_source = None + expected_host = client.DEFAULT_ENDPOINT + else: + expected_client_cert_source = client_cert_source_callback + expected_host = client.DEFAULT_MTLS_ENDPOINT - patched.assert_called_once_with( - credentials=None, - credentials_file=None, - host=expected_host, - scopes=None, - ssl_channel_credentials=expected_ssl_channel_creds, - quota_project_id=None, - client_info=transports.base.DEFAULT_CLIENT_INFO, - ) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=expected_host, + scopes=None, + client_cert_source_for_mtls=expected_client_cert_source, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) # Check the case ADC client cert is provided. Whether client cert is used depends on # GOOGLE_API_USE_CLIENT_CERTIFICATE value. @@ -288,66 +304,53 @@ def test_completion_client_mtls_env_auto( ): with mock.patch.object(transport_class, "__init__") as patched: with mock.patch( - "google.auth.transport.grpc.SslCredentials.__init__", return_value=None + "google.auth.transport.mtls.has_default_client_cert_source", + return_value=True, ): with mock.patch( - "google.auth.transport.grpc.SslCredentials.is_mtls", - new_callable=mock.PropertyMock, - ) as is_mtls_mock: - with mock.patch( - "google.auth.transport.grpc.SslCredentials.ssl_credentials", - new_callable=mock.PropertyMock, - ) as ssl_credentials_mock: - if use_client_cert_env == "false": - is_mtls_mock.return_value = False - ssl_credentials_mock.return_value = None - expected_host = client.DEFAULT_ENDPOINT - expected_ssl_channel_creds = None - else: - is_mtls_mock.return_value = True - ssl_credentials_mock.return_value = mock.Mock() - expected_host = client.DEFAULT_MTLS_ENDPOINT - expected_ssl_channel_creds = ( - ssl_credentials_mock.return_value - ) - - patched.return_value = None - client = client_class() - patched.assert_called_once_with( - credentials=None, - credentials_file=None, - host=expected_host, - scopes=None, - ssl_channel_credentials=expected_ssl_channel_creds, - quota_project_id=None, - client_info=transports.base.DEFAULT_CLIENT_INFO, - ) + "google.auth.transport.mtls.default_client_cert_source", + return_value=client_cert_source_callback, + ): + if use_client_cert_env == "false": + expected_host = client.DEFAULT_ENDPOINT + expected_client_cert_source = None + else: + expected_host = client.DEFAULT_MTLS_ENDPOINT + expected_client_cert_source = client_cert_source_callback - # Check the case client_cert_source and ADC client cert are not provided. - with mock.patch.dict( - os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env} - ): - with mock.patch.object(transport_class, "__init__") as patched: - with mock.patch( - "google.auth.transport.grpc.SslCredentials.__init__", return_value=None - ): - with mock.patch( - "google.auth.transport.grpc.SslCredentials.is_mtls", - new_callable=mock.PropertyMock, - ) as is_mtls_mock: - is_mtls_mock.return_value = False patched.return_value = None client = client_class() patched.assert_called_once_with( credentials=None, credentials_file=None, - host=client.DEFAULT_ENDPOINT, + host=expected_host, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=expected_client_cert_source, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) + # Check the case client_cert_source and ADC client cert are not provided. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env} + ): + with mock.patch.object(transport_class, "__init__") as patched: + with mock.patch( + "google.auth.transport.mtls.has_default_client_cert_source", + return_value=False, + ): + patched.return_value = None + client = client_class() + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) + @pytest.mark.parametrize( "client_class,transport_class,transport_name", @@ -373,7 +376,7 @@ def test_completion_client_client_options_scopes( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=["1", "2"], - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -403,7 +406,7 @@ def test_completion_client_client_options_credentials_file( credentials_file="credentials.json", host=client.DEFAULT_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -420,7 +423,7 @@ def test_completion_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, ) @@ -459,6 +462,22 @@ def test_complete_query_from_dict(): test_complete_query(request_type=dict) +def test_complete_query_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 = CompletionClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.complete_query), "__call__") as call: + client.complete_query() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == completion_service.CompleteQueryRequest() + + @pytest.mark.asyncio async def test_complete_query_async( transport: str = "grpc_asyncio", @@ -603,7 +622,7 @@ def test_transport_get_channel(): @pytest.mark.parametrize( "transport_class", - [transports.CompletionGrpcTransport, transports.CompletionGrpcAsyncIOTransport], + [transports.CompletionGrpcTransport, transports.CompletionGrpcAsyncIOTransport,], ) def test_transport_adc(transport_class): # Test default credentials are used if not provided. @@ -710,6 +729,51 @@ def test_completion_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [transports.CompletionGrpcTransport, transports.CompletionGrpcAsyncIOTransport], +) +def test_completion_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", + "https://www.googleapis.com/auth/jobs", + ), + 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_completion_host_no_port(): client = CompletionClient( credentials=credentials.AnonymousCredentials(), @@ -729,7 +793,7 @@ def test_completion_host_with_port(): def test_completion_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.CompletionGrpcTransport( @@ -741,7 +805,7 @@ def test_completion_grpc_transport_channel(): def test_completion_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.CompletionGrpcAsyncIOTransport( @@ -752,6 +816,8 @@ def test_completion_grpc_asyncio_transport_channel(): assert transport._ssl_channel_credentials == None +# Remove this test when deprecated arguments (api_mtls_endpoint, client_cert_source) are +# removed from grpc/grpc_asyncio transport constructor. @pytest.mark.parametrize( "transport_class", [transports.CompletionGrpcTransport, transports.CompletionGrpcAsyncIOTransport], @@ -761,7 +827,7 @@ def test_completion_transport_channel_mtls_with_client_cert_source(transport_cla "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 @@ -802,6 +868,8 @@ def test_completion_transport_channel_mtls_with_client_cert_source(transport_cla assert transport._ssl_channel_credentials == mock_ssl_cred +# Remove this test when deprecated arguments (api_mtls_endpoint, client_cert_source) are +# removed from grpc/grpc_asyncio transport constructor. @pytest.mark.parametrize( "transport_class", [transports.CompletionGrpcTransport, transports.CompletionGrpcAsyncIOTransport], @@ -814,7 +882,7 @@ def test_completion_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/talent_v4beta1/test_event_service.py b/tests/unit/gapic/talent_v4beta1/test_event_service.py index a5f2b7c0..16e25afe 100644 --- a/tests/unit/gapic/talent_v4beta1/test_event_service.py +++ b/tests/unit/gapic/talent_v4beta1/test_event_service.py @@ -82,7 +82,22 @@ def test__get_default_mtls_endpoint(): assert EventServiceClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi -@pytest.mark.parametrize("client_class", [EventServiceClient, EventServiceAsyncClient]) +@pytest.mark.parametrize("client_class", [EventServiceClient, EventServiceAsyncClient,]) +def test_event_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 == "jobs.googleapis.com:443" + + +@pytest.mark.parametrize("client_class", [EventServiceClient, EventServiceAsyncClient,]) def test_event_service_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() with mock.patch.object( @@ -91,16 +106,21 @@ def test_event_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 == "jobs.googleapis.com:443" def test_event_service_client_get_transport_class(): transport = EventServiceClient.get_transport_class() - assert transport == transports.EventServiceGrpcTransport + available_transports = [ + transports.EventServiceGrpcTransport, + ] + assert transport in available_transports transport = EventServiceClient.get_transport_class("grpc") assert transport == transports.EventServiceGrpcTransport @@ -149,7 +169,7 @@ def test_event_service_client_client_options( credentials_file=None, host="squid.clam.whelk", scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -165,7 +185,7 @@ def test_event_service_client_client_options( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -181,7 +201,7 @@ def test_event_service_client_client_options( credentials_file=None, host=client.DEFAULT_MTLS_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -209,7 +229,7 @@ def test_event_service_client_client_options( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id="octopus", client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -258,29 +278,25 @@ def test_event_service_client_mtls_env_auto( client_cert_source=client_cert_source_callback ) with mock.patch.object(transport_class, "__init__") as patched: - ssl_channel_creds = mock.Mock() - with mock.patch( - "grpc.ssl_channel_credentials", return_value=ssl_channel_creds - ): - patched.return_value = None - client = client_class(client_options=options) + patched.return_value = None + client = client_class(client_options=options) - if use_client_cert_env == "false": - expected_ssl_channel_creds = None - expected_host = client.DEFAULT_ENDPOINT - else: - expected_ssl_channel_creds = ssl_channel_creds - expected_host = client.DEFAULT_MTLS_ENDPOINT + if use_client_cert_env == "false": + expected_client_cert_source = None + expected_host = client.DEFAULT_ENDPOINT + else: + expected_client_cert_source = client_cert_source_callback + expected_host = client.DEFAULT_MTLS_ENDPOINT - patched.assert_called_once_with( - credentials=None, - credentials_file=None, - host=expected_host, - scopes=None, - ssl_channel_credentials=expected_ssl_channel_creds, - quota_project_id=None, - client_info=transports.base.DEFAULT_CLIENT_INFO, - ) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=expected_host, + scopes=None, + client_cert_source_for_mtls=expected_client_cert_source, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) # Check the case ADC client cert is provided. Whether client cert is used depends on # GOOGLE_API_USE_CLIENT_CERTIFICATE value. @@ -289,66 +305,53 @@ def test_event_service_client_mtls_env_auto( ): with mock.patch.object(transport_class, "__init__") as patched: with mock.patch( - "google.auth.transport.grpc.SslCredentials.__init__", return_value=None + "google.auth.transport.mtls.has_default_client_cert_source", + return_value=True, ): with mock.patch( - "google.auth.transport.grpc.SslCredentials.is_mtls", - new_callable=mock.PropertyMock, - ) as is_mtls_mock: - with mock.patch( - "google.auth.transport.grpc.SslCredentials.ssl_credentials", - new_callable=mock.PropertyMock, - ) as ssl_credentials_mock: - if use_client_cert_env == "false": - is_mtls_mock.return_value = False - ssl_credentials_mock.return_value = None - expected_host = client.DEFAULT_ENDPOINT - expected_ssl_channel_creds = None - else: - is_mtls_mock.return_value = True - ssl_credentials_mock.return_value = mock.Mock() - expected_host = client.DEFAULT_MTLS_ENDPOINT - expected_ssl_channel_creds = ( - ssl_credentials_mock.return_value - ) - - patched.return_value = None - client = client_class() - patched.assert_called_once_with( - credentials=None, - credentials_file=None, - host=expected_host, - scopes=None, - ssl_channel_credentials=expected_ssl_channel_creds, - quota_project_id=None, - client_info=transports.base.DEFAULT_CLIENT_INFO, - ) + "google.auth.transport.mtls.default_client_cert_source", + return_value=client_cert_source_callback, + ): + if use_client_cert_env == "false": + expected_host = client.DEFAULT_ENDPOINT + expected_client_cert_source = None + else: + expected_host = client.DEFAULT_MTLS_ENDPOINT + expected_client_cert_source = client_cert_source_callback - # Check the case client_cert_source and ADC client cert are not provided. - with mock.patch.dict( - os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env} - ): - with mock.patch.object(transport_class, "__init__") as patched: - with mock.patch( - "google.auth.transport.grpc.SslCredentials.__init__", return_value=None - ): - with mock.patch( - "google.auth.transport.grpc.SslCredentials.is_mtls", - new_callable=mock.PropertyMock, - ) as is_mtls_mock: - is_mtls_mock.return_value = False patched.return_value = None client = client_class() patched.assert_called_once_with( credentials=None, credentials_file=None, - host=client.DEFAULT_ENDPOINT, + host=expected_host, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=expected_client_cert_source, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) + # Check the case client_cert_source and ADC client cert are not provided. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env} + ): + with mock.patch.object(transport_class, "__init__") as patched: + with mock.patch( + "google.auth.transport.mtls.has_default_client_cert_source", + return_value=False, + ): + patched.return_value = None + client = client_class() + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) + @pytest.mark.parametrize( "client_class,transport_class,transport_name", @@ -374,7 +377,7 @@ def test_event_service_client_client_options_scopes( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=["1", "2"], - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -404,7 +407,7 @@ def test_event_service_client_client_options_credentials_file( credentials_file="credentials.json", host=client.DEFAULT_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -421,7 +424,7 @@ def test_event_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, ) @@ -473,6 +476,24 @@ def test_create_client_event_from_dict(): test_create_client_event(request_type=dict) +def test_create_client_event_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 = EventServiceClient( + 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_client_event), "__call__" + ) as call: + client.create_client_event() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == event_service.CreateClientEventRequest() + + @pytest.mark.asyncio async def test_create_client_event_async( transport: str = "grpc_asyncio", request_type=event_service.CreateClientEventRequest @@ -713,7 +734,10 @@ def test_transport_get_channel(): @pytest.mark.parametrize( "transport_class", - [transports.EventServiceGrpcTransport, transports.EventServiceGrpcAsyncIOTransport], + [ + transports.EventServiceGrpcTransport, + transports.EventServiceGrpcAsyncIOTransport, + ], ) def test_transport_adc(transport_class): # Test default credentials are used if not provided. @@ -820,6 +844,51 @@ def test_event_service_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [transports.EventServiceGrpcTransport, transports.EventServiceGrpcAsyncIOTransport], +) +def test_event_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", + "https://www.googleapis.com/auth/jobs", + ), + 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_event_service_host_no_port(): client = EventServiceClient( credentials=credentials.AnonymousCredentials(), @@ -839,7 +908,7 @@ def test_event_service_host_with_port(): def test_event_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.EventServiceGrpcTransport( @@ -851,7 +920,7 @@ def test_event_service_grpc_transport_channel(): def test_event_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.EventServiceGrpcAsyncIOTransport( @@ -862,6 +931,8 @@ def test_event_service_grpc_asyncio_transport_channel(): assert transport._ssl_channel_credentials == None +# Remove this test when deprecated arguments (api_mtls_endpoint, client_cert_source) are +# removed from grpc/grpc_asyncio transport constructor. @pytest.mark.parametrize( "transport_class", [transports.EventServiceGrpcTransport, transports.EventServiceGrpcAsyncIOTransport], @@ -871,7 +942,7 @@ def test_event_service_transport_channel_mtls_with_client_cert_source(transport_ "grpc.ssl_channel_credentials", autospec=True ) as grpc_ssl_channel_cred: with mock.patch.object( - transport_class, "create_channel", autospec=True + transport_class, "create_channel" ) as grpc_create_channel: mock_ssl_cred = mock.Mock() grpc_ssl_channel_cred.return_value = mock_ssl_cred @@ -912,6 +983,8 @@ def test_event_service_transport_channel_mtls_with_client_cert_source(transport_ assert transport._ssl_channel_credentials == mock_ssl_cred +# Remove this test when deprecated arguments (api_mtls_endpoint, client_cert_source) are +# removed from grpc/grpc_asyncio transport constructor. @pytest.mark.parametrize( "transport_class", [transports.EventServiceGrpcTransport, transports.EventServiceGrpcAsyncIOTransport], @@ -924,7 +997,7 @@ def test_event_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/talent_v4beta1/test_job_service.py b/tests/unit/gapic/talent_v4beta1/test_job_service.py index 43896c99..db29e42b 100644 --- a/tests/unit/gapic/talent_v4beta1/test_job_service.py +++ b/tests/unit/gapic/talent_v4beta1/test_job_service.py @@ -98,7 +98,22 @@ def test__get_default_mtls_endpoint(): assert JobServiceClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi -@pytest.mark.parametrize("client_class", [JobServiceClient, JobServiceAsyncClient]) +@pytest.mark.parametrize("client_class", [JobServiceClient, JobServiceAsyncClient,]) +def test_job_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 == "jobs.googleapis.com:443" + + +@pytest.mark.parametrize("client_class", [JobServiceClient, JobServiceAsyncClient,]) def test_job_service_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() with mock.patch.object( @@ -107,16 +122,21 @@ def test_job_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 == "jobs.googleapis.com:443" def test_job_service_client_get_transport_class(): transport = JobServiceClient.get_transport_class() - assert transport == transports.JobServiceGrpcTransport + available_transports = [ + transports.JobServiceGrpcTransport, + ] + assert transport in available_transports transport = JobServiceClient.get_transport_class("grpc") assert transport == transports.JobServiceGrpcTransport @@ -165,7 +185,7 @@ def test_job_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, ) @@ -181,7 +201,7 @@ def test_job_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, ) @@ -197,7 +217,7 @@ def test_job_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, ) @@ -225,7 +245,7 @@ def test_job_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, ) @@ -274,29 +294,25 @@ def test_job_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. @@ -305,66 +321,53 @@ def test_job_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", @@ -390,7 +393,7 @@ def test_job_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, ) @@ -420,7 +423,7 @@ def test_job_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, ) @@ -437,7 +440,7 @@ def test_job_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, ) @@ -532,6 +535,22 @@ def test_create_job_from_dict(): test_create_job(request_type=dict) +def test_create_job_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = JobServiceClient( + 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_job), "__call__") as call: + client.create_job() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == job_service.CreateJobRequest() + + @pytest.mark.asyncio async def test_create_job_async( transport: str = "grpc_asyncio", request_type=job_service.CreateJobRequest @@ -786,6 +805,24 @@ def test_batch_create_jobs_from_dict(): test_batch_create_jobs(request_type=dict) +def test_batch_create_jobs_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = JobServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.batch_create_jobs), "__call__" + ) as call: + client.batch_create_jobs() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == job_service.BatchCreateJobsRequest() + + @pytest.mark.asyncio async def test_batch_create_jobs_async( transport: str = "grpc_asyncio", request_type=job_service.BatchCreateJobsRequest @@ -1051,6 +1088,22 @@ def test_get_job_from_dict(): test_get_job(request_type=dict) +def test_get_job_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = JobServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_job), "__call__") as call: + client.get_job() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == job_service.GetJobRequest() + + @pytest.mark.asyncio async def test_get_job_async( transport: str = "grpc_asyncio", request_type=job_service.GetJobRequest @@ -1348,6 +1401,22 @@ def test_update_job_from_dict(): test_update_job(request_type=dict) +def test_update_job_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = JobServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.update_job), "__call__") as call: + client.update_job() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == job_service.UpdateJobRequest() + + @pytest.mark.asyncio async def test_update_job_async( transport: str = "grpc_asyncio", request_type=job_service.UpdateJobRequest @@ -1590,6 +1659,24 @@ def test_batch_update_jobs_from_dict(): test_batch_update_jobs(request_type=dict) +def test_batch_update_jobs_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = JobServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.batch_update_jobs), "__call__" + ) as call: + client.batch_update_jobs() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == job_service.BatchUpdateJobsRequest() + + @pytest.mark.asyncio async def test_batch_update_jobs_async( transport: str = "grpc_asyncio", request_type=job_service.BatchUpdateJobsRequest @@ -1796,6 +1883,22 @@ def test_delete_job_from_dict(): test_delete_job(request_type=dict) +def test_delete_job_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = JobServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_job), "__call__") as call: + client.delete_job() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == job_service.DeleteJobRequest() + + @pytest.mark.asyncio async def test_delete_job_async( transport: str = "grpc_asyncio", request_type=job_service.DeleteJobRequest @@ -1978,6 +2081,24 @@ def test_batch_delete_jobs_from_dict(): test_batch_delete_jobs(request_type=dict) +def test_batch_delete_jobs_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = JobServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.batch_delete_jobs), "__call__" + ) as call: + client.batch_delete_jobs() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == job_service.BatchDeleteJobsRequest() + + @pytest.mark.asyncio async def test_batch_delete_jobs_async( transport: str = "grpc_asyncio", request_type=job_service.BatchDeleteJobsRequest @@ -2183,6 +2304,22 @@ def test_list_jobs_from_dict(): test_list_jobs(request_type=dict) +def test_list_jobs_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = JobServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_jobs), "__call__") as call: + client.list_jobs() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == job_service.ListJobsRequest() + + @pytest.mark.asyncio async def test_list_jobs_async( transport: str = "grpc_asyncio", request_type=job_service.ListJobsRequest @@ -2493,6 +2630,22 @@ def test_search_jobs_from_dict(): test_search_jobs(request_type=dict) +def test_search_jobs_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = JobServiceClient( + 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_jobs), "__call__") as call: + client.search_jobs() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == job_service.SearchJobsRequest() + + @pytest.mark.asyncio async def test_search_jobs_async( transport: str = "grpc_asyncio", request_type=job_service.SearchJobsRequest @@ -2799,6 +2952,24 @@ def test_search_jobs_for_alert_from_dict(): test_search_jobs_for_alert(request_type=dict) +def test_search_jobs_for_alert_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 = JobServiceClient( + 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_jobs_for_alert), "__call__" + ) as call: + client.search_jobs_for_alert() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == job_service.SearchJobsRequest() + + @pytest.mark.asyncio async def test_search_jobs_for_alert_async( transport: str = "grpc_asyncio", request_type=job_service.SearchJobsRequest @@ -3127,7 +3298,7 @@ def test_transport_get_channel(): @pytest.mark.parametrize( "transport_class", - [transports.JobServiceGrpcTransport, transports.JobServiceGrpcAsyncIOTransport], + [transports.JobServiceGrpcTransport, transports.JobServiceGrpcAsyncIOTransport,], ) def test_transport_adc(transport_class): # Test default credentials are used if not provided. @@ -3250,6 +3421,51 @@ def test_job_service_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [transports.JobServiceGrpcTransport, transports.JobServiceGrpcAsyncIOTransport], +) +def test_job_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", + "https://www.googleapis.com/auth/jobs", + ), + 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_job_service_host_no_port(): client = JobServiceClient( credentials=credentials.AnonymousCredentials(), @@ -3269,7 +3485,7 @@ def test_job_service_host_with_port(): def test_job_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.JobServiceGrpcTransport( @@ -3281,7 +3497,7 @@ def test_job_service_grpc_transport_channel(): def test_job_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.JobServiceGrpcAsyncIOTransport( @@ -3292,6 +3508,8 @@ def test_job_service_grpc_asyncio_transport_channel(): assert transport._ssl_channel_credentials == None +# Remove this test when deprecated arguments (api_mtls_endpoint, client_cert_source) are +# removed from grpc/grpc_asyncio transport constructor. @pytest.mark.parametrize( "transport_class", [transports.JobServiceGrpcTransport, transports.JobServiceGrpcAsyncIOTransport], @@ -3301,7 +3519,7 @@ def test_job_service_transport_channel_mtls_with_client_cert_source(transport_cl "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 @@ -3342,6 +3560,8 @@ def test_job_service_transport_channel_mtls_with_client_cert_source(transport_cl assert transport._ssl_channel_credentials == mock_ssl_cred +# Remove this test when deprecated arguments (api_mtls_endpoint, client_cert_source) are +# removed from grpc/grpc_asyncio transport constructor. @pytest.mark.parametrize( "transport_class", [transports.JobServiceGrpcTransport, transports.JobServiceGrpcAsyncIOTransport], @@ -3354,7 +3574,7 @@ def test_job_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/talent_v4beta1/test_profile_service.py b/tests/unit/gapic/talent_v4beta1/test_profile_service.py index 136e0be1..843a00c4 100644 --- a/tests/unit/gapic/talent_v4beta1/test_profile_service.py +++ b/tests/unit/gapic/talent_v4beta1/test_profile_service.py @@ -99,7 +99,24 @@ def test__get_default_mtls_endpoint(): @pytest.mark.parametrize( - "client_class", [ProfileServiceClient, ProfileServiceAsyncClient] + "client_class", [ProfileServiceClient, ProfileServiceAsyncClient,] +) +def test_profile_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 == "jobs.googleapis.com:443" + + +@pytest.mark.parametrize( + "client_class", [ProfileServiceClient, ProfileServiceAsyncClient,] ) def test_profile_service_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() @@ -109,16 +126,21 @@ def test_profile_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 == "jobs.googleapis.com:443" def test_profile_service_client_get_transport_class(): transport = ProfileServiceClient.get_transport_class() - assert transport == transports.ProfileServiceGrpcTransport + available_transports = [ + transports.ProfileServiceGrpcTransport, + ] + assert transport in available_transports transport = ProfileServiceClient.get_transport_class("grpc") assert transport == transports.ProfileServiceGrpcTransport @@ -169,7 +191,7 @@ def test_profile_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, ) @@ -185,7 +207,7 @@ def test_profile_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, ) @@ -201,7 +223,7 @@ def test_profile_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, ) @@ -229,7 +251,7 @@ def test_profile_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, ) @@ -280,29 +302,25 @@ def test_profile_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. @@ -311,66 +329,53 @@ def test_profile_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", @@ -396,7 +401,7 @@ def test_profile_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, ) @@ -426,7 +431,7 @@ def test_profile_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, ) @@ -445,7 +450,7 @@ def test_profile_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, ) @@ -488,6 +493,22 @@ def test_list_profiles_from_dict(): test_list_profiles(request_type=dict) +def test_list_profiles_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 = ProfileServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_profiles), "__call__") as call: + client.list_profiles() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == profile_service.ListProfilesRequest() + + @pytest.mark.asyncio async def test_list_profiles_async( transport: str = "grpc_asyncio", request_type=profile_service.ListProfilesRequest @@ -829,6 +850,22 @@ def test_create_profile_from_dict(): test_create_profile(request_type=dict) +def test_create_profile_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 = ProfileServiceClient( + 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_profile), "__call__") as call: + client.create_profile() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == profile_service.CreateProfileRequest() + + @pytest.mark.asyncio async def test_create_profile_async( transport: str = "grpc_asyncio", request_type=profile_service.CreateProfileRequest @@ -1080,6 +1117,22 @@ def test_get_profile_from_dict(): test_get_profile(request_type=dict) +def test_get_profile_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 = ProfileServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_profile), "__call__") as call: + client.get_profile() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == profile_service.GetProfileRequest() + + @pytest.mark.asyncio async def test_get_profile_async( transport: str = "grpc_asyncio", request_type=profile_service.GetProfileRequest @@ -1319,6 +1372,22 @@ def test_update_profile_from_dict(): test_update_profile(request_type=dict) +def test_update_profile_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 = ProfileServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.update_profile), "__call__") as call: + client.update_profile() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == profile_service.UpdateProfileRequest() + + @pytest.mark.asyncio async def test_update_profile_async( transport: str = "grpc_asyncio", request_type=profile_service.UpdateProfileRequest @@ -1537,6 +1606,22 @@ def test_delete_profile_from_dict(): test_delete_profile(request_type=dict) +def test_delete_profile_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 = ProfileServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_profile), "__call__") as call: + client.delete_profile() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == profile_service.DeleteProfileRequest() + + @pytest.mark.asyncio async def test_delete_profile_async( transport: str = "grpc_asyncio", request_type=profile_service.DeleteProfileRequest @@ -1728,6 +1813,22 @@ def test_search_profiles_from_dict(): test_search_profiles(request_type=dict) +def test_search_profiles_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 = ProfileServiceClient( + 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_profiles), "__call__") as call: + client.search_profiles() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == profile_service.SearchProfilesRequest() + + @pytest.mark.asyncio async def test_search_profiles_async( transport: str = "grpc_asyncio", request_type=profile_service.SearchProfilesRequest @@ -2160,6 +2261,54 @@ def test_profile_service_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [ + transports.ProfileServiceGrpcTransport, + transports.ProfileServiceGrpcAsyncIOTransport, + ], +) +def test_profile_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", + "https://www.googleapis.com/auth/jobs", + ), + 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_profile_service_host_no_port(): client = ProfileServiceClient( credentials=credentials.AnonymousCredentials(), @@ -2179,7 +2328,7 @@ def test_profile_service_host_with_port(): def test_profile_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.ProfileServiceGrpcTransport( @@ -2191,7 +2340,7 @@ def test_profile_service_grpc_transport_channel(): def test_profile_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.ProfileServiceGrpcAsyncIOTransport( @@ -2202,6 +2351,8 @@ def test_profile_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", [ @@ -2216,7 +2367,7 @@ def test_profile_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 @@ -2257,6 +2408,8 @@ def test_profile_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", [ @@ -2272,7 +2425,7 @@ def test_profile_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/talent_v4beta1/test_tenant_service.py b/tests/unit/gapic/talent_v4beta1/test_tenant_service.py index 62a13dd4..e4e6acc6 100644 --- a/tests/unit/gapic/talent_v4beta1/test_tenant_service.py +++ b/tests/unit/gapic/talent_v4beta1/test_tenant_service.py @@ -88,7 +88,24 @@ def test__get_default_mtls_endpoint(): @pytest.mark.parametrize( - "client_class", [TenantServiceClient, TenantServiceAsyncClient] + "client_class", [TenantServiceClient, TenantServiceAsyncClient,] +) +def test_tenant_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 == "jobs.googleapis.com:443" + + +@pytest.mark.parametrize( + "client_class", [TenantServiceClient, TenantServiceAsyncClient,] ) def test_tenant_service_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() @@ -98,16 +115,21 @@ def test_tenant_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 == "jobs.googleapis.com:443" def test_tenant_service_client_get_transport_class(): transport = TenantServiceClient.get_transport_class() - assert transport == transports.TenantServiceGrpcTransport + available_transports = [ + transports.TenantServiceGrpcTransport, + ] + assert transport in available_transports transport = TenantServiceClient.get_transport_class("grpc") assert transport == transports.TenantServiceGrpcTransport @@ -158,7 +180,7 @@ def test_tenant_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, ) @@ -174,7 +196,7 @@ def test_tenant_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, ) @@ -190,7 +212,7 @@ def test_tenant_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, ) @@ -218,7 +240,7 @@ def test_tenant_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, ) @@ -269,29 +291,25 @@ def test_tenant_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. @@ -300,66 +318,53 @@ def test_tenant_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", @@ -385,7 +390,7 @@ def test_tenant_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, ) @@ -415,7 +420,7 @@ def test_tenant_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, ) @@ -434,7 +439,7 @@ def test_tenant_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, ) @@ -490,6 +495,22 @@ def test_create_tenant_from_dict(): test_create_tenant(request_type=dict) +def test_create_tenant_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 = TenantServiceClient( + 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_tenant), "__call__") as call: + client.create_tenant() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == tenant_service.CreateTenantRequest() + + @pytest.mark.asyncio async def test_create_tenant_async( transport: str = "grpc_asyncio", request_type=tenant_service.CreateTenantRequest @@ -719,6 +740,22 @@ def test_get_tenant_from_dict(): test_get_tenant(request_type=dict) +def test_get_tenant_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 = TenantServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_tenant), "__call__") as call: + client.get_tenant() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == tenant_service.GetTenantRequest() + + @pytest.mark.asyncio async def test_get_tenant_async( transport: str = "grpc_asyncio", request_type=tenant_service.GetTenantRequest @@ -936,6 +973,22 @@ def test_update_tenant_from_dict(): test_update_tenant(request_type=dict) +def test_update_tenant_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 = TenantServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.update_tenant), "__call__") as call: + client.update_tenant() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == tenant_service.UpdateTenantRequest() + + @pytest.mark.asyncio async def test_update_tenant_async( transport: str = "grpc_asyncio", request_type=tenant_service.UpdateTenantRequest @@ -1139,6 +1192,22 @@ def test_delete_tenant_from_dict(): test_delete_tenant(request_type=dict) +def test_delete_tenant_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 = TenantServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_tenant), "__call__") as call: + client.delete_tenant() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == tenant_service.DeleteTenantRequest() + + @pytest.mark.asyncio async def test_delete_tenant_async( transport: str = "grpc_asyncio", request_type=tenant_service.DeleteTenantRequest @@ -1324,6 +1393,22 @@ def test_list_tenants_from_dict(): test_list_tenants(request_type=dict) +def test_list_tenants_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 = TenantServiceClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_tenants), "__call__") as call: + client.list_tenants() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == tenant_service.ListTenantsRequest() + + @pytest.mark.asyncio async def test_list_tenants_async( transport: str = "grpc_asyncio", request_type=tenant_service.ListTenantsRequest @@ -1774,6 +1859,54 @@ def test_tenant_service_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [ + transports.TenantServiceGrpcTransport, + transports.TenantServiceGrpcAsyncIOTransport, + ], +) +def test_tenant_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", + "https://www.googleapis.com/auth/jobs", + ), + 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_tenant_service_host_no_port(): client = TenantServiceClient( credentials=credentials.AnonymousCredentials(), @@ -1793,7 +1926,7 @@ def test_tenant_service_host_with_port(): def test_tenant_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.TenantServiceGrpcTransport( @@ -1805,7 +1938,7 @@ def test_tenant_service_grpc_transport_channel(): def test_tenant_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.TenantServiceGrpcAsyncIOTransport( @@ -1816,6 +1949,8 @@ def test_tenant_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", [ @@ -1828,7 +1963,7 @@ def test_tenant_service_transport_channel_mtls_with_client_cert_source(transport "grpc.ssl_channel_credentials", autospec=True ) as grpc_ssl_channel_cred: with mock.patch.object( - transport_class, "create_channel", autospec=True + transport_class, "create_channel" ) as grpc_create_channel: mock_ssl_cred = mock.Mock() grpc_ssl_channel_cred.return_value = mock_ssl_cred @@ -1869,6 +2004,8 @@ def test_tenant_service_transport_channel_mtls_with_client_cert_source(transport assert transport._ssl_channel_credentials == mock_ssl_cred +# Remove this test when deprecated arguments (api_mtls_endpoint, client_cert_source) are +# removed from grpc/grpc_asyncio transport constructor. @pytest.mark.parametrize( "transport_class", [ @@ -1884,7 +2021,7 @@ def test_tenant_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