From d9bd192a87bc8a4462da3bdbda362b359d86dd65 Mon Sep 17 00:00:00 2001 From: Yoshi Automation Bot Date: Thu, 4 Mar 2021 16:29:30 -0800 Subject: [PATCH] chore: re-generate (#41) feat: allow to disable webhook invocation per request feat: added support for test cases and agent validation feat: supports SentimentAnalysisResult in webhook request feat: add from_service_account_info factory feat: Add new Experiment service docs: test cases doc update docs: update languages link --- .coveragerc | 18 + .github/header-checker-lint.yml | 15 + .gitignore | 4 +- .kokoro/build.sh | 26 +- .kokoro/docs/docs-presubmit.cfg | 11 + .trampolinerc | 1 + CONTRIBUTING.rst | 22 +- LICENSE | 7 +- MANIFEST.in | 4 +- README.rst | 45 +- docs/_static/custom.css | 7 +- docs/dialogflowcx_v3/agents.rst | 11 + docs/dialogflowcx_v3/entity_types.rst | 11 + docs/dialogflowcx_v3/environments.rst | 11 + docs/dialogflowcx_v3/experiments.rst | 11 + docs/dialogflowcx_v3/flows.rst | 11 + docs/dialogflowcx_v3/intents.rst | 11 + docs/dialogflowcx_v3/pages.rst | 11 + .../security_settings_service.rst | 11 + docs/dialogflowcx_v3/services.rst | 55 +- docs/dialogflowcx_v3/session_entity_types.rst | 11 + docs/dialogflowcx_v3/sessions.rst | 6 + docs/dialogflowcx_v3/test_cases.rst | 11 + .../transition_route_groups.rst | 11 + docs/dialogflowcx_v3/types.rst | 1 + docs/dialogflowcx_v3/versions.rst | 11 + docs/dialogflowcx_v3/webhooks.rst | 11 + docs/dialogflowcx_v3beta1/agents.rst | 11 + docs/dialogflowcx_v3beta1/entity_types.rst | 11 + docs/dialogflowcx_v3beta1/environments.rst | 11 + docs/dialogflowcx_v3beta1/experiments.rst | 11 + docs/dialogflowcx_v3beta1/flows.rst | 11 + docs/dialogflowcx_v3beta1/intents.rst | 11 + docs/dialogflowcx_v3beta1/pages.rst | 11 + .../security_settings_service.rst | 11 + docs/dialogflowcx_v3beta1/services.rst | 55 +- .../session_entity_types.rst | 11 + docs/dialogflowcx_v3beta1/sessions.rst | 6 + docs/dialogflowcx_v3beta1/test_cases.rst | 11 + .../transition_route_groups.rst | 11 + docs/dialogflowcx_v3beta1/types.rst | 1 + docs/dialogflowcx_v3beta1/versions.rst | 11 + docs/dialogflowcx_v3beta1/webhooks.rst | 11 + google/cloud/dialogflowcx/__init__.py | 88 + google/cloud/dialogflowcx_v3/__init__.py | 88 +- .../services/agents/async_client.py | 318 +- .../dialogflowcx_v3/services/agents/client.py | 377 +- .../dialogflowcx_v3/services/agents/pagers.py | 27 +- .../services/agents/transports/base.py | 30 + .../services/agents/transports/grpc.py | 79 +- .../agents/transports/grpc_asyncio.py | 81 +- .../services/entity_types/async_client.py | 267 +- .../services/entity_types/client.py | 284 +- .../services/entity_types/pagers.py | 27 +- .../services/entity_types/transports/grpc.py | 23 +- .../entity_types/transports/grpc_asyncio.py | 23 +- .../services/environments/async_client.py | 111 +- .../services/environments/client.py | 130 +- .../services/environments/pagers.py | 43 +- .../services/environments/transports/grpc.py | 23 +- .../environments/transports/grpc_asyncio.py | 23 +- .../services/experiments/async_client.py | 80 +- .../services/experiments/client.py | 101 +- .../services/experiments/pagers.py | 27 +- .../services/experiments/transports/grpc.py | 23 +- .../experiments/transports/grpc_asyncio.py | 23 +- .../services/flows/async_client.py | 221 +- .../dialogflowcx_v3/services/flows/client.py | 258 +- .../dialogflowcx_v3/services/flows/pagers.py | 27 +- .../services/flows/transports/base.py | 30 + .../services/flows/transports/grpc.py | 79 +- .../services/flows/transports/grpc_asyncio.py | 81 +- .../services/intents/async_client.py | 60 +- .../services/intents/client.py | 77 +- .../services/intents/pagers.py | 27 +- .../services/intents/transports/grpc.py | 23 +- .../intents/transports/grpc_asyncio.py | 23 +- .../services/pages/async_client.py | 189 +- .../dialogflowcx_v3/services/pages/client.py | 206 +- .../dialogflowcx_v3/services/pages/pagers.py | 27 +- .../services/pages/transports/grpc.py | 23 +- .../services/pages/transports/grpc_asyncio.py | 23 +- .../security_settings_service/async_client.py | 62 +- .../security_settings_service/client.py | 79 +- .../security_settings_service/pagers.py | 27 +- .../transports/grpc.py | 23 +- .../transports/grpc_asyncio.py | 23 +- .../session_entity_types/async_client.py | 143 +- .../services/session_entity_types/client.py | 160 +- .../services/session_entity_types/pagers.py | 27 +- .../session_entity_types/transports/grpc.py | 23 +- .../transports/grpc_asyncio.py | 23 +- .../services/sessions/async_client.py | 65 +- .../services/sessions/client.py | 74 +- .../services/sessions/transports/grpc.py | 23 +- .../sessions/transports/grpc_asyncio.py | 23 +- .../services/test_cases/__init__.py | 24 + .../services/test_cases/async_client.py | 984 +++++ .../services/test_cases/client.py | 1311 ++++++ .../services/test_cases/pagers.py | 285 ++ .../test_cases/transports/__init__.py | 35 + .../services/test_cases/transports/base.py | 275 ++ .../services/test_cases/transports/grpc.py | 568 +++ .../test_cases/transports/grpc_asyncio.py | 584 +++ .../transition_route_groups/async_client.py | 80 +- .../transition_route_groups/client.py | 97 +- .../transition_route_groups/pagers.py | 27 +- .../transports/grpc.py | 23 +- .../transports/grpc_asyncio.py | 23 +- .../services/versions/async_client.py | 91 +- .../services/versions/client.py | 110 +- .../services/versions/pagers.py | 27 +- .../services/versions/transports/grpc.py | 23 +- .../versions/transports/grpc_asyncio.py | 23 +- .../services/webhooks/async_client.py | 60 +- .../services/webhooks/client.py | 77 +- .../services/webhooks/pagers.py | 27 +- .../services/webhooks/transports/grpc.py | 23 +- .../webhooks/transports/grpc_asyncio.py | 23 +- .../cloud/dialogflowcx_v3/types/__init__.py | 86 + google/cloud/dialogflowcx_v3/types/agent.py | 79 +- .../dialogflowcx_v3/types/audio_config.py | 24 +- .../dialogflowcx_v3/types/entity_type.py | 34 +- .../dialogflowcx_v3/types/environment.py | 14 +- .../cloud/dialogflowcx_v3/types/experiment.py | 69 +- google/cloud/dialogflowcx_v3/types/flow.py | 90 +- .../dialogflowcx_v3/types/fulfillment.py | 16 +- google/cloud/dialogflowcx_v3/types/intent.py | 38 +- google/cloud/dialogflowcx_v3/types/page.py | 59 +- .../dialogflowcx_v3/types/response_message.py | 30 +- .../types/security_settings.py | 14 +- google/cloud/dialogflowcx_v3/types/session.py | 99 +- .../types/session_entity_type.py | 12 +- .../cloud/dialogflowcx_v3/types/test_case.py | 1001 +++++ .../types/transition_route_group.py | 25 +- .../types/validation_message.py | 98 + google/cloud/dialogflowcx_v3/types/version.py | 14 +- google/cloud/dialogflowcx_v3/types/webhook.py | 96 +- google/cloud/dialogflowcx_v3beta1/__init__.py | 88 +- .../services/agents/async_client.py | 321 +- .../services/agents/client.py | 380 +- .../services/agents/pagers.py | 27 +- .../services/agents/transports/base.py | 30 + .../services/agents/transports/grpc.py | 79 +- .../agents/transports/grpc_asyncio.py | 81 +- .../services/entity_types/async_client.py | 267 +- .../services/entity_types/client.py | 284 +- .../services/entity_types/pagers.py | 27 +- .../services/entity_types/transports/grpc.py | 23 +- .../entity_types/transports/grpc_asyncio.py | 23 +- .../services/environments/async_client.py | 111 +- .../services/environments/client.py | 130 +- .../services/environments/pagers.py | 43 +- .../services/environments/transports/grpc.py | 23 +- .../environments/transports/grpc_asyncio.py | 23 +- .../services/experiments/async_client.py | 80 +- .../services/experiments/client.py | 101 +- .../services/experiments/pagers.py | 27 +- .../services/experiments/transports/grpc.py | 23 +- .../experiments/transports/grpc_asyncio.py | 23 +- .../services/flows/async_client.py | 221 +- .../services/flows/client.py | 258 +- .../services/flows/pagers.py | 27 +- .../services/flows/transports/base.py | 30 + .../services/flows/transports/grpc.py | 79 +- .../services/flows/transports/grpc_asyncio.py | 81 +- .../services/intents/async_client.py | 60 +- .../services/intents/client.py | 77 +- .../services/intents/pagers.py | 27 +- .../services/intents/transports/grpc.py | 23 +- .../intents/transports/grpc_asyncio.py | 23 +- .../services/pages/async_client.py | 189 +- .../services/pages/client.py | 206 +- .../services/pages/pagers.py | 27 +- .../services/pages/transports/grpc.py | 23 +- .../services/pages/transports/grpc_asyncio.py | 23 +- .../security_settings_service/async_client.py | 62 +- .../security_settings_service/client.py | 79 +- .../security_settings_service/pagers.py | 27 +- .../transports/grpc.py | 23 +- .../transports/grpc_asyncio.py | 23 +- .../session_entity_types/async_client.py | 146 +- .../services/session_entity_types/client.py | 163 +- .../services/session_entity_types/pagers.py | 27 +- .../session_entity_types/transports/grpc.py | 23 +- .../transports/grpc_asyncio.py | 23 +- .../services/sessions/async_client.py | 65 +- .../services/sessions/client.py | 74 +- .../services/sessions/transports/grpc.py | 23 +- .../sessions/transports/grpc_asyncio.py | 23 +- .../services/test_cases/__init__.py | 24 + .../services/test_cases/async_client.py | 984 +++++ .../services/test_cases/client.py | 1311 ++++++ .../services/test_cases/pagers.py | 285 ++ .../test_cases/transports/__init__.py | 35 + .../services/test_cases/transports/base.py | 275 ++ .../services/test_cases/transports/grpc.py | 568 +++ .../test_cases/transports/grpc_asyncio.py | 584 +++ .../transition_route_groups/async_client.py | 80 +- .../transition_route_groups/client.py | 97 +- .../transition_route_groups/pagers.py | 27 +- .../transports/grpc.py | 23 +- .../transports/grpc_asyncio.py | 23 +- .../services/versions/async_client.py | 91 +- .../services/versions/client.py | 110 +- .../services/versions/pagers.py | 27 +- .../services/versions/transports/grpc.py | 23 +- .../versions/transports/grpc_asyncio.py | 23 +- .../services/webhooks/async_client.py | 60 +- .../services/webhooks/client.py | 77 +- .../services/webhooks/pagers.py | 27 +- .../services/webhooks/transports/grpc.py | 23 +- .../webhooks/transports/grpc_asyncio.py | 23 +- .../dialogflowcx_v3beta1/types/__init__.py | 86 + .../cloud/dialogflowcx_v3beta1/types/agent.py | 79 +- .../types/audio_config.py | 20 +- .../dialogflowcx_v3beta1/types/entity_type.py | 34 +- .../dialogflowcx_v3beta1/types/environment.py | 14 +- .../dialogflowcx_v3beta1/types/experiment.py | 69 +- .../cloud/dialogflowcx_v3beta1/types/flow.py | 90 +- .../dialogflowcx_v3beta1/types/fulfillment.py | 16 +- .../dialogflowcx_v3beta1/types/intent.py | 38 +- .../cloud/dialogflowcx_v3beta1/types/page.py | 59 +- .../types/response_message.py | 82 +- .../types/security_settings.py | 14 +- .../dialogflowcx_v3beta1/types/session.py | 99 +- .../types/session_entity_type.py | 12 +- .../dialogflowcx_v3beta1/types/test_case.py | 1003 +++++ .../types/transition_route_group.py | 25 +- .../types/validation_message.py | 98 + .../dialogflowcx_v3beta1/types/version.py | 14 +- .../dialogflowcx_v3beta1/types/webhook.py | 96 +- noxfile.py | 32 +- synth.metadata | 359 +- tests/unit/gapic/dialogflowcx_v3/__init__.py | 15 + .../unit/gapic/dialogflowcx_v3/test_agents.py | 823 +++- .../dialogflowcx_v3/test_entity_types.py | 322 +- .../dialogflowcx_v3/test_environments.py | 325 +- .../gapic/dialogflowcx_v3/test_experiments.py | 334 +- .../unit/gapic/dialogflowcx_v3/test_flows.py | 774 +++- .../gapic/dialogflowcx_v3/test_intents.py | 296 +- .../unit/gapic/dialogflowcx_v3/test_pages.py | 296 +- .../test_security_settings_service.py | 311 +- .../test_session_entity_types.py | 311 +- .../gapic/dialogflowcx_v3/test_sessions.py | 264 +- .../gapic/dialogflowcx_v3/test_test_cases.py | 3630 +++++++++++++++++ .../test_transition_route_groups.py | 315 +- .../gapic/dialogflowcx_v3/test_versions.py | 312 +- .../gapic/dialogflowcx_v3/test_webhooks.py | 296 +- .../gapic/dialogflowcx_v3beta1/__init__.py | 15 + .../gapic/dialogflowcx_v3beta1/test_agents.py | 823 +++- .../dialogflowcx_v3beta1/test_entity_types.py | 322 +- .../dialogflowcx_v3beta1/test_environments.py | 325 +- .../dialogflowcx_v3beta1/test_experiments.py | 334 +- .../gapic/dialogflowcx_v3beta1/test_flows.py | 774 +++- .../dialogflowcx_v3beta1/test_intents.py | 296 +- .../gapic/dialogflowcx_v3beta1/test_pages.py | 296 +- .../test_security_settings_service.py | 311 +- .../test_session_entity_types.py | 311 +- .../dialogflowcx_v3beta1/test_sessions.py | 264 +- .../dialogflowcx_v3beta1/test_test_cases.py | 3630 +++++++++++++++++ .../test_transition_route_groups.py | 315 +- .../dialogflowcx_v3beta1/test_versions.py | 312 +- .../dialogflowcx_v3beta1/test_webhooks.py | 296 +- 264 files changed, 34158 insertions(+), 6311 deletions(-) create mode 100644 .coveragerc create mode 100644 .github/header-checker-lint.yml create mode 100644 docs/dialogflowcx_v3/agents.rst create mode 100644 docs/dialogflowcx_v3/entity_types.rst create mode 100644 docs/dialogflowcx_v3/environments.rst create mode 100644 docs/dialogflowcx_v3/experiments.rst create mode 100644 docs/dialogflowcx_v3/flows.rst create mode 100644 docs/dialogflowcx_v3/intents.rst create mode 100644 docs/dialogflowcx_v3/pages.rst create mode 100644 docs/dialogflowcx_v3/security_settings_service.rst create mode 100644 docs/dialogflowcx_v3/session_entity_types.rst create mode 100644 docs/dialogflowcx_v3/sessions.rst create mode 100644 docs/dialogflowcx_v3/test_cases.rst create mode 100644 docs/dialogflowcx_v3/transition_route_groups.rst create mode 100644 docs/dialogflowcx_v3/versions.rst create mode 100644 docs/dialogflowcx_v3/webhooks.rst create mode 100644 docs/dialogflowcx_v3beta1/agents.rst create mode 100644 docs/dialogflowcx_v3beta1/entity_types.rst create mode 100644 docs/dialogflowcx_v3beta1/environments.rst create mode 100644 docs/dialogflowcx_v3beta1/experiments.rst create mode 100644 docs/dialogflowcx_v3beta1/flows.rst create mode 100644 docs/dialogflowcx_v3beta1/intents.rst create mode 100644 docs/dialogflowcx_v3beta1/pages.rst create mode 100644 docs/dialogflowcx_v3beta1/security_settings_service.rst create mode 100644 docs/dialogflowcx_v3beta1/session_entity_types.rst create mode 100644 docs/dialogflowcx_v3beta1/sessions.rst create mode 100644 docs/dialogflowcx_v3beta1/test_cases.rst create mode 100644 docs/dialogflowcx_v3beta1/transition_route_groups.rst create mode 100644 docs/dialogflowcx_v3beta1/versions.rst create mode 100644 docs/dialogflowcx_v3beta1/webhooks.rst create mode 100644 google/cloud/dialogflowcx_v3/services/test_cases/__init__.py create mode 100644 google/cloud/dialogflowcx_v3/services/test_cases/async_client.py create mode 100644 google/cloud/dialogflowcx_v3/services/test_cases/client.py create mode 100644 google/cloud/dialogflowcx_v3/services/test_cases/pagers.py create mode 100644 google/cloud/dialogflowcx_v3/services/test_cases/transports/__init__.py create mode 100644 google/cloud/dialogflowcx_v3/services/test_cases/transports/base.py create mode 100644 google/cloud/dialogflowcx_v3/services/test_cases/transports/grpc.py create mode 100644 google/cloud/dialogflowcx_v3/services/test_cases/transports/grpc_asyncio.py create mode 100644 google/cloud/dialogflowcx_v3/types/test_case.py create mode 100644 google/cloud/dialogflowcx_v3/types/validation_message.py create mode 100644 google/cloud/dialogflowcx_v3beta1/services/test_cases/__init__.py create mode 100644 google/cloud/dialogflowcx_v3beta1/services/test_cases/async_client.py create mode 100644 google/cloud/dialogflowcx_v3beta1/services/test_cases/client.py create mode 100644 google/cloud/dialogflowcx_v3beta1/services/test_cases/pagers.py create mode 100644 google/cloud/dialogflowcx_v3beta1/services/test_cases/transports/__init__.py create mode 100644 google/cloud/dialogflowcx_v3beta1/services/test_cases/transports/base.py create mode 100644 google/cloud/dialogflowcx_v3beta1/services/test_cases/transports/grpc.py create mode 100644 google/cloud/dialogflowcx_v3beta1/services/test_cases/transports/grpc_asyncio.py create mode 100644 google/cloud/dialogflowcx_v3beta1/types/test_case.py create mode 100644 google/cloud/dialogflowcx_v3beta1/types/validation_message.py create mode 100644 tests/unit/gapic/dialogflowcx_v3/test_test_cases.py create mode 100644 tests/unit/gapic/dialogflowcx_v3beta1/test_test_cases.py diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 00000000..a6e44e2d --- /dev/null +++ b/.coveragerc @@ -0,0 +1,18 @@ +[run] +branch = True + +[report] +fail_under = 100 +show_missing = True +omit = + google/cloud/dialogflowcx/__init__.py +exclude_lines = + # Re-enable the standard pragma + pragma: NO COVER + # Ignore debug-only repr + def __repr__ + # Ignore pkg_resources exceptions. + # This is added at the module level as a safeguard for if someone + # generates the code and tries to run it without pip installing. This + # makes it virtually impossible to test properly. + except pkg_resources.DistributionNotFound diff --git a/.github/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 a60755e5..e6b479bf 100755 --- a/.kokoro/build.sh +++ b/.kokoro/build.sh @@ -15,7 +15,11 @@ set -eo pipefail -cd github/python-dialogflow-cx +if [[ -z "${PROJECT_ROOT:-}" ]]; then + PROJECT_ROOT="github/python-dialogflow-cx" +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..abe915ce 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-dialogflow-cx/.kokoro/build.sh" +} + +# Only run this nox session. +env_vars: { + key: "NOX_SESSION" + value: "docs docfx" +} 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 7485098a..37c5a832 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -70,9 +70,14 @@ We use `nox `__ to instrument our tests. - To test your changes, run unit tests with ``nox``:: $ nox -s unit-2.7 - $ nox -s unit-3.7 + $ nox -s unit-3.8 $ ... +- Args to pytest can be passed through the nox command separated by a `--`. For + example, to run a single test:: + + $ nox -s unit-3.8 -- -k + .. note:: The unit tests and system tests are described in the @@ -93,8 +98,12 @@ On Debian/Ubuntu:: ************ Coding Style ************ +- We use the automatic code formatter ``black``. You can run it using + the nox session ``blacken``. This will eliminate many lint errors. Run via:: + + $ nox -s blacken -- PEP8 compliance, with exceptions defined in the linter configuration. +- PEP8 compliance is required, with exceptions defined in the linter configuration. If you have ``nox`` installed, you can test that you have not introduced any non-compliant code via:: @@ -133,13 +142,18 @@ Running System Tests - To run system tests, you can execute:: - $ nox -s system-3.7 + # Run all system tests + $ nox -s system-3.8 $ nox -s system-2.7 + # Run a single system test + $ nox -s system-3.8 -- -k + + .. note:: System tests are only configured to run under Python 2.7 and - Python 3.7. For expediency, we do not run them in older versions + Python 3.8. For expediency, we do not run them in older versions of Python 3. This alone will not run the tests. You'll need to change some local diff --git a/LICENSE b/LICENSE index a8ee855d..d6456956 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,7 @@ - Apache License + + Apache License Version 2.0, January 2004 - https://www.apache.org/licenses/ + http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION @@ -192,7 +193,7 @@ you may not use this file except in compliance with the License. You may obtain a copy of the License at - https://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, diff --git a/MANIFEST.in b/MANIFEST.in index 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/README.rst b/README.rst index 6bf68b26..bfe57a44 100644 --- a/README.rst +++ b/README.rst @@ -1,23 +1,6 @@ -Python Client for Dialogflow CX API +Python Client for Google Cloud Dialogflowcx API ================================================= -|beta| |pypi| |versions| - -`Dialogflow CX API`_: Builds conversational interfaces (for example, chatbots, and voice-powered apps and devices). - -- `Client Library Documentation`_ -- `Product Documentation`_ - -.. |beta| image:: https://img.shields.io/badge/support-beta-orange.svg - :target: https://github.com/googleapis/google-cloud-python/blob/master/README.rst#beta-support -.. |pypi| image:: https://img.shields.io/pypi/v/google-cloud-dialogflow-cx.svg - :target: https://pypi.org/project/google-cloud-dialogflow-cx/ -.. |versions| image:: https://img.shields.io/pypi/pyversions/google-cloud-dialogflow-cx.svg - :target: https://pypi.org/project/google-cloud-dialogflow-cx/ -.. _Dialogflow CX API: https://cloud.google.com/dialogflow/cx/docs -.. _Client Library Documentation: https://googleapis.dev/python/dialogflow-cx/latest -.. _Product Documentation: https://cloud.google.com/dialogflow/cx/docs - Quick Start ----------- @@ -25,12 +8,11 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ -3. `Enable the Dialogflow CX API.`_ +3. Enable the Google Cloud Dialogflowcx API. 4. `Setup Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project -.. _Enable the Dialogflow CX API.: https://cloud.google.com/dialogflow/cx/docs .. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation @@ -52,10 +34,9 @@ Mac/Linux .. code-block:: console - pip install virtualenv - virtualenv + python3 -m venv source /bin/activate - /bin/pip install google-cloud-dialogflow-cx + /bin/pip install /path/to/library Windows @@ -63,20 +44,6 @@ Windows .. code-block:: console - pip install virtualenv - virtualenv + python3 -m venv \Scripts\activate - \Scripts\pip.exe install google-cloud-dialogflow-cx - -Next Steps -~~~~~~~~~~ - -- Read the `Client Library Documentation`_ for Cloud Dialogflow CX API - API to see other available methods on the client. -- Read the `Dialogflow CX API Product documentation`_ to learn - more about the product and see How-to Guides. -- View this `README`_ to see the full list of Cloud - APIs that we cover. - -.. _Dialogflow CX API Product documentation: https://cloud.google.com/dialogflow/cx/docs -.. _README: https://github.com/googleapis/google-cloud-python/blob/master/README.rst \ No newline at end of file + \Scripts\pip.exe install \path\to\library diff --git a/docs/_static/custom.css b/docs/_static/custom.css index 0abaf229..bcd37bbd 100644 --- a/docs/_static/custom.css +++ b/docs/_static/custom.css @@ -1,4 +1,9 @@ div#python2-eol { border-color: red; border-width: medium; -} \ No newline at end of file +} + +/* Ensure minimum width for 'Parameters' / 'Returns' column */ +dl.field-list > dt { + min-width: 100px +} diff --git a/docs/dialogflowcx_v3/agents.rst b/docs/dialogflowcx_v3/agents.rst new file mode 100644 index 00000000..fbd83fe0 --- /dev/null +++ b/docs/dialogflowcx_v3/agents.rst @@ -0,0 +1,11 @@ +Agents +------------------------ + +.. automodule:: google.cloud.dialogflowcx_v3.services.agents + :members: + :inherited-members: + + +.. automodule:: google.cloud.dialogflowcx_v3.services.agents.pagers + :members: + :inherited-members: diff --git a/docs/dialogflowcx_v3/entity_types.rst b/docs/dialogflowcx_v3/entity_types.rst new file mode 100644 index 00000000..c6b68f5d --- /dev/null +++ b/docs/dialogflowcx_v3/entity_types.rst @@ -0,0 +1,11 @@ +EntityTypes +----------------------------- + +.. automodule:: google.cloud.dialogflowcx_v3.services.entity_types + :members: + :inherited-members: + + +.. automodule:: google.cloud.dialogflowcx_v3.services.entity_types.pagers + :members: + :inherited-members: diff --git a/docs/dialogflowcx_v3/environments.rst b/docs/dialogflowcx_v3/environments.rst new file mode 100644 index 00000000..fc10a8e8 --- /dev/null +++ b/docs/dialogflowcx_v3/environments.rst @@ -0,0 +1,11 @@ +Environments +------------------------------ + +.. automodule:: google.cloud.dialogflowcx_v3.services.environments + :members: + :inherited-members: + + +.. automodule:: google.cloud.dialogflowcx_v3.services.environments.pagers + :members: + :inherited-members: diff --git a/docs/dialogflowcx_v3/experiments.rst b/docs/dialogflowcx_v3/experiments.rst new file mode 100644 index 00000000..6f13e0ab --- /dev/null +++ b/docs/dialogflowcx_v3/experiments.rst @@ -0,0 +1,11 @@ +Experiments +----------------------------- + +.. automodule:: google.cloud.dialogflowcx_v3.services.experiments + :members: + :inherited-members: + + +.. automodule:: google.cloud.dialogflowcx_v3.services.experiments.pagers + :members: + :inherited-members: diff --git a/docs/dialogflowcx_v3/flows.rst b/docs/dialogflowcx_v3/flows.rst new file mode 100644 index 00000000..832a92cd --- /dev/null +++ b/docs/dialogflowcx_v3/flows.rst @@ -0,0 +1,11 @@ +Flows +----------------------- + +.. automodule:: google.cloud.dialogflowcx_v3.services.flows + :members: + :inherited-members: + + +.. automodule:: google.cloud.dialogflowcx_v3.services.flows.pagers + :members: + :inherited-members: diff --git a/docs/dialogflowcx_v3/intents.rst b/docs/dialogflowcx_v3/intents.rst new file mode 100644 index 00000000..e5521b4a --- /dev/null +++ b/docs/dialogflowcx_v3/intents.rst @@ -0,0 +1,11 @@ +Intents +------------------------- + +.. automodule:: google.cloud.dialogflowcx_v3.services.intents + :members: + :inherited-members: + + +.. automodule:: google.cloud.dialogflowcx_v3.services.intents.pagers + :members: + :inherited-members: diff --git a/docs/dialogflowcx_v3/pages.rst b/docs/dialogflowcx_v3/pages.rst new file mode 100644 index 00000000..6ed56180 --- /dev/null +++ b/docs/dialogflowcx_v3/pages.rst @@ -0,0 +1,11 @@ +Pages +----------------------- + +.. automodule:: google.cloud.dialogflowcx_v3.services.pages + :members: + :inherited-members: + + +.. automodule:: google.cloud.dialogflowcx_v3.services.pages.pagers + :members: + :inherited-members: diff --git a/docs/dialogflowcx_v3/security_settings_service.rst b/docs/dialogflowcx_v3/security_settings_service.rst new file mode 100644 index 00000000..6e9967b8 --- /dev/null +++ b/docs/dialogflowcx_v3/security_settings_service.rst @@ -0,0 +1,11 @@ +SecuritySettingsService +----------------------------------------- + +.. automodule:: google.cloud.dialogflowcx_v3.services.security_settings_service + :members: + :inherited-members: + + +.. automodule:: google.cloud.dialogflowcx_v3.services.security_settings_service.pagers + :members: + :inherited-members: diff --git a/docs/dialogflowcx_v3/services.rst b/docs/dialogflowcx_v3/services.rst index 958aa685..3da663c9 100644 --- a/docs/dialogflowcx_v3/services.rst +++ b/docs/dialogflowcx_v3/services.rst @@ -1,42 +1,19 @@ Services for Google Cloud Dialogflowcx v3 API ============================================= +.. toctree:: + :maxdepth: 2 -.. automodule:: google.cloud.dialogflowcx_v3.services.agents - :members: - :inherited-members: -.. automodule:: google.cloud.dialogflowcx_v3.services.entity_types - :members: - :inherited-members: -.. automodule:: google.cloud.dialogflowcx_v3.services.environments - :members: - :inherited-members: -.. automodule:: google.cloud.dialogflowcx_v3.services.experiments - :members: - :inherited-members: -.. automodule:: google.cloud.dialogflowcx_v3.services.flows - :members: - :inherited-members: -.. automodule:: google.cloud.dialogflowcx_v3.services.intents - :members: - :inherited-members: -.. automodule:: google.cloud.dialogflowcx_v3.services.pages - :members: - :inherited-members: -.. automodule:: google.cloud.dialogflowcx_v3.services.security_settings_service - :members: - :inherited-members: -.. automodule:: google.cloud.dialogflowcx_v3.services.session_entity_types - :members: - :inherited-members: -.. automodule:: google.cloud.dialogflowcx_v3.services.sessions - :members: - :inherited-members: -.. automodule:: google.cloud.dialogflowcx_v3.services.transition_route_groups - :members: - :inherited-members: -.. automodule:: google.cloud.dialogflowcx_v3.services.versions - :members: - :inherited-members: -.. automodule:: google.cloud.dialogflowcx_v3.services.webhooks - :members: - :inherited-members: + agents + entity_types + environments + experiments + flows + intents + pages + security_settings_service + session_entity_types + sessions + test_cases + transition_route_groups + versions + webhooks diff --git a/docs/dialogflowcx_v3/session_entity_types.rst b/docs/dialogflowcx_v3/session_entity_types.rst new file mode 100644 index 00000000..d92d0fe5 --- /dev/null +++ b/docs/dialogflowcx_v3/session_entity_types.rst @@ -0,0 +1,11 @@ +SessionEntityTypes +------------------------------------ + +.. automodule:: google.cloud.dialogflowcx_v3.services.session_entity_types + :members: + :inherited-members: + + +.. automodule:: google.cloud.dialogflowcx_v3.services.session_entity_types.pagers + :members: + :inherited-members: diff --git a/docs/dialogflowcx_v3/sessions.rst b/docs/dialogflowcx_v3/sessions.rst new file mode 100644 index 00000000..494bceb1 --- /dev/null +++ b/docs/dialogflowcx_v3/sessions.rst @@ -0,0 +1,6 @@ +Sessions +-------------------------- + +.. automodule:: google.cloud.dialogflowcx_v3.services.sessions + :members: + :inherited-members: diff --git a/docs/dialogflowcx_v3/test_cases.rst b/docs/dialogflowcx_v3/test_cases.rst new file mode 100644 index 00000000..ab5a6fbb --- /dev/null +++ b/docs/dialogflowcx_v3/test_cases.rst @@ -0,0 +1,11 @@ +TestCases +--------------------------- + +.. automodule:: google.cloud.dialogflowcx_v3.services.test_cases + :members: + :inherited-members: + + +.. automodule:: google.cloud.dialogflowcx_v3.services.test_cases.pagers + :members: + :inherited-members: diff --git a/docs/dialogflowcx_v3/transition_route_groups.rst b/docs/dialogflowcx_v3/transition_route_groups.rst new file mode 100644 index 00000000..437962a6 --- /dev/null +++ b/docs/dialogflowcx_v3/transition_route_groups.rst @@ -0,0 +1,11 @@ +TransitionRouteGroups +--------------------------------------- + +.. automodule:: google.cloud.dialogflowcx_v3.services.transition_route_groups + :members: + :inherited-members: + + +.. automodule:: google.cloud.dialogflowcx_v3.services.transition_route_groups.pagers + :members: + :inherited-members: diff --git a/docs/dialogflowcx_v3/types.rst b/docs/dialogflowcx_v3/types.rst index eee8146a..7e2b1c53 100644 --- a/docs/dialogflowcx_v3/types.rst +++ b/docs/dialogflowcx_v3/types.rst @@ -3,4 +3,5 @@ Types for Google Cloud Dialogflowcx v3 API .. automodule:: google.cloud.dialogflowcx_v3.types :members: + :undoc-members: :show-inheritance: diff --git a/docs/dialogflowcx_v3/versions.rst b/docs/dialogflowcx_v3/versions.rst new file mode 100644 index 00000000..10f422b8 --- /dev/null +++ b/docs/dialogflowcx_v3/versions.rst @@ -0,0 +1,11 @@ +Versions +-------------------------- + +.. automodule:: google.cloud.dialogflowcx_v3.services.versions + :members: + :inherited-members: + + +.. automodule:: google.cloud.dialogflowcx_v3.services.versions.pagers + :members: + :inherited-members: diff --git a/docs/dialogflowcx_v3/webhooks.rst b/docs/dialogflowcx_v3/webhooks.rst new file mode 100644 index 00000000..53f893eb --- /dev/null +++ b/docs/dialogflowcx_v3/webhooks.rst @@ -0,0 +1,11 @@ +Webhooks +-------------------------- + +.. automodule:: google.cloud.dialogflowcx_v3.services.webhooks + :members: + :inherited-members: + + +.. automodule:: google.cloud.dialogflowcx_v3.services.webhooks.pagers + :members: + :inherited-members: diff --git a/docs/dialogflowcx_v3beta1/agents.rst b/docs/dialogflowcx_v3beta1/agents.rst new file mode 100644 index 00000000..f1f6e5e9 --- /dev/null +++ b/docs/dialogflowcx_v3beta1/agents.rst @@ -0,0 +1,11 @@ +Agents +------------------------ + +.. automodule:: google.cloud.dialogflowcx_v3beta1.services.agents + :members: + :inherited-members: + + +.. automodule:: google.cloud.dialogflowcx_v3beta1.services.agents.pagers + :members: + :inherited-members: diff --git a/docs/dialogflowcx_v3beta1/entity_types.rst b/docs/dialogflowcx_v3beta1/entity_types.rst new file mode 100644 index 00000000..27814dcd --- /dev/null +++ b/docs/dialogflowcx_v3beta1/entity_types.rst @@ -0,0 +1,11 @@ +EntityTypes +----------------------------- + +.. automodule:: google.cloud.dialogflowcx_v3beta1.services.entity_types + :members: + :inherited-members: + + +.. automodule:: google.cloud.dialogflowcx_v3beta1.services.entity_types.pagers + :members: + :inherited-members: diff --git a/docs/dialogflowcx_v3beta1/environments.rst b/docs/dialogflowcx_v3beta1/environments.rst new file mode 100644 index 00000000..eeb8ed19 --- /dev/null +++ b/docs/dialogflowcx_v3beta1/environments.rst @@ -0,0 +1,11 @@ +Environments +------------------------------ + +.. automodule:: google.cloud.dialogflowcx_v3beta1.services.environments + :members: + :inherited-members: + + +.. automodule:: google.cloud.dialogflowcx_v3beta1.services.environments.pagers + :members: + :inherited-members: diff --git a/docs/dialogflowcx_v3beta1/experiments.rst b/docs/dialogflowcx_v3beta1/experiments.rst new file mode 100644 index 00000000..fc67280f --- /dev/null +++ b/docs/dialogflowcx_v3beta1/experiments.rst @@ -0,0 +1,11 @@ +Experiments +----------------------------- + +.. automodule:: google.cloud.dialogflowcx_v3beta1.services.experiments + :members: + :inherited-members: + + +.. automodule:: google.cloud.dialogflowcx_v3beta1.services.experiments.pagers + :members: + :inherited-members: diff --git a/docs/dialogflowcx_v3beta1/flows.rst b/docs/dialogflowcx_v3beta1/flows.rst new file mode 100644 index 00000000..ef180bee --- /dev/null +++ b/docs/dialogflowcx_v3beta1/flows.rst @@ -0,0 +1,11 @@ +Flows +----------------------- + +.. automodule:: google.cloud.dialogflowcx_v3beta1.services.flows + :members: + :inherited-members: + + +.. automodule:: google.cloud.dialogflowcx_v3beta1.services.flows.pagers + :members: + :inherited-members: diff --git a/docs/dialogflowcx_v3beta1/intents.rst b/docs/dialogflowcx_v3beta1/intents.rst new file mode 100644 index 00000000..4e4f0077 --- /dev/null +++ b/docs/dialogflowcx_v3beta1/intents.rst @@ -0,0 +1,11 @@ +Intents +------------------------- + +.. automodule:: google.cloud.dialogflowcx_v3beta1.services.intents + :members: + :inherited-members: + + +.. automodule:: google.cloud.dialogflowcx_v3beta1.services.intents.pagers + :members: + :inherited-members: diff --git a/docs/dialogflowcx_v3beta1/pages.rst b/docs/dialogflowcx_v3beta1/pages.rst new file mode 100644 index 00000000..780bcf97 --- /dev/null +++ b/docs/dialogflowcx_v3beta1/pages.rst @@ -0,0 +1,11 @@ +Pages +----------------------- + +.. automodule:: google.cloud.dialogflowcx_v3beta1.services.pages + :members: + :inherited-members: + + +.. automodule:: google.cloud.dialogflowcx_v3beta1.services.pages.pagers + :members: + :inherited-members: diff --git a/docs/dialogflowcx_v3beta1/security_settings_service.rst b/docs/dialogflowcx_v3beta1/security_settings_service.rst new file mode 100644 index 00000000..560a3364 --- /dev/null +++ b/docs/dialogflowcx_v3beta1/security_settings_service.rst @@ -0,0 +1,11 @@ +SecuritySettingsService +----------------------------------------- + +.. automodule:: google.cloud.dialogflowcx_v3beta1.services.security_settings_service + :members: + :inherited-members: + + +.. automodule:: google.cloud.dialogflowcx_v3beta1.services.security_settings_service.pagers + :members: + :inherited-members: diff --git a/docs/dialogflowcx_v3beta1/services.rst b/docs/dialogflowcx_v3beta1/services.rst index 89e12040..03f147db 100644 --- a/docs/dialogflowcx_v3beta1/services.rst +++ b/docs/dialogflowcx_v3beta1/services.rst @@ -1,42 +1,19 @@ Services for Google Cloud Dialogflowcx v3beta1 API ================================================== +.. toctree:: + :maxdepth: 2 -.. automodule:: google.cloud.dialogflowcx_v3beta1.services.agents - :members: - :inherited-members: -.. automodule:: google.cloud.dialogflowcx_v3beta1.services.entity_types - :members: - :inherited-members: -.. automodule:: google.cloud.dialogflowcx_v3beta1.services.environments - :members: - :inherited-members: -.. automodule:: google.cloud.dialogflowcx_v3beta1.services.experiments - :members: - :inherited-members: -.. automodule:: google.cloud.dialogflowcx_v3beta1.services.flows - :members: - :inherited-members: -.. automodule:: google.cloud.dialogflowcx_v3beta1.services.intents - :members: - :inherited-members: -.. automodule:: google.cloud.dialogflowcx_v3beta1.services.pages - :members: - :inherited-members: -.. automodule:: google.cloud.dialogflowcx_v3beta1.services.security_settings_service - :members: - :inherited-members: -.. automodule:: google.cloud.dialogflowcx_v3beta1.services.session_entity_types - :members: - :inherited-members: -.. automodule:: google.cloud.dialogflowcx_v3beta1.services.sessions - :members: - :inherited-members: -.. automodule:: google.cloud.dialogflowcx_v3beta1.services.transition_route_groups - :members: - :inherited-members: -.. automodule:: google.cloud.dialogflowcx_v3beta1.services.versions - :members: - :inherited-members: -.. automodule:: google.cloud.dialogflowcx_v3beta1.services.webhooks - :members: - :inherited-members: + agents + entity_types + environments + experiments + flows + intents + pages + security_settings_service + session_entity_types + sessions + test_cases + transition_route_groups + versions + webhooks diff --git a/docs/dialogflowcx_v3beta1/session_entity_types.rst b/docs/dialogflowcx_v3beta1/session_entity_types.rst new file mode 100644 index 00000000..b4c42ef9 --- /dev/null +++ b/docs/dialogflowcx_v3beta1/session_entity_types.rst @@ -0,0 +1,11 @@ +SessionEntityTypes +------------------------------------ + +.. automodule:: google.cloud.dialogflowcx_v3beta1.services.session_entity_types + :members: + :inherited-members: + + +.. automodule:: google.cloud.dialogflowcx_v3beta1.services.session_entity_types.pagers + :members: + :inherited-members: diff --git a/docs/dialogflowcx_v3beta1/sessions.rst b/docs/dialogflowcx_v3beta1/sessions.rst new file mode 100644 index 00000000..3f792bf8 --- /dev/null +++ b/docs/dialogflowcx_v3beta1/sessions.rst @@ -0,0 +1,6 @@ +Sessions +-------------------------- + +.. automodule:: google.cloud.dialogflowcx_v3beta1.services.sessions + :members: + :inherited-members: diff --git a/docs/dialogflowcx_v3beta1/test_cases.rst b/docs/dialogflowcx_v3beta1/test_cases.rst new file mode 100644 index 00000000..0840b07a --- /dev/null +++ b/docs/dialogflowcx_v3beta1/test_cases.rst @@ -0,0 +1,11 @@ +TestCases +--------------------------- + +.. automodule:: google.cloud.dialogflowcx_v3beta1.services.test_cases + :members: + :inherited-members: + + +.. automodule:: google.cloud.dialogflowcx_v3beta1.services.test_cases.pagers + :members: + :inherited-members: diff --git a/docs/dialogflowcx_v3beta1/transition_route_groups.rst b/docs/dialogflowcx_v3beta1/transition_route_groups.rst new file mode 100644 index 00000000..894278a4 --- /dev/null +++ b/docs/dialogflowcx_v3beta1/transition_route_groups.rst @@ -0,0 +1,11 @@ +TransitionRouteGroups +--------------------------------------- + +.. automodule:: google.cloud.dialogflowcx_v3beta1.services.transition_route_groups + :members: + :inherited-members: + + +.. automodule:: google.cloud.dialogflowcx_v3beta1.services.transition_route_groups.pagers + :members: + :inherited-members: diff --git a/docs/dialogflowcx_v3beta1/types.rst b/docs/dialogflowcx_v3beta1/types.rst index 3c1160db..a7388b27 100644 --- a/docs/dialogflowcx_v3beta1/types.rst +++ b/docs/dialogflowcx_v3beta1/types.rst @@ -3,4 +3,5 @@ Types for Google Cloud Dialogflowcx v3beta1 API .. automodule:: google.cloud.dialogflowcx_v3beta1.types :members: + :undoc-members: :show-inheritance: diff --git a/docs/dialogflowcx_v3beta1/versions.rst b/docs/dialogflowcx_v3beta1/versions.rst new file mode 100644 index 00000000..c08e348c --- /dev/null +++ b/docs/dialogflowcx_v3beta1/versions.rst @@ -0,0 +1,11 @@ +Versions +-------------------------- + +.. automodule:: google.cloud.dialogflowcx_v3beta1.services.versions + :members: + :inherited-members: + + +.. automodule:: google.cloud.dialogflowcx_v3beta1.services.versions.pagers + :members: + :inherited-members: diff --git a/docs/dialogflowcx_v3beta1/webhooks.rst b/docs/dialogflowcx_v3beta1/webhooks.rst new file mode 100644 index 00000000..d5a82452 --- /dev/null +++ b/docs/dialogflowcx_v3beta1/webhooks.rst @@ -0,0 +1,11 @@ +Webhooks +-------------------------- + +.. automodule:: google.cloud.dialogflowcx_v3beta1.services.webhooks + :members: + :inherited-members: + + +.. automodule:: google.cloud.dialogflowcx_v3beta1.services.webhooks.pagers + :members: + :inherited-members: diff --git a/google/cloud/dialogflowcx/__init__.py b/google/cloud/dialogflowcx/__init__.py index cc38b578..cd27a417 100644 --- a/google/cloud/dialogflowcx/__init__.py +++ b/google/cloud/dialogflowcx/__init__.py @@ -53,6 +53,10 @@ SessionsAsyncClient, ) from google.cloud.dialogflowcx_v3.services.sessions.client import SessionsClient +from google.cloud.dialogflowcx_v3.services.test_cases.async_client import ( + TestCasesAsyncClient, +) +from google.cloud.dialogflowcx_v3.services.test_cases.client import TestCasesClient from google.cloud.dialogflowcx_v3.services.transition_route_groups.async_client import ( TransitionRouteGroupsAsyncClient, ) @@ -68,16 +72,19 @@ ) from google.cloud.dialogflowcx_v3.services.webhooks.client import WebhooksClient from google.cloud.dialogflowcx_v3.types.agent import Agent +from google.cloud.dialogflowcx_v3.types.agent import AgentValidationResult from google.cloud.dialogflowcx_v3.types.agent import CreateAgentRequest from google.cloud.dialogflowcx_v3.types.agent import DeleteAgentRequest from google.cloud.dialogflowcx_v3.types.agent import ExportAgentRequest from google.cloud.dialogflowcx_v3.types.agent import ExportAgentResponse from google.cloud.dialogflowcx_v3.types.agent import GetAgentRequest +from google.cloud.dialogflowcx_v3.types.agent import GetAgentValidationResultRequest from google.cloud.dialogflowcx_v3.types.agent import ListAgentsRequest from google.cloud.dialogflowcx_v3.types.agent import ListAgentsResponse from google.cloud.dialogflowcx_v3.types.agent import RestoreAgentRequest from google.cloud.dialogflowcx_v3.types.agent import SpeechToTextSettings from google.cloud.dialogflowcx_v3.types.agent import UpdateAgentRequest +from google.cloud.dialogflowcx_v3.types.agent import ValidateAgentRequest from google.cloud.dialogflowcx_v3.types.audio_config import AudioEncoding from google.cloud.dialogflowcx_v3.types.audio_config import InputAudioConfig from google.cloud.dialogflowcx_v3.types.audio_config import OutputAudioConfig @@ -121,12 +128,15 @@ from google.cloud.dialogflowcx_v3.types.flow import CreateFlowRequest from google.cloud.dialogflowcx_v3.types.flow import DeleteFlowRequest from google.cloud.dialogflowcx_v3.types.flow import Flow +from google.cloud.dialogflowcx_v3.types.flow import FlowValidationResult from google.cloud.dialogflowcx_v3.types.flow import GetFlowRequest +from google.cloud.dialogflowcx_v3.types.flow import GetFlowValidationResultRequest from google.cloud.dialogflowcx_v3.types.flow import ListFlowsRequest from google.cloud.dialogflowcx_v3.types.flow import ListFlowsResponse from google.cloud.dialogflowcx_v3.types.flow import NluSettings from google.cloud.dialogflowcx_v3.types.flow import TrainFlowRequest from google.cloud.dialogflowcx_v3.types.flow import UpdateFlowRequest +from google.cloud.dialogflowcx_v3.types.flow import ValidateFlowRequest from google.cloud.dialogflowcx_v3.types.fulfillment import Fulfillment from google.cloud.dialogflowcx_v3.types.intent import CreateIntentRequest from google.cloud.dialogflowcx_v3.types.intent import DeleteIntentRequest @@ -204,6 +214,39 @@ from google.cloud.dialogflowcx_v3.types.session_entity_type import ( UpdateSessionEntityTypeRequest, ) +from google.cloud.dialogflowcx_v3.types.test_case import BatchDeleteTestCasesRequest +from google.cloud.dialogflowcx_v3.types.test_case import BatchRunTestCasesMetadata +from google.cloud.dialogflowcx_v3.types.test_case import BatchRunTestCasesRequest +from google.cloud.dialogflowcx_v3.types.test_case import BatchRunTestCasesResponse +from google.cloud.dialogflowcx_v3.types.test_case import CalculateCoverageRequest +from google.cloud.dialogflowcx_v3.types.test_case import CalculateCoverageResponse +from google.cloud.dialogflowcx_v3.types.test_case import ConversationTurn +from google.cloud.dialogflowcx_v3.types.test_case import CreateTestCaseRequest +from google.cloud.dialogflowcx_v3.types.test_case import ExportTestCasesMetadata +from google.cloud.dialogflowcx_v3.types.test_case import ExportTestCasesRequest +from google.cloud.dialogflowcx_v3.types.test_case import ExportTestCasesResponse +from google.cloud.dialogflowcx_v3.types.test_case import GetTestCaseRequest +from google.cloud.dialogflowcx_v3.types.test_case import ImportTestCasesMetadata +from google.cloud.dialogflowcx_v3.types.test_case import ImportTestCasesRequest +from google.cloud.dialogflowcx_v3.types.test_case import ImportTestCasesResponse +from google.cloud.dialogflowcx_v3.types.test_case import IntentCoverage +from google.cloud.dialogflowcx_v3.types.test_case import ListTestCaseResultsRequest +from google.cloud.dialogflowcx_v3.types.test_case import ListTestCaseResultsResponse +from google.cloud.dialogflowcx_v3.types.test_case import ListTestCasesRequest +from google.cloud.dialogflowcx_v3.types.test_case import ListTestCasesResponse +from google.cloud.dialogflowcx_v3.types.test_case import RunTestCaseMetadata +from google.cloud.dialogflowcx_v3.types.test_case import RunTestCaseRequest +from google.cloud.dialogflowcx_v3.types.test_case import RunTestCaseResponse +from google.cloud.dialogflowcx_v3.types.test_case import TestCase +from google.cloud.dialogflowcx_v3.types.test_case import TestCaseError +from google.cloud.dialogflowcx_v3.types.test_case import TestCaseResult +from google.cloud.dialogflowcx_v3.types.test_case import TestConfig +from google.cloud.dialogflowcx_v3.types.test_case import TestError +from google.cloud.dialogflowcx_v3.types.test_case import TestResult +from google.cloud.dialogflowcx_v3.types.test_case import TestRunDifference +from google.cloud.dialogflowcx_v3.types.test_case import TransitionCoverage +from google.cloud.dialogflowcx_v3.types.test_case import TransitionRouteGroupCoverage +from google.cloud.dialogflowcx_v3.types.test_case import UpdateTestCaseRequest from google.cloud.dialogflowcx_v3.types.transition_route_group import ( CreateTransitionRouteGroupRequest, ) @@ -225,6 +268,8 @@ from google.cloud.dialogflowcx_v3.types.transition_route_group import ( UpdateTransitionRouteGroupRequest, ) +from google.cloud.dialogflowcx_v3.types.validation_message import ResourceName +from google.cloud.dialogflowcx_v3.types.validation_message import ValidationMessage from google.cloud.dialogflowcx_v3.types.version import CreateVersionOperationMetadata from google.cloud.dialogflowcx_v3.types.version import CreateVersionRequest from google.cloud.dialogflowcx_v3.types.version import DeleteVersionRequest @@ -248,10 +293,18 @@ __all__ = ( "Agent", + "AgentValidationResult", "AgentsAsyncClient", "AgentsClient", "AudioEncoding", "AudioInput", + "BatchDeleteTestCasesRequest", + "BatchRunTestCasesMetadata", + "BatchRunTestCasesRequest", + "BatchRunTestCasesResponse", + "CalculateCoverageRequest", + "CalculateCoverageResponse", + "ConversationTurn", "CreateAgentRequest", "CreateEntityTypeRequest", "CreateEnvironmentRequest", @@ -261,6 +314,7 @@ "CreatePageRequest", "CreateSecuritySettingsRequest", "CreateSessionEntityTypeRequest", + "CreateTestCaseRequest", "CreateTransitionRouteGroupRequest", "CreateVersionOperationMetadata", "CreateVersionRequest", @@ -293,7 +347,11 @@ "ExperimentsClient", "ExportAgentRequest", "ExportAgentResponse", + "ExportTestCasesMetadata", + "ExportTestCasesRequest", + "ExportTestCasesResponse", "Flow", + "FlowValidationResult", "FlowsAsyncClient", "FlowsClient", "Form", @@ -301,19 +359,26 @@ "FulfillIntentResponse", "Fulfillment", "GetAgentRequest", + "GetAgentValidationResultRequest", "GetEntityTypeRequest", "GetEnvironmentRequest", "GetExperimentRequest", "GetFlowRequest", + "GetFlowValidationResultRequest", "GetIntentRequest", "GetPageRequest", "GetSecuritySettingsRequest", "GetSessionEntityTypeRequest", + "GetTestCaseRequest", "GetTransitionRouteGroupRequest", "GetVersionRequest", "GetWebhookRequest", + "ImportTestCasesMetadata", + "ImportTestCasesRequest", + "ImportTestCasesResponse", "InputAudioConfig", "Intent", + "IntentCoverage", "IntentInput", "IntentView", "IntentsAsyncClient", @@ -336,6 +401,10 @@ "ListSecuritySettingsResponse", "ListSessionEntityTypesRequest", "ListSessionEntityTypesResponse", + "ListTestCaseResultsRequest", + "ListTestCaseResultsResponse", + "ListTestCasesRequest", + "ListTestCasesResponse", "ListTransitionRouteGroupsRequest", "ListTransitionRouteGroupsResponse", "ListVersionsRequest", @@ -358,8 +427,12 @@ "QueryInput", "QueryParameters", "QueryResult", + "ResourceName", "ResponseMessage", "RestoreAgentRequest", + "RunTestCaseMetadata", + "RunTestCaseRequest", + "RunTestCaseResponse", "SecuritySettings", "SecuritySettingsServiceAsyncClient", "SecuritySettingsServiceClient", @@ -380,10 +453,21 @@ "StreamingDetectIntentResponse", "StreamingRecognitionResult", "SynthesizeSpeechConfig", + "TestCase", + "TestCaseError", + "TestCaseResult", + "TestCasesAsyncClient", + "TestCasesClient", + "TestConfig", + "TestError", + "TestResult", + "TestRunDifference", "TextInput", "TrainFlowRequest", + "TransitionCoverage", "TransitionRoute", "TransitionRouteGroup", + "TransitionRouteGroupCoverage", "TransitionRouteGroupsAsyncClient", "TransitionRouteGroupsClient", "UpdateAgentRequest", @@ -395,9 +479,13 @@ "UpdatePageRequest", "UpdateSecuritySettingsRequest", "UpdateSessionEntityTypeRequest", + "UpdateTestCaseRequest", "UpdateTransitionRouteGroupRequest", "UpdateVersionRequest", "UpdateWebhookRequest", + "ValidateAgentRequest", + "ValidateFlowRequest", + "ValidationMessage", "VariantsHistory", "Version", "VersionVariants", diff --git a/google/cloud/dialogflowcx_v3/__init__.py b/google/cloud/dialogflowcx_v3/__init__.py index a897ab89..b85b6810 100644 --- a/google/cloud/dialogflowcx_v3/__init__.py +++ b/google/cloud/dialogflowcx_v3/__init__.py @@ -25,20 +25,24 @@ from .services.security_settings_service import SecuritySettingsServiceClient from .services.session_entity_types import SessionEntityTypesClient from .services.sessions import SessionsClient +from .services.test_cases import TestCasesClient from .services.transition_route_groups import TransitionRouteGroupsClient from .services.versions import VersionsClient from .services.webhooks import WebhooksClient from .types.agent import Agent +from .types.agent import AgentValidationResult from .types.agent import CreateAgentRequest from .types.agent import DeleteAgentRequest from .types.agent import ExportAgentRequest from .types.agent import ExportAgentResponse from .types.agent import GetAgentRequest +from .types.agent import GetAgentValidationResultRequest from .types.agent import ListAgentsRequest from .types.agent import ListAgentsResponse from .types.agent import RestoreAgentRequest from .types.agent import SpeechToTextSettings from .types.agent import UpdateAgentRequest +from .types.agent import ValidateAgentRequest from .types.audio_config import AudioEncoding from .types.audio_config import InputAudioConfig from .types.audio_config import OutputAudioConfig @@ -78,12 +82,15 @@ from .types.flow import CreateFlowRequest from .types.flow import DeleteFlowRequest from .types.flow import Flow +from .types.flow import FlowValidationResult from .types.flow import GetFlowRequest +from .types.flow import GetFlowValidationResultRequest from .types.flow import ListFlowsRequest from .types.flow import ListFlowsResponse from .types.flow import NluSettings from .types.flow import TrainFlowRequest from .types.flow import UpdateFlowRequest +from .types.flow import ValidateFlowRequest from .types.fulfillment import Fulfillment from .types.intent import CreateIntentRequest from .types.intent import DeleteIntentRequest @@ -137,6 +144,39 @@ from .types.session_entity_type import ListSessionEntityTypesResponse from .types.session_entity_type import SessionEntityType from .types.session_entity_type import UpdateSessionEntityTypeRequest +from .types.test_case import BatchDeleteTestCasesRequest +from .types.test_case import BatchRunTestCasesMetadata +from .types.test_case import BatchRunTestCasesRequest +from .types.test_case import BatchRunTestCasesResponse +from .types.test_case import CalculateCoverageRequest +from .types.test_case import CalculateCoverageResponse +from .types.test_case import ConversationTurn +from .types.test_case import CreateTestCaseRequest +from .types.test_case import ExportTestCasesMetadata +from .types.test_case import ExportTestCasesRequest +from .types.test_case import ExportTestCasesResponse +from .types.test_case import GetTestCaseRequest +from .types.test_case import ImportTestCasesMetadata +from .types.test_case import ImportTestCasesRequest +from .types.test_case import ImportTestCasesResponse +from .types.test_case import IntentCoverage +from .types.test_case import ListTestCaseResultsRequest +from .types.test_case import ListTestCaseResultsResponse +from .types.test_case import ListTestCasesRequest +from .types.test_case import ListTestCasesResponse +from .types.test_case import RunTestCaseMetadata +from .types.test_case import RunTestCaseRequest +from .types.test_case import RunTestCaseResponse +from .types.test_case import TestCase +from .types.test_case import TestCaseError +from .types.test_case import TestCaseResult +from .types.test_case import TestConfig +from .types.test_case import TestError +from .types.test_case import TestResult +from .types.test_case import TestRunDifference +from .types.test_case import TransitionCoverage +from .types.test_case import TransitionRouteGroupCoverage +from .types.test_case import UpdateTestCaseRequest from .types.transition_route_group import CreateTransitionRouteGroupRequest from .types.transition_route_group import DeleteTransitionRouteGroupRequest from .types.transition_route_group import GetTransitionRouteGroupRequest @@ -144,6 +184,8 @@ from .types.transition_route_group import ListTransitionRouteGroupsResponse from .types.transition_route_group import TransitionRouteGroup from .types.transition_route_group import UpdateTransitionRouteGroupRequest +from .types.validation_message import ResourceName +from .types.validation_message import ValidationMessage from .types.version import CreateVersionOperationMetadata from .types.version import CreateVersionRequest from .types.version import DeleteVersionRequest @@ -168,9 +210,17 @@ __all__ = ( "Agent", + "AgentValidationResult", "AgentsClient", "AudioEncoding", "AudioInput", + "BatchDeleteTestCasesRequest", + "BatchRunTestCasesMetadata", + "BatchRunTestCasesRequest", + "BatchRunTestCasesResponse", + "CalculateCoverageRequest", + "CalculateCoverageResponse", + "ConversationTurn", "CreateAgentRequest", "CreateEntityTypeRequest", "CreateEnvironmentRequest", @@ -180,6 +230,7 @@ "CreatePageRequest", "CreateSecuritySettingsRequest", "CreateSessionEntityTypeRequest", + "CreateTestCaseRequest", "CreateTransitionRouteGroupRequest", "CreateVersionOperationMetadata", "CreateVersionRequest", @@ -200,6 +251,7 @@ "DetectIntentResponse", "DtmfInput", "EntityType", + "EntityTypesClient", "Environment", "EnvironmentsClient", "EventHandler", @@ -208,26 +260,37 @@ "ExperimentsClient", "ExportAgentRequest", "ExportAgentResponse", + "ExportTestCasesMetadata", + "ExportTestCasesRequest", + "ExportTestCasesResponse", "Flow", + "FlowValidationResult", "FlowsClient", "Form", "FulfillIntentRequest", "FulfillIntentResponse", "Fulfillment", "GetAgentRequest", + "GetAgentValidationResultRequest", "GetEntityTypeRequest", "GetEnvironmentRequest", "GetExperimentRequest", "GetFlowRequest", + "GetFlowValidationResultRequest", "GetIntentRequest", "GetPageRequest", "GetSecuritySettingsRequest", "GetSessionEntityTypeRequest", + "GetTestCaseRequest", "GetTransitionRouteGroupRequest", "GetVersionRequest", "GetWebhookRequest", + "ImportTestCasesMetadata", + "ImportTestCasesRequest", + "ImportTestCasesResponse", "InputAudioConfig", "Intent", + "IntentCoverage", "IntentInput", "IntentView", "IntentsClient", @@ -249,6 +312,10 @@ "ListSecuritySettingsResponse", "ListSessionEntityTypesRequest", "ListSessionEntityTypesResponse", + "ListTestCaseResultsRequest", + "ListTestCaseResultsResponse", + "ListTestCasesRequest", + "ListTestCasesResponse", "ListTransitionRouteGroupsRequest", "ListTransitionRouteGroupsResponse", "ListVersionsRequest", @@ -270,8 +337,12 @@ "QueryInput", "QueryParameters", "QueryResult", + "ResourceName", "ResponseMessage", "RestoreAgentRequest", + "RunTestCaseMetadata", + "RunTestCaseRequest", + "RunTestCaseResponse", "SecuritySettings", "SecuritySettingsServiceClient", "SentimentAnalysisResult", @@ -289,10 +360,21 @@ "StreamingDetectIntentResponse", "StreamingRecognitionResult", "SynthesizeSpeechConfig", + "TestCase", + "TestCaseError", + "TestCaseResult", + "TestCasesClient", + "TestConfig", + "TestError", + "TestResult", + "TestRunDifference", "TextInput", "TrainFlowRequest", + "TransitionCoverage", "TransitionRoute", "TransitionRouteGroup", + "TransitionRouteGroupCoverage", + "TransitionRouteGroupsClient", "UpdateAgentRequest", "UpdateEntityTypeRequest", "UpdateEnvironmentRequest", @@ -302,9 +384,13 @@ "UpdatePageRequest", "UpdateSecuritySettingsRequest", "UpdateSessionEntityTypeRequest", + "UpdateTestCaseRequest", "UpdateTransitionRouteGroupRequest", "UpdateVersionRequest", "UpdateWebhookRequest", + "ValidateAgentRequest", + "ValidateFlowRequest", + "ValidationMessage", "VariantsHistory", "Version", "VersionVariants", @@ -314,6 +400,4 @@ "WebhookRequest", "WebhookResponse", "WebhooksClient", - "EntityTypesClient", - "TransitionRouteGroupsClient", ) diff --git a/google/cloud/dialogflowcx_v3/services/agents/async_client.py b/google/cloud/dialogflowcx_v3/services/agents/async_client.py index 49935e19..2dcd732c 100644 --- a/google/cloud/dialogflowcx_v3/services/agents/async_client.py +++ b/google/cloud/dialogflowcx_v3/services/agents/async_client.py @@ -33,6 +33,7 @@ from google.cloud.dialogflowcx_v3.services.agents import pagers from google.cloud.dialogflowcx_v3.types import agent from google.cloud.dialogflowcx_v3.types import agent as gcdc_agent +from google.cloud.dialogflowcx_v3.types import flow from google.protobuf import empty_pb2 as empty # type: ignore from google.protobuf import field_mask_pb2 as field_mask # type: ignore from google.protobuf import struct_pb2 as struct # type: ignore @@ -52,8 +53,22 @@ class AgentsAsyncClient: agent_path = staticmethod(AgentsClient.agent_path) parse_agent_path = staticmethod(AgentsClient.parse_agent_path) + agent_validation_result_path = staticmethod( + AgentsClient.agent_validation_result_path + ) + parse_agent_validation_result_path = staticmethod( + AgentsClient.parse_agent_validation_result_path + ) flow_path = staticmethod(AgentsClient.flow_path) parse_flow_path = staticmethod(AgentsClient.parse_flow_path) + flow_validation_result_path = staticmethod(AgentsClient.flow_validation_result_path) + parse_flow_validation_result_path = staticmethod( + AgentsClient.parse_flow_validation_result_path + ) + security_settings_path = staticmethod(AgentsClient.security_settings_path) + parse_security_settings_path = staticmethod( + AgentsClient.parse_security_settings_path + ) common_billing_account_path = staticmethod(AgentsClient.common_billing_account_path) parse_common_billing_account_path = staticmethod( @@ -74,7 +89,36 @@ class AgentsAsyncClient: common_location_path = staticmethod(AgentsClient.common_location_path) parse_common_location_path = staticmethod(AgentsClient.parse_common_location_path) - from_service_account_file = AgentsClient.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: + AgentsAsyncClient: The constructed client. + """ + return AgentsClient.from_service_account_info.__func__(AgentsAsyncClient, 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: + AgentsAsyncClient: The constructed client. + """ + return AgentsClient.from_service_account_file.__func__(AgentsAsyncClient, filename, *args, **kwargs) # type: ignore + from_service_account_json = from_service_account_file @property @@ -151,12 +195,13 @@ async def list_agents( location. Args: - request (:class:`~.agent.ListAgentsRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.ListAgentsRequest`): The request object. The request message for [Agents.ListAgents][google.cloud.dialogflow.cx.v3.Agents.ListAgents]. parent (:class:`str`): Required. The location to list all agents for. Format: ``projects//locations/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -168,7 +213,7 @@ async def list_agents( sent along with the request as metadata. Returns: - ~.pagers.ListAgentsAsyncPager: + google.cloud.dialogflowcx_v3.services.agents.pagers.ListAgentsAsyncPager: The response message for [Agents.ListAgents][google.cloud.dialogflow.cx.v3.Agents.ListAgents]. @@ -232,12 +277,13 @@ async def get_agent( r"""Retrieves the specified agent. Args: - request (:class:`~.agent.GetAgentRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.GetAgentRequest`): The request object. The request message for [Agents.GetAgent][google.cloud.dialogflow.cx.v3.Agents.GetAgent]. name (:class:`str`): Required. The name of the agent. Format: ``projects//locations//agents/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -249,20 +295,21 @@ async def get_agent( sent along with the request as metadata. Returns: - ~.agent.Agent: - Agents are best described as Natural Language - Understanding (NLU) modules that transform user requests - into actionable data. You can include agents in your - app, product, or service to determine user intent and - respond to the user in a natural way. - - After you create an agent, you can add - [Intents][google.cloud.dialogflow.cx.v3.Intent], [Entity - Types][google.cloud.dialogflow.cx.v3.EntityType], - [Flows][google.cloud.dialogflow.cx.v3.Flow], - [Fulfillments][google.cloud.dialogflow.cx.v3.Fulfillment], - [Webhooks][google.cloud.dialogflow.cx.v3.Webhook], and - so on to manage the conversation flows.. + google.cloud.dialogflowcx_v3.types.Agent: + Agents are best described as Natural Language Understanding (NLU) modules + that transform user requests into actionable data. + You can include agents in your app, product, or + service to determine user intent and respond to the + user in a natural way. + + After you create an agent, you can add + [Intents][google.cloud.dialogflow.cx.v3.Intent], + [Entity + Types][google.cloud.dialogflow.cx.v3.EntityType], + [Flows][google.cloud.dialogflow.cx.v3.Flow], + [Fulfillments][google.cloud.dialogflow.cx.v3.Fulfillment], + [Webhooks][google.cloud.dialogflow.cx.v3.Webhook], + and so on to manage the conversation flows.. """ # Create or coerce a protobuf request object. @@ -316,16 +363,17 @@ async def create_agent( r"""Creates an agent in the specified location. Args: - request (:class:`~.gcdc_agent.CreateAgentRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.CreateAgentRequest`): The request object. The request message for [Agents.CreateAgent][google.cloud.dialogflow.cx.v3.Agents.CreateAgent]. parent (:class:`str`): Required. The location to create a agent for. Format: ``projects//locations/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - agent (:class:`~.gcdc_agent.Agent`): + agent (:class:`google.cloud.dialogflowcx_v3.types.Agent`): Required. The agent to create. This corresponds to the ``agent`` field on the ``request`` instance; if ``request`` is provided, this @@ -338,20 +386,21 @@ async def create_agent( sent along with the request as metadata. Returns: - ~.gcdc_agent.Agent: - Agents are best described as Natural Language - Understanding (NLU) modules that transform user requests - into actionable data. You can include agents in your - app, product, or service to determine user intent and - respond to the user in a natural way. - - After you create an agent, you can add - [Intents][google.cloud.dialogflow.cx.v3.Intent], [Entity - Types][google.cloud.dialogflow.cx.v3.EntityType], - [Flows][google.cloud.dialogflow.cx.v3.Flow], - [Fulfillments][google.cloud.dialogflow.cx.v3.Fulfillment], - [Webhooks][google.cloud.dialogflow.cx.v3.Webhook], and - so on to manage the conversation flows.. + google.cloud.dialogflowcx_v3.types.Agent: + Agents are best described as Natural Language Understanding (NLU) modules + that transform user requests into actionable data. + You can include agents in your app, product, or + service to determine user intent and respond to the + user in a natural way. + + After you create an agent, you can add + [Intents][google.cloud.dialogflow.cx.v3.Intent], + [Entity + Types][google.cloud.dialogflow.cx.v3.EntityType], + [Flows][google.cloud.dialogflow.cx.v3.Flow], + [Fulfillments][google.cloud.dialogflow.cx.v3.Fulfillment], + [Webhooks][google.cloud.dialogflow.cx.v3.Webhook], + and so on to manage the conversation flows.. """ # Create or coerce a protobuf request object. @@ -407,18 +456,19 @@ async def update_agent( r"""Updates the specified agent. Args: - request (:class:`~.gcdc_agent.UpdateAgentRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.UpdateAgentRequest`): The request object. The request message for [Agents.UpdateAgent][google.cloud.dialogflow.cx.v3.Agents.UpdateAgent]. - agent (:class:`~.gcdc_agent.Agent`): + agent (:class:`google.cloud.dialogflowcx_v3.types.Agent`): Required. The agent to update. This corresponds to the ``agent`` 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`): The mask to control which fields get updated. If the mask is not present, all fields will be updated. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -430,20 +480,21 @@ async def update_agent( sent along with the request as metadata. Returns: - ~.gcdc_agent.Agent: - Agents are best described as Natural Language - Understanding (NLU) modules that transform user requests - into actionable data. You can include agents in your - app, product, or service to determine user intent and - respond to the user in a natural way. - - After you create an agent, you can add - [Intents][google.cloud.dialogflow.cx.v3.Intent], [Entity - Types][google.cloud.dialogflow.cx.v3.EntityType], - [Flows][google.cloud.dialogflow.cx.v3.Flow], - [Fulfillments][google.cloud.dialogflow.cx.v3.Fulfillment], - [Webhooks][google.cloud.dialogflow.cx.v3.Webhook], and - so on to manage the conversation flows.. + google.cloud.dialogflowcx_v3.types.Agent: + Agents are best described as Natural Language Understanding (NLU) modules + that transform user requests into actionable data. + You can include agents in your app, product, or + service to determine user intent and respond to the + user in a natural way. + + After you create an agent, you can add + [Intents][google.cloud.dialogflow.cx.v3.Intent], + [Entity + Types][google.cloud.dialogflow.cx.v3.EntityType], + [Flows][google.cloud.dialogflow.cx.v3.Flow], + [Fulfillments][google.cloud.dialogflow.cx.v3.Fulfillment], + [Webhooks][google.cloud.dialogflow.cx.v3.Webhook], + and so on to manage the conversation flows.. """ # Create or coerce a protobuf request object. @@ -500,12 +551,13 @@ async def delete_agent( r"""Deletes the specified agent. Args: - request (:class:`~.agent.DeleteAgentRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.DeleteAgentRequest`): The request object. The request message for [Agents.DeleteAgent][google.cloud.dialogflow.cx.v3.Agents.DeleteAgent]. name (:class:`str`): Required. The name of the agent to delete. Format: ``projects//locations//agents/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -564,7 +616,7 @@ async def export_agent( r"""Exports the specified agent to a binary file. Args: - request (:class:`~.agent.ExportAgentRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.ExportAgentRequest`): The request object. The request message for [Agents.ExportAgent][google.cloud.dialogflow.cx.v3.Agents.ExportAgent]. @@ -575,12 +627,12 @@ async def export_agent( 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:``~.agent.ExportAgentResponse``: The response - message for + :class:`google.cloud.dialogflowcx_v3.types.ExportAgentResponse` + The response message for [Agents.ExportAgent][google.cloud.dialogflow.cx.v3.Agents.ExportAgent]. """ @@ -630,7 +682,7 @@ async def restore_agent( flows) will be removed. Args: - request (:class:`~.agent.RestoreAgentRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.RestoreAgentRequest`): The request object. The request message for [Agents.RestoreAgent][google.cloud.dialogflow.cx.v3.Agents.RestoreAgent]. @@ -641,24 +693,22 @@ async def restore_agent( 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:``~.empty.Empty``: A generic empty message that - you can re-use to avoid defining duplicated empty - messages in your APIs. A typical example is to use it as - the request or the response type of an API method. For - instance: + The result type for the operation will be :class:`google.protobuf.empty_pb2.Empty` A generic empty message that you can re-use to avoid defining duplicated + empty messages in your APIs. A typical example is to + use it as the request or the response type of an API + method. For instance: - :: + service Foo { + rpc Bar(google.protobuf.Empty) returns + (google.protobuf.Empty); - service Foo { - rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty); - } + } - The JSON representation for ``Empty`` is empty JSON - object ``{}``. + The JSON representation for Empty is empty JSON + object {}. """ # Create or coerce a protobuf request object. @@ -693,6 +743,134 @@ async def restore_agent( # Done; return the response. return response + async def validate_agent( + self, + request: agent.ValidateAgentRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> agent.AgentValidationResult: + r"""Validates the specified agent and creates or updates + validation results. The agent in draft version is + validated. Please call this API after the training is + completed to get the complete validation results. + + Args: + request (:class:`google.cloud.dialogflowcx_v3.types.ValidateAgentRequest`): + The request object. The request message for + [Agents.ValidateAgent][google.cloud.dialogflow.cx.v3.Agents.ValidateAgent]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.dialogflowcx_v3.types.AgentValidationResult: + The response message for + [Agents.GetAgentValidationResult][google.cloud.dialogflow.cx.v3.Agents.GetAgentValidationResult]. + + """ + # Create or coerce a protobuf request object. + + request = agent.ValidateAgentRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.validate_agent, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = await rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + + async def get_agent_validation_result( + self, + request: agent.GetAgentValidationResultRequest = None, + *, + name: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> agent.AgentValidationResult: + r"""Gets the latest agent validation result. Agent + validation is performed when ValidateAgent is called. + + Args: + request (:class:`google.cloud.dialogflowcx_v3.types.GetAgentValidationResultRequest`): + The request object. The request message for + [Agents.GetAgentValidationResult][google.cloud.dialogflow.cx.v3.Agents.GetAgentValidationResult]. + name (:class:`str`): + Required. The agent name. Format: + ``projects//locations//agents//validationResult``. + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.dialogflowcx_v3.types.AgentValidationResult: + The response message for + [Agents.GetAgentValidationResult][google.cloud.dialogflow.cx.v3.Agents.GetAgentValidationResult]. + + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = agent.GetAgentValidationResultRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.get_agent_validation_result, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = await rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + try: DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/google/cloud/dialogflowcx_v3/services/agents/client.py b/google/cloud/dialogflowcx_v3/services/agents/client.py index 67b8d2e7..8ebc02b7 100644 --- a/google/cloud/dialogflowcx_v3/services/agents/client.py +++ b/google/cloud/dialogflowcx_v3/services/agents/client.py @@ -37,6 +37,7 @@ from google.cloud.dialogflowcx_v3.services.agents import pagers from google.cloud.dialogflowcx_v3.types import agent from google.cloud.dialogflowcx_v3.types import agent as gcdc_agent +from google.cloud.dialogflowcx_v3.types import flow from google.protobuf import empty_pb2 as empty # type: ignore from google.protobuf import field_mask_pb2 as field_mask # type: ignore from google.protobuf import struct_pb2 as struct # type: ignore @@ -114,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: + AgentsClient: The constructed client. + """ + credentials = service_account.Credentials.from_service_account_info(info) + kwargs["credentials"] = credentials + return cls(*args, **kwargs) + @classmethod def from_service_account_file(cls, filename: str, *args, **kwargs): """Creates an instance of this client using the provided credentials @@ -126,7 +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. + AgentsClient: The constructed client. """ credentials = service_account.Credentials.from_service_account_file(filename) kwargs["credentials"] = credentials @@ -159,6 +176,22 @@ def parse_agent_path(path: str) -> Dict[str, str]: ) return m.groupdict() if m else {} + @staticmethod + def agent_validation_result_path(project: str, location: str, agent: str,) -> str: + """Return a fully-qualified agent_validation_result string.""" + return "projects/{project}/locations/{location}/agents/{agent}/validationResult".format( + project=project, location=location, agent=agent, + ) + + @staticmethod + def parse_agent_validation_result_path(path: str) -> Dict[str, str]: + """Parse a agent_validation_result path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/locations/(?P.+?)/agents/(?P.+?)/validationResult$", + path, + ) + return m.groupdict() if m else {} + @staticmethod def flow_path(project: str, location: str, agent: str, flow: str,) -> str: """Return a fully-qualified flow string.""" @@ -175,6 +208,42 @@ def parse_flow_path(path: str) -> Dict[str, str]: ) return m.groupdict() if m else {} + @staticmethod + def flow_validation_result_path( + project: str, location: str, agent: str, flow: str, + ) -> str: + """Return a fully-qualified flow_validation_result string.""" + return "projects/{project}/locations/{location}/agents/{agent}/flows/{flow}/validationResult".format( + project=project, location=location, agent=agent, flow=flow, + ) + + @staticmethod + def parse_flow_validation_result_path(path: str) -> Dict[str, str]: + """Parse a flow_validation_result path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/locations/(?P.+?)/agents/(?P.+?)/flows/(?P.+?)/validationResult$", + path, + ) + return m.groupdict() if m else {} + + @staticmethod + def security_settings_path( + project: str, location: str, security_settings: str, + ) -> str: + """Return a fully-qualified security_settings string.""" + return "projects/{project}/locations/{location}/securitySettings/{security_settings}".format( + project=project, location=location, security_settings=security_settings, + ) + + @staticmethod + def parse_security_settings_path(path: str) -> Dict[str, str]: + """Parse a security_settings path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/locations/(?P.+?)/securitySettings/(?P.+?)$", + path, + ) + return m.groupdict() if m else {} + @staticmethod def common_billing_account_path(billing_account: str,) -> str: """Return a fully-qualified billing_account string.""" @@ -250,10 +319,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, ~.AgentsTransport]): The + transport (Union[str, AgentsTransport]): 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 @@ -289,21 +358,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: @@ -346,7 +411,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,12 +429,13 @@ def list_agents( location. Args: - request (:class:`~.agent.ListAgentsRequest`): + request (google.cloud.dialogflowcx_v3.types.ListAgentsRequest): The request object. The request message for [Agents.ListAgents][google.cloud.dialogflow.cx.v3.Agents.ListAgents]. - parent (:class:`str`): + parent (str): Required. The location to list all agents for. Format: ``projects//locations/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -381,7 +447,7 @@ def list_agents( sent along with the request as metadata. Returns: - ~.pagers.ListAgentsPager: + google.cloud.dialogflowcx_v3.services.agents.pagers.ListAgentsPager: The response message for [Agents.ListAgents][google.cloud.dialogflow.cx.v3.Agents.ListAgents]. @@ -446,12 +512,13 @@ def get_agent( r"""Retrieves the specified agent. Args: - request (:class:`~.agent.GetAgentRequest`): + request (google.cloud.dialogflowcx_v3.types.GetAgentRequest): The request object. The request message for [Agents.GetAgent][google.cloud.dialogflow.cx.v3.Agents.GetAgent]. - name (:class:`str`): + name (str): Required. The name of the agent. Format: ``projects//locations//agents/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -463,20 +530,21 @@ def get_agent( sent along with the request as metadata. Returns: - ~.agent.Agent: - Agents are best described as Natural Language - Understanding (NLU) modules that transform user requests - into actionable data. You can include agents in your - app, product, or service to determine user intent and - respond to the user in a natural way. - - After you create an agent, you can add - [Intents][google.cloud.dialogflow.cx.v3.Intent], [Entity - Types][google.cloud.dialogflow.cx.v3.EntityType], - [Flows][google.cloud.dialogflow.cx.v3.Flow], - [Fulfillments][google.cloud.dialogflow.cx.v3.Fulfillment], - [Webhooks][google.cloud.dialogflow.cx.v3.Webhook], and - so on to manage the conversation flows.. + google.cloud.dialogflowcx_v3.types.Agent: + Agents are best described as Natural Language Understanding (NLU) modules + that transform user requests into actionable data. + You can include agents in your app, product, or + service to determine user intent and respond to the + user in a natural way. + + After you create an agent, you can add + [Intents][google.cloud.dialogflow.cx.v3.Intent], + [Entity + Types][google.cloud.dialogflow.cx.v3.EntityType], + [Flows][google.cloud.dialogflow.cx.v3.Flow], + [Fulfillments][google.cloud.dialogflow.cx.v3.Fulfillment], + [Webhooks][google.cloud.dialogflow.cx.v3.Webhook], + and so on to manage the conversation flows.. """ # Create or coerce a protobuf request object. @@ -531,16 +599,17 @@ def create_agent( r"""Creates an agent in the specified location. Args: - request (:class:`~.gcdc_agent.CreateAgentRequest`): + request (google.cloud.dialogflowcx_v3.types.CreateAgentRequest): The request object. The request message for [Agents.CreateAgent][google.cloud.dialogflow.cx.v3.Agents.CreateAgent]. - parent (:class:`str`): + parent (str): Required. The location to create a agent for. Format: ``projects//locations/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - agent (:class:`~.gcdc_agent.Agent`): + agent (google.cloud.dialogflowcx_v3.types.Agent): Required. The agent to create. This corresponds to the ``agent`` field on the ``request`` instance; if ``request`` is provided, this @@ -553,20 +622,21 @@ def create_agent( sent along with the request as metadata. Returns: - ~.gcdc_agent.Agent: - Agents are best described as Natural Language - Understanding (NLU) modules that transform user requests - into actionable data. You can include agents in your - app, product, or service to determine user intent and - respond to the user in a natural way. - - After you create an agent, you can add - [Intents][google.cloud.dialogflow.cx.v3.Intent], [Entity - Types][google.cloud.dialogflow.cx.v3.EntityType], - [Flows][google.cloud.dialogflow.cx.v3.Flow], - [Fulfillments][google.cloud.dialogflow.cx.v3.Fulfillment], - [Webhooks][google.cloud.dialogflow.cx.v3.Webhook], and - so on to manage the conversation flows.. + google.cloud.dialogflowcx_v3.types.Agent: + Agents are best described as Natural Language Understanding (NLU) modules + that transform user requests into actionable data. + You can include agents in your app, product, or + service to determine user intent and respond to the + user in a natural way. + + After you create an agent, you can add + [Intents][google.cloud.dialogflow.cx.v3.Intent], + [Entity + Types][google.cloud.dialogflow.cx.v3.EntityType], + [Flows][google.cloud.dialogflow.cx.v3.Flow], + [Fulfillments][google.cloud.dialogflow.cx.v3.Fulfillment], + [Webhooks][google.cloud.dialogflow.cx.v3.Webhook], + and so on to manage the conversation flows.. """ # Create or coerce a protobuf request object. @@ -623,18 +693,19 @@ def update_agent( r"""Updates the specified agent. Args: - request (:class:`~.gcdc_agent.UpdateAgentRequest`): + request (google.cloud.dialogflowcx_v3.types.UpdateAgentRequest): The request object. The request message for [Agents.UpdateAgent][google.cloud.dialogflow.cx.v3.Agents.UpdateAgent]. - agent (:class:`~.gcdc_agent.Agent`): + agent (google.cloud.dialogflowcx_v3.types.Agent): Required. The agent to update. This corresponds to the ``agent`` 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): The mask to control which fields get updated. If the mask is not present, all fields will be updated. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -646,20 +717,21 @@ def update_agent( sent along with the request as metadata. Returns: - ~.gcdc_agent.Agent: - Agents are best described as Natural Language - Understanding (NLU) modules that transform user requests - into actionable data. You can include agents in your - app, product, or service to determine user intent and - respond to the user in a natural way. - - After you create an agent, you can add - [Intents][google.cloud.dialogflow.cx.v3.Intent], [Entity - Types][google.cloud.dialogflow.cx.v3.EntityType], - [Flows][google.cloud.dialogflow.cx.v3.Flow], - [Fulfillments][google.cloud.dialogflow.cx.v3.Fulfillment], - [Webhooks][google.cloud.dialogflow.cx.v3.Webhook], and - so on to manage the conversation flows.. + google.cloud.dialogflowcx_v3.types.Agent: + Agents are best described as Natural Language Understanding (NLU) modules + that transform user requests into actionable data. + You can include agents in your app, product, or + service to determine user intent and respond to the + user in a natural way. + + After you create an agent, you can add + [Intents][google.cloud.dialogflow.cx.v3.Intent], + [Entity + Types][google.cloud.dialogflow.cx.v3.EntityType], + [Flows][google.cloud.dialogflow.cx.v3.Flow], + [Fulfillments][google.cloud.dialogflow.cx.v3.Fulfillment], + [Webhooks][google.cloud.dialogflow.cx.v3.Webhook], + and so on to manage the conversation flows.. """ # Create or coerce a protobuf request object. @@ -717,12 +789,13 @@ def delete_agent( r"""Deletes the specified agent. Args: - request (:class:`~.agent.DeleteAgentRequest`): + request (google.cloud.dialogflowcx_v3.types.DeleteAgentRequest): The request object. The request message for [Agents.DeleteAgent][google.cloud.dialogflow.cx.v3.Agents.DeleteAgent]. - name (:class:`str`): + name (str): Required. The name of the agent to delete. Format: ``projects//locations//agents/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -782,7 +855,7 @@ def export_agent( r"""Exports the specified agent to a binary file. Args: - request (:class:`~.agent.ExportAgentRequest`): + request (google.cloud.dialogflowcx_v3.types.ExportAgentRequest): The request object. The request message for [Agents.ExportAgent][google.cloud.dialogflow.cx.v3.Agents.ExportAgent]. @@ -793,12 +866,12 @@ def export_agent( 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:``~.agent.ExportAgentResponse``: The response - message for + :class:`google.cloud.dialogflowcx_v3.types.ExportAgentResponse` + The response message for [Agents.ExportAgent][google.cloud.dialogflow.cx.v3.Agents.ExportAgent]. """ @@ -849,7 +922,7 @@ def restore_agent( flows) will be removed. Args: - request (:class:`~.agent.RestoreAgentRequest`): + request (google.cloud.dialogflowcx_v3.types.RestoreAgentRequest): The request object. The request message for [Agents.RestoreAgent][google.cloud.dialogflow.cx.v3.Agents.RestoreAgent]. @@ -860,24 +933,22 @@ def restore_agent( 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:``~.empty.Empty``: A generic empty message that - you can re-use to avoid defining duplicated empty - messages in your APIs. A typical example is to use it as - the request or the response type of an API method. For - instance: + The result type for the operation will be :class:`google.protobuf.empty_pb2.Empty` A generic empty message that you can re-use to avoid defining duplicated + empty messages in your APIs. A typical example is to + use it as the request or the response type of an API + method. For instance: - :: + service Foo { + rpc Bar(google.protobuf.Empty) returns + (google.protobuf.Empty); - service Foo { - rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty); - } + } - The JSON representation for ``Empty`` is empty JSON - object ``{}``. + The JSON representation for Empty is empty JSON + object {}. """ # Create or coerce a protobuf request object. @@ -913,6 +984,138 @@ def restore_agent( # Done; return the response. return response + def validate_agent( + self, + request: agent.ValidateAgentRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> agent.AgentValidationResult: + r"""Validates the specified agent and creates or updates + validation results. The agent in draft version is + validated. Please call this API after the training is + completed to get the complete validation results. + + Args: + request (google.cloud.dialogflowcx_v3.types.ValidateAgentRequest): + The request object. The request message for + [Agents.ValidateAgent][google.cloud.dialogflow.cx.v3.Agents.ValidateAgent]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.dialogflowcx_v3.types.AgentValidationResult: + The response message for + [Agents.GetAgentValidationResult][google.cloud.dialogflow.cx.v3.Agents.GetAgentValidationResult]. + + """ + # Create or coerce a protobuf request object. + + # Minor optimization to avoid making a copy if the user passes + # in a agent.ValidateAgentRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, agent.ValidateAgentRequest): + request = agent.ValidateAgentRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.validate_agent] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + + def get_agent_validation_result( + self, + request: agent.GetAgentValidationResultRequest = None, + *, + name: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> agent.AgentValidationResult: + r"""Gets the latest agent validation result. Agent + validation is performed when ValidateAgent is called. + + Args: + request (google.cloud.dialogflowcx_v3.types.GetAgentValidationResultRequest): + The request object. The request message for + [Agents.GetAgentValidationResult][google.cloud.dialogflow.cx.v3.Agents.GetAgentValidationResult]. + name (str): + Required. The agent name. Format: + ``projects//locations//agents//validationResult``. + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.dialogflowcx_v3.types.AgentValidationResult: + The response message for + [Agents.GetAgentValidationResult][google.cloud.dialogflow.cx.v3.Agents.GetAgentValidationResult]. + + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a agent.GetAgentValidationResultRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, agent.GetAgentValidationResultRequest): + request = agent.GetAgentValidationResultRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[ + self._transport.get_agent_validation_result + ] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + try: DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/google/cloud/dialogflowcx_v3/services/agents/pagers.py b/google/cloud/dialogflowcx_v3/services/agents/pagers.py index f5fceec5..f937cd89 100644 --- a/google/cloud/dialogflowcx_v3/services/agents/pagers.py +++ b/google/cloud/dialogflowcx_v3/services/agents/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.dialogflowcx_v3.types import agent @@ -24,7 +33,7 @@ class ListAgentsPager: """A pager for iterating through ``list_agents`` requests. This class thinly wraps an initial - :class:`~.agent.ListAgentsResponse` object, and + :class:`google.cloud.dialogflowcx_v3.types.ListAgentsResponse` object, and provides an ``__iter__`` method to iterate through its ``agents`` field. @@ -33,7 +42,7 @@ class ListAgentsPager: through the ``agents`` field on the corresponding responses. - All the usual :class:`~.agent.ListAgentsResponse` + All the usual :class:`google.cloud.dialogflowcx_v3.types.ListAgentsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -51,9 +60,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.agent.ListAgentsRequest`): + request (google.cloud.dialogflowcx_v3.types.ListAgentsRequest): The initial request object. - response (:class:`~.agent.ListAgentsResponse`): + response (google.cloud.dialogflowcx_v3.types.ListAgentsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -86,7 +95,7 @@ class ListAgentsAsyncPager: """A pager for iterating through ``list_agents`` requests. This class thinly wraps an initial - :class:`~.agent.ListAgentsResponse` object, and + :class:`google.cloud.dialogflowcx_v3.types.ListAgentsResponse` object, and provides an ``__aiter__`` method to iterate through its ``agents`` field. @@ -95,7 +104,7 @@ class ListAgentsAsyncPager: through the ``agents`` field on the corresponding responses. - All the usual :class:`~.agent.ListAgentsResponse` + All the usual :class:`google.cloud.dialogflowcx_v3.types.ListAgentsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -113,9 +122,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.agent.ListAgentsRequest`): + request (google.cloud.dialogflowcx_v3.types.ListAgentsRequest): The initial request object. - response (:class:`~.agent.ListAgentsResponse`): + response (google.cloud.dialogflowcx_v3.types.ListAgentsResponse): 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/dialogflowcx_v3/services/agents/transports/base.py b/google/cloud/dialogflowcx_v3/services/agents/transports/base.py index c8f8d077..e313f4de 100644 --- a/google/cloud/dialogflowcx_v3/services/agents/transports/base.py +++ b/google/cloud/dialogflowcx_v3/services/agents/transports/base.py @@ -134,6 +134,14 @@ def _prep_wrapped_messages(self, client_info): self.restore_agent: gapic_v1.method.wrap_method( self.restore_agent, default_timeout=None, client_info=client_info, ), + self.validate_agent: gapic_v1.method.wrap_method( + self.validate_agent, default_timeout=None, client_info=client_info, + ), + self.get_agent_validation_result: gapic_v1.method.wrap_method( + self.get_agent_validation_result, + default_timeout=None, + client_info=client_info, + ), } @property @@ -206,5 +214,27 @@ def restore_agent( ]: raise NotImplementedError() + @property + def validate_agent( + self, + ) -> typing.Callable[ + [agent.ValidateAgentRequest], + typing.Union[ + agent.AgentValidationResult, typing.Awaitable[agent.AgentValidationResult] + ], + ]: + raise NotImplementedError() + + @property + def get_agent_validation_result( + self, + ) -> typing.Callable[ + [agent.GetAgentValidationResultRequest], + typing.Union[ + agent.AgentValidationResult, typing.Awaitable[agent.AgentValidationResult] + ], + ]: + raise NotImplementedError() + __all__ = ("AgentsTransport",) diff --git a/google/cloud/dialogflowcx_v3/services/agents/transports/grpc.py b/google/cloud/dialogflowcx_v3/services/agents/transports/grpc.py index 496da86b..1522556d 100644 --- a/google/cloud/dialogflowcx_v3/services/agents/transports/grpc.py +++ b/google/cloud/dialogflowcx_v3/services/agents/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): @@ -107,6 +112,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -116,11 +126,6 @@ def __init__( 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 @@ -164,12 +169,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ @@ -438,5 +449,61 @@ def restore_agent( ) return self._stubs["restore_agent"] + @property + def validate_agent( + self, + ) -> Callable[[agent.ValidateAgentRequest], agent.AgentValidationResult]: + r"""Return a callable for the validate agent method over gRPC. + + Validates the specified agent and creates or updates + validation results. The agent in draft version is + validated. Please call this API after the training is + completed to get the complete validation results. + + Returns: + Callable[[~.ValidateAgentRequest], + ~.AgentValidationResult]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "validate_agent" not in self._stubs: + self._stubs["validate_agent"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3.Agents/ValidateAgent", + request_serializer=agent.ValidateAgentRequest.serialize, + response_deserializer=agent.AgentValidationResult.deserialize, + ) + return self._stubs["validate_agent"] + + @property + def get_agent_validation_result( + self, + ) -> Callable[[agent.GetAgentValidationResultRequest], agent.AgentValidationResult]: + r"""Return a callable for the get agent validation result method over gRPC. + + Gets the latest agent validation result. Agent + validation is performed when ValidateAgent is called. + + Returns: + Callable[[~.GetAgentValidationResultRequest], + ~.AgentValidationResult]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_agent_validation_result" not in self._stubs: + self._stubs["get_agent_validation_result"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3.Agents/GetAgentValidationResult", + request_serializer=agent.GetAgentValidationResultRequest.serialize, + response_deserializer=agent.AgentValidationResult.deserialize, + ) + return self._stubs["get_agent_validation_result"] + __all__ = ("AgentsGrpcTransport",) diff --git a/google/cloud/dialogflowcx_v3/services/agents/transports/grpc_asyncio.py b/google/cloud/dialogflowcx_v3/services/agents/transports/grpc_asyncio.py index fb4eb8fb..30d00bd9 100644 --- a/google/cloud/dialogflowcx_v3/services/agents/transports/grpc_asyncio.py +++ b/google/cloud/dialogflowcx_v3/services/agents/transports/grpc_asyncio.py @@ -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,6 +137,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): @@ -152,6 +157,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -161,11 +171,6 @@ def __init__( 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 @@ -209,12 +214,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ @@ -446,5 +457,63 @@ def restore_agent( ) return self._stubs["restore_agent"] + @property + def validate_agent( + self, + ) -> Callable[[agent.ValidateAgentRequest], Awaitable[agent.AgentValidationResult]]: + r"""Return a callable for the validate agent method over gRPC. + + Validates the specified agent and creates or updates + validation results. The agent in draft version is + validated. Please call this API after the training is + completed to get the complete validation results. + + Returns: + Callable[[~.ValidateAgentRequest], + Awaitable[~.AgentValidationResult]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "validate_agent" not in self._stubs: + self._stubs["validate_agent"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3.Agents/ValidateAgent", + request_serializer=agent.ValidateAgentRequest.serialize, + response_deserializer=agent.AgentValidationResult.deserialize, + ) + return self._stubs["validate_agent"] + + @property + def get_agent_validation_result( + self, + ) -> Callable[ + [agent.GetAgentValidationResultRequest], Awaitable[agent.AgentValidationResult] + ]: + r"""Return a callable for the get agent validation result method over gRPC. + + Gets the latest agent validation result. Agent + validation is performed when ValidateAgent is called. + + Returns: + Callable[[~.GetAgentValidationResultRequest], + Awaitable[~.AgentValidationResult]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_agent_validation_result" not in self._stubs: + self._stubs["get_agent_validation_result"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3.Agents/GetAgentValidationResult", + request_serializer=agent.GetAgentValidationResultRequest.serialize, + response_deserializer=agent.AgentValidationResult.deserialize, + ) + return self._stubs["get_agent_validation_result"] + __all__ = ("AgentsGrpcAsyncIOTransport",) diff --git a/google/cloud/dialogflowcx_v3/services/entity_types/async_client.py b/google/cloud/dialogflowcx_v3/services/entity_types/async_client.py index 3397af5b..f74b07c0 100644 --- a/google/cloud/dialogflowcx_v3/services/entity_types/async_client.py +++ b/google/cloud/dialogflowcx_v3/services/entity_types/async_client.py @@ -76,7 +76,36 @@ class EntityTypesAsyncClient: EntityTypesClient.parse_common_location_path ) - from_service_account_file = EntityTypesClient.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: + EntityTypesAsyncClient: The constructed client. + """ + return EntityTypesClient.from_service_account_info.__func__(EntityTypesAsyncClient, 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: + EntityTypesAsyncClient: The constructed client. + """ + return EntityTypesClient.from_service_account_file.__func__(EntityTypesAsyncClient, filename, *args, **kwargs) # type: ignore + from_service_account_json = from_service_account_file @property @@ -153,13 +182,14 @@ async def list_entity_types( agent. Args: - request (:class:`~.entity_type.ListEntityTypesRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.ListEntityTypesRequest`): The request object. The request message for [EntityTypes.ListEntityTypes][google.cloud.dialogflow.cx.v3.EntityTypes.ListEntityTypes]. parent (:class:`str`): Required. The agent to list all entity types for. Format: ``projects//locations//agents/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -171,7 +201,7 @@ async def list_entity_types( sent along with the request as metadata. Returns: - ~.pagers.ListEntityTypesAsyncPager: + google.cloud.dialogflowcx_v3.services.entity_types.pagers.ListEntityTypesAsyncPager: The response message for [EntityTypes.ListEntityTypes][google.cloud.dialogflow.cx.v3.EntityTypes.ListEntityTypes]. @@ -235,12 +265,13 @@ async def get_entity_type( r"""Retrieves the specified entity type. Args: - request (:class:`~.entity_type.GetEntityTypeRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.GetEntityTypeRequest`): The request object. The request message for [EntityTypes.GetEntityType][google.cloud.dialogflow.cx.v3.EntityTypes.GetEntityType]. name (:class:`str`): Required. The name of the entity type. Format: ``projects//locations//agents//entityTypes/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -252,42 +283,41 @@ async def get_entity_type( sent along with the request as metadata. Returns: - ~.entity_type.EntityType: - Entities are extracted from user input and represent - parameters that are meaningful to your application. For - example, a date range, a proper name such as a - geographic location or landmark, and so on. Entities - represent actionable data for your application. - - When you define an entity, you can also include synonyms - that all map to that entity. For example, "soft drink", - "soda", "pop", and so on. - - There are three types of entities: - - - **System** - entities that are defined by the - Dialogflow API for common data types such as date, - time, currency, and so on. A system entity is - represented by the ``EntityType`` type. - - - **Custom** - entities that are defined by you that - represent actionable data that is meaningful to your - application. For example, you could define a - ``pizza.sauce`` entity for red or white pizza sauce, - a ``pizza.cheese`` entity for the different types of - cheese on a pizza, a ``pizza.topping`` entity for - different toppings, and so on. A custom entity is - represented by the ``EntityType`` type. - - - **User** - entities that are built for an individual - user such as favorites, preferences, playlists, and - so on. A user entity is represented by the - [SessionEntityType][google.cloud.dialogflow.cx.v3.SessionEntityType] - type. - - For more information about entity types, see the - `Dialogflow - documentation `__. + google.cloud.dialogflowcx_v3.types.EntityType: + Entities are extracted from user input and represent parameters that are + meaningful to your application. For example, a date + range, a proper name such as a geographic location or + landmark, and so on. Entities represent actionable + data for your application. + + When you define an entity, you can also include + synonyms that all map to that entity. For example, + "soft drink", "soda", "pop", and so on. + + There are three types of entities: + + - **System** - entities that are defined by the + Dialogflow API for common data types such as date, + time, currency, and so on. A system entity is + represented by the EntityType type. + - **Custom** - entities that are defined by you that + represent actionable data that is meaningful to + your application. For example, you could define a + pizza.sauce entity for red or white pizza sauce, a + pizza.cheese entity for the different types of + cheese on a pizza, a pizza.topping entity for + different toppings, and so on. A custom entity is + represented by the EntityType type. + - **User** - entities that are built for an + individual user such as favorites, preferences, + playlists, and so on. A user entity is represented + by the + [SessionEntityType][google.cloud.dialogflow.cx.v3.SessionEntityType] + type. + + For more information about entity types, see the + [Dialogflow + documentation](\ https://cloud.google.com/dialogflow/docs/entities-overview). """ # Create or coerce a protobuf request object. @@ -341,16 +371,17 @@ async def create_entity_type( r"""Creates an entity type in the specified agent. Args: - request (:class:`~.gcdc_entity_type.CreateEntityTypeRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.CreateEntityTypeRequest`): The request object. The request message for [EntityTypes.CreateEntityType][google.cloud.dialogflow.cx.v3.EntityTypes.CreateEntityType]. parent (:class:`str`): Required. The agent to create a entity type for. Format: ``projects//locations//agents/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - entity_type (:class:`~.gcdc_entity_type.EntityType`): + entity_type (:class:`google.cloud.dialogflowcx_v3.types.EntityType`): Required. The entity type to create. This corresponds to the ``entity_type`` field on the ``request`` instance; if ``request`` is provided, this @@ -363,42 +394,41 @@ async def create_entity_type( sent along with the request as metadata. Returns: - ~.gcdc_entity_type.EntityType: - Entities are extracted from user input and represent - parameters that are meaningful to your application. For - example, a date range, a proper name such as a - geographic location or landmark, and so on. Entities - represent actionable data for your application. - - When you define an entity, you can also include synonyms - that all map to that entity. For example, "soft drink", - "soda", "pop", and so on. - - There are three types of entities: - - - **System** - entities that are defined by the - Dialogflow API for common data types such as date, - time, currency, and so on. A system entity is - represented by the ``EntityType`` type. - - - **Custom** - entities that are defined by you that - represent actionable data that is meaningful to your - application. For example, you could define a - ``pizza.sauce`` entity for red or white pizza sauce, - a ``pizza.cheese`` entity for the different types of - cheese on a pizza, a ``pizza.topping`` entity for - different toppings, and so on. A custom entity is - represented by the ``EntityType`` type. - - - **User** - entities that are built for an individual - user such as favorites, preferences, playlists, and - so on. A user entity is represented by the - [SessionEntityType][google.cloud.dialogflow.cx.v3.SessionEntityType] - type. - - For more information about entity types, see the - `Dialogflow - documentation `__. + google.cloud.dialogflowcx_v3.types.EntityType: + Entities are extracted from user input and represent parameters that are + meaningful to your application. For example, a date + range, a proper name such as a geographic location or + landmark, and so on. Entities represent actionable + data for your application. + + When you define an entity, you can also include + synonyms that all map to that entity. For example, + "soft drink", "soda", "pop", and so on. + + There are three types of entities: + + - **System** - entities that are defined by the + Dialogflow API for common data types such as date, + time, currency, and so on. A system entity is + represented by the EntityType type. + - **Custom** - entities that are defined by you that + represent actionable data that is meaningful to + your application. For example, you could define a + pizza.sauce entity for red or white pizza sauce, a + pizza.cheese entity for the different types of + cheese on a pizza, a pizza.topping entity for + different toppings, and so on. A custom entity is + represented by the EntityType type. + - **User** - entities that are built for an + individual user such as favorites, preferences, + playlists, and so on. A user entity is represented + by the + [SessionEntityType][google.cloud.dialogflow.cx.v3.SessionEntityType] + type. + + For more information about entity types, see the + [Dialogflow + documentation](\ https://cloud.google.com/dialogflow/docs/entities-overview). """ # Create or coerce a protobuf request object. @@ -454,17 +484,18 @@ async def update_entity_type( r"""Updates the specified entity type. Args: - request (:class:`~.gcdc_entity_type.UpdateEntityTypeRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.UpdateEntityTypeRequest`): The request object. The request message for [EntityTypes.UpdateEntityType][google.cloud.dialogflow.cx.v3.EntityTypes.UpdateEntityType]. - entity_type (:class:`~.gcdc_entity_type.EntityType`): + entity_type (:class:`google.cloud.dialogflowcx_v3.types.EntityType`): Required. The entity type to update. This corresponds to the ``entity_type`` 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`): The mask to control which fields get updated. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -476,42 +507,41 @@ async def update_entity_type( sent along with the request as metadata. Returns: - ~.gcdc_entity_type.EntityType: - Entities are extracted from user input and represent - parameters that are meaningful to your application. For - example, a date range, a proper name such as a - geographic location or landmark, and so on. Entities - represent actionable data for your application. - - When you define an entity, you can also include synonyms - that all map to that entity. For example, "soft drink", - "soda", "pop", and so on. - - There are three types of entities: - - - **System** - entities that are defined by the - Dialogflow API for common data types such as date, - time, currency, and so on. A system entity is - represented by the ``EntityType`` type. - - - **Custom** - entities that are defined by you that - represent actionable data that is meaningful to your - application. For example, you could define a - ``pizza.sauce`` entity for red or white pizza sauce, - a ``pizza.cheese`` entity for the different types of - cheese on a pizza, a ``pizza.topping`` entity for - different toppings, and so on. A custom entity is - represented by the ``EntityType`` type. - - - **User** - entities that are built for an individual - user such as favorites, preferences, playlists, and - so on. A user entity is represented by the - [SessionEntityType][google.cloud.dialogflow.cx.v3.SessionEntityType] - type. - - For more information about entity types, see the - `Dialogflow - documentation `__. + google.cloud.dialogflowcx_v3.types.EntityType: + Entities are extracted from user input and represent parameters that are + meaningful to your application. For example, a date + range, a proper name such as a geographic location or + landmark, and so on. Entities represent actionable + data for your application. + + When you define an entity, you can also include + synonyms that all map to that entity. For example, + "soft drink", "soda", "pop", and so on. + + There are three types of entities: + + - **System** - entities that are defined by the + Dialogflow API for common data types such as date, + time, currency, and so on. A system entity is + represented by the EntityType type. + - **Custom** - entities that are defined by you that + represent actionable data that is meaningful to + your application. For example, you could define a + pizza.sauce entity for red or white pizza sauce, a + pizza.cheese entity for the different types of + cheese on a pizza, a pizza.topping entity for + different toppings, and so on. A custom entity is + represented by the EntityType type. + - **User** - entities that are built for an + individual user such as favorites, preferences, + playlists, and so on. A user entity is represented + by the + [SessionEntityType][google.cloud.dialogflow.cx.v3.SessionEntityType] + type. + + For more information about entity types, see the + [Dialogflow + documentation](\ https://cloud.google.com/dialogflow/docs/entities-overview). """ # Create or coerce a protobuf request object. @@ -568,12 +598,13 @@ async def delete_entity_type( r"""Deletes the specified entity type. Args: - request (:class:`~.entity_type.DeleteEntityTypeRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.DeleteEntityTypeRequest`): The request object. The request message for [EntityTypes.DeleteEntityType][google.cloud.dialogflow.cx.v3.EntityTypes.DeleteEntityType]. name (:class:`str`): Required. The name of the entity type to delete. Format: ``projects//locations//agents//entityTypes/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. diff --git a/google/cloud/dialogflowcx_v3/services/entity_types/client.py b/google/cloud/dialogflowcx_v3/services/entity_types/client.py index aacf1f5e..852b3ef4 100644 --- a/google/cloud/dialogflowcx_v3/services/entity_types/client.py +++ b/google/cloud/dialogflowcx_v3/services/entity_types/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: + EntityTypesClient: 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. + EntityTypesClient: The constructed client. """ credentials = service_account.Credentials.from_service_account_file(filename) kwargs["credentials"] = credentials @@ -234,10 +250,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, ~.EntityTypesTransport]): The + transport (Union[str, EntityTypesTransport]): 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 @@ -273,21 +289,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: @@ -330,7 +342,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, ) @@ -348,13 +360,14 @@ def list_entity_types( agent. Args: - request (:class:`~.entity_type.ListEntityTypesRequest`): + request (google.cloud.dialogflowcx_v3.types.ListEntityTypesRequest): The request object. The request message for [EntityTypes.ListEntityTypes][google.cloud.dialogflow.cx.v3.EntityTypes.ListEntityTypes]. - parent (:class:`str`): + parent (str): Required. The agent to list all entity types for. Format: ``projects//locations//agents/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -366,7 +379,7 @@ def list_entity_types( sent along with the request as metadata. Returns: - ~.pagers.ListEntityTypesPager: + google.cloud.dialogflowcx_v3.services.entity_types.pagers.ListEntityTypesPager: The response message for [EntityTypes.ListEntityTypes][google.cloud.dialogflow.cx.v3.EntityTypes.ListEntityTypes]. @@ -431,12 +444,13 @@ def get_entity_type( r"""Retrieves the specified entity type. Args: - request (:class:`~.entity_type.GetEntityTypeRequest`): + request (google.cloud.dialogflowcx_v3.types.GetEntityTypeRequest): The request object. The request message for [EntityTypes.GetEntityType][google.cloud.dialogflow.cx.v3.EntityTypes.GetEntityType]. - name (:class:`str`): + name (str): Required. The name of the entity type. Format: ``projects//locations//agents//entityTypes/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -448,42 +462,41 @@ def get_entity_type( sent along with the request as metadata. Returns: - ~.entity_type.EntityType: - Entities are extracted from user input and represent - parameters that are meaningful to your application. For - example, a date range, a proper name such as a - geographic location or landmark, and so on. Entities - represent actionable data for your application. - - When you define an entity, you can also include synonyms - that all map to that entity. For example, "soft drink", - "soda", "pop", and so on. - - There are three types of entities: - - - **System** - entities that are defined by the - Dialogflow API for common data types such as date, - time, currency, and so on. A system entity is - represented by the ``EntityType`` type. - - - **Custom** - entities that are defined by you that - represent actionable data that is meaningful to your - application. For example, you could define a - ``pizza.sauce`` entity for red or white pizza sauce, - a ``pizza.cheese`` entity for the different types of - cheese on a pizza, a ``pizza.topping`` entity for - different toppings, and so on. A custom entity is - represented by the ``EntityType`` type. - - - **User** - entities that are built for an individual - user such as favorites, preferences, playlists, and - so on. A user entity is represented by the - [SessionEntityType][google.cloud.dialogflow.cx.v3.SessionEntityType] - type. - - For more information about entity types, see the - `Dialogflow - documentation `__. + google.cloud.dialogflowcx_v3.types.EntityType: + Entities are extracted from user input and represent parameters that are + meaningful to your application. For example, a date + range, a proper name such as a geographic location or + landmark, and so on. Entities represent actionable + data for your application. + + When you define an entity, you can also include + synonyms that all map to that entity. For example, + "soft drink", "soda", "pop", and so on. + + There are three types of entities: + + - **System** - entities that are defined by the + Dialogflow API for common data types such as date, + time, currency, and so on. A system entity is + represented by the EntityType type. + - **Custom** - entities that are defined by you that + represent actionable data that is meaningful to + your application. For example, you could define a + pizza.sauce entity for red or white pizza sauce, a + pizza.cheese entity for the different types of + cheese on a pizza, a pizza.topping entity for + different toppings, and so on. A custom entity is + represented by the EntityType type. + - **User** - entities that are built for an + individual user such as favorites, preferences, + playlists, and so on. A user entity is represented + by the + [SessionEntityType][google.cloud.dialogflow.cx.v3.SessionEntityType] + type. + + For more information about entity types, see the + [Dialogflow + documentation](\ https://cloud.google.com/dialogflow/docs/entities-overview). """ # Create or coerce a protobuf request object. @@ -538,16 +551,17 @@ def create_entity_type( r"""Creates an entity type in the specified agent. Args: - request (:class:`~.gcdc_entity_type.CreateEntityTypeRequest`): + request (google.cloud.dialogflowcx_v3.types.CreateEntityTypeRequest): The request object. The request message for [EntityTypes.CreateEntityType][google.cloud.dialogflow.cx.v3.EntityTypes.CreateEntityType]. - parent (:class:`str`): + parent (str): Required. The agent to create a entity type for. Format: ``projects//locations//agents/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - entity_type (:class:`~.gcdc_entity_type.EntityType`): + entity_type (google.cloud.dialogflowcx_v3.types.EntityType): Required. The entity type to create. This corresponds to the ``entity_type`` field on the ``request`` instance; if ``request`` is provided, this @@ -560,42 +574,41 @@ def create_entity_type( sent along with the request as metadata. Returns: - ~.gcdc_entity_type.EntityType: - Entities are extracted from user input and represent - parameters that are meaningful to your application. For - example, a date range, a proper name such as a - geographic location or landmark, and so on. Entities - represent actionable data for your application. - - When you define an entity, you can also include synonyms - that all map to that entity. For example, "soft drink", - "soda", "pop", and so on. - - There are three types of entities: - - - **System** - entities that are defined by the - Dialogflow API for common data types such as date, - time, currency, and so on. A system entity is - represented by the ``EntityType`` type. - - - **Custom** - entities that are defined by you that - represent actionable data that is meaningful to your - application. For example, you could define a - ``pizza.sauce`` entity for red or white pizza sauce, - a ``pizza.cheese`` entity for the different types of - cheese on a pizza, a ``pizza.topping`` entity for - different toppings, and so on. A custom entity is - represented by the ``EntityType`` type. - - - **User** - entities that are built for an individual - user such as favorites, preferences, playlists, and - so on. A user entity is represented by the - [SessionEntityType][google.cloud.dialogflow.cx.v3.SessionEntityType] - type. - - For more information about entity types, see the - `Dialogflow - documentation `__. + google.cloud.dialogflowcx_v3.types.EntityType: + Entities are extracted from user input and represent parameters that are + meaningful to your application. For example, a date + range, a proper name such as a geographic location or + landmark, and so on. Entities represent actionable + data for your application. + + When you define an entity, you can also include + synonyms that all map to that entity. For example, + "soft drink", "soda", "pop", and so on. + + There are three types of entities: + + - **System** - entities that are defined by the + Dialogflow API for common data types such as date, + time, currency, and so on. A system entity is + represented by the EntityType type. + - **Custom** - entities that are defined by you that + represent actionable data that is meaningful to + your application. For example, you could define a + pizza.sauce entity for red or white pizza sauce, a + pizza.cheese entity for the different types of + cheese on a pizza, a pizza.topping entity for + different toppings, and so on. A custom entity is + represented by the EntityType type. + - **User** - entities that are built for an + individual user such as favorites, preferences, + playlists, and so on. A user entity is represented + by the + [SessionEntityType][google.cloud.dialogflow.cx.v3.SessionEntityType] + type. + + For more information about entity types, see the + [Dialogflow + documentation](\ https://cloud.google.com/dialogflow/docs/entities-overview). """ # Create or coerce a protobuf request object. @@ -652,17 +665,18 @@ def update_entity_type( r"""Updates the specified entity type. Args: - request (:class:`~.gcdc_entity_type.UpdateEntityTypeRequest`): + request (google.cloud.dialogflowcx_v3.types.UpdateEntityTypeRequest): The request object. The request message for [EntityTypes.UpdateEntityType][google.cloud.dialogflow.cx.v3.EntityTypes.UpdateEntityType]. - entity_type (:class:`~.gcdc_entity_type.EntityType`): + entity_type (google.cloud.dialogflowcx_v3.types.EntityType): Required. The entity type to update. This corresponds to the ``entity_type`` 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): The mask to control which fields get updated. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -674,42 +688,41 @@ def update_entity_type( sent along with the request as metadata. Returns: - ~.gcdc_entity_type.EntityType: - Entities are extracted from user input and represent - parameters that are meaningful to your application. For - example, a date range, a proper name such as a - geographic location or landmark, and so on. Entities - represent actionable data for your application. - - When you define an entity, you can also include synonyms - that all map to that entity. For example, "soft drink", - "soda", "pop", and so on. - - There are three types of entities: - - - **System** - entities that are defined by the - Dialogflow API for common data types such as date, - time, currency, and so on. A system entity is - represented by the ``EntityType`` type. - - - **Custom** - entities that are defined by you that - represent actionable data that is meaningful to your - application. For example, you could define a - ``pizza.sauce`` entity for red or white pizza sauce, - a ``pizza.cheese`` entity for the different types of - cheese on a pizza, a ``pizza.topping`` entity for - different toppings, and so on. A custom entity is - represented by the ``EntityType`` type. - - - **User** - entities that are built for an individual - user such as favorites, preferences, playlists, and - so on. A user entity is represented by the - [SessionEntityType][google.cloud.dialogflow.cx.v3.SessionEntityType] - type. - - For more information about entity types, see the - `Dialogflow - documentation `__. + google.cloud.dialogflowcx_v3.types.EntityType: + Entities are extracted from user input and represent parameters that are + meaningful to your application. For example, a date + range, a proper name such as a geographic location or + landmark, and so on. Entities represent actionable + data for your application. + + When you define an entity, you can also include + synonyms that all map to that entity. For example, + "soft drink", "soda", "pop", and so on. + + There are three types of entities: + + - **System** - entities that are defined by the + Dialogflow API for common data types such as date, + time, currency, and so on. A system entity is + represented by the EntityType type. + - **Custom** - entities that are defined by you that + represent actionable data that is meaningful to + your application. For example, you could define a + pizza.sauce entity for red or white pizza sauce, a + pizza.cheese entity for the different types of + cheese on a pizza, a pizza.topping entity for + different toppings, and so on. A custom entity is + represented by the EntityType type. + - **User** - entities that are built for an + individual user such as favorites, preferences, + playlists, and so on. A user entity is represented + by the + [SessionEntityType][google.cloud.dialogflow.cx.v3.SessionEntityType] + type. + + For more information about entity types, see the + [Dialogflow + documentation](\ https://cloud.google.com/dialogflow/docs/entities-overview). """ # Create or coerce a protobuf request object. @@ -767,12 +780,13 @@ def delete_entity_type( r"""Deletes the specified entity type. Args: - request (:class:`~.entity_type.DeleteEntityTypeRequest`): + request (google.cloud.dialogflowcx_v3.types.DeleteEntityTypeRequest): The request object. The request message for [EntityTypes.DeleteEntityType][google.cloud.dialogflow.cx.v3.EntityTypes.DeleteEntityType]. - name (:class:`str`): + name (str): Required. The name of the entity type to delete. Format: ``projects//locations//agents//entityTypes/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. diff --git a/google/cloud/dialogflowcx_v3/services/entity_types/pagers.py b/google/cloud/dialogflowcx_v3/services/entity_types/pagers.py index edafb73d..5a575953 100644 --- a/google/cloud/dialogflowcx_v3/services/entity_types/pagers.py +++ b/google/cloud/dialogflowcx_v3/services/entity_types/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.dialogflowcx_v3.types import entity_type @@ -24,7 +33,7 @@ class ListEntityTypesPager: """A pager for iterating through ``list_entity_types`` requests. This class thinly wraps an initial - :class:`~.entity_type.ListEntityTypesResponse` object, and + :class:`google.cloud.dialogflowcx_v3.types.ListEntityTypesResponse` object, and provides an ``__iter__`` method to iterate through its ``entity_types`` field. @@ -33,7 +42,7 @@ class ListEntityTypesPager: through the ``entity_types`` field on the corresponding responses. - All the usual :class:`~.entity_type.ListEntityTypesResponse` + All the usual :class:`google.cloud.dialogflowcx_v3.types.ListEntityTypesResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -51,9 +60,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.entity_type.ListEntityTypesRequest`): + request (google.cloud.dialogflowcx_v3.types.ListEntityTypesRequest): The initial request object. - response (:class:`~.entity_type.ListEntityTypesResponse`): + response (google.cloud.dialogflowcx_v3.types.ListEntityTypesResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -86,7 +95,7 @@ class ListEntityTypesAsyncPager: """A pager for iterating through ``list_entity_types`` requests. This class thinly wraps an initial - :class:`~.entity_type.ListEntityTypesResponse` object, and + :class:`google.cloud.dialogflowcx_v3.types.ListEntityTypesResponse` object, and provides an ``__aiter__`` method to iterate through its ``entity_types`` field. @@ -95,7 +104,7 @@ class ListEntityTypesAsyncPager: through the ``entity_types`` field on the corresponding responses. - All the usual :class:`~.entity_type.ListEntityTypesResponse` + All the usual :class:`google.cloud.dialogflowcx_v3.types.ListEntityTypesResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -113,9 +122,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.entity_type.ListEntityTypesRequest`): + request (google.cloud.dialogflowcx_v3.types.ListEntityTypesRequest): The initial request object. - response (:class:`~.entity_type.ListEntityTypesResponse`): + response (google.cloud.dialogflowcx_v3.types.ListEntityTypesResponse): 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/dialogflowcx_v3/services/entity_types/transports/grpc.py b/google/cloud/dialogflowcx_v3/services/entity_types/transports/grpc.py index e4f92f71..24b05efe 100644 --- a/google/cloud/dialogflowcx_v3/services/entity_types/transports/grpc.py +++ b/google/cloud/dialogflowcx_v3/services/entity_types/transports/grpc.py @@ -60,6 +60,7 @@ def __init__( api_mtls_endpoint: str = None, client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, quota_project_id: Optional[str] = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: @@ -90,6 +91,10 @@ def __init__( ``api_mtls_endpoint`` is None. ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials for grpc channel. It is ignored if ``channel`` is provided. + client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]): + A callback to provide client certificate bytes and private key bytes, + both in PEM format. It is used to configure mutual TLS channel. It is + ignored if ``channel`` or ``ssl_channel_credentials`` is provided. quota_project_id (Optional[str]): An optional project to use for billing and quota. client_info (google.api_core.gapic_v1.client_info.ClientInfo): @@ -106,6 +111,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -115,11 +125,6 @@ def __init__( 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 @@ -163,12 +168,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ diff --git a/google/cloud/dialogflowcx_v3/services/entity_types/transports/grpc_asyncio.py b/google/cloud/dialogflowcx_v3/services/entity_types/transports/grpc_asyncio.py index a3c09563..210f2c7f 100644 --- a/google/cloud/dialogflowcx_v3/services/entity_types/transports/grpc_asyncio.py +++ b/google/cloud/dialogflowcx_v3/services/entity_types/transports/grpc_asyncio.py @@ -104,6 +104,7 @@ def __init__( api_mtls_endpoint: str = None, client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, quota_project_id=None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: @@ -135,6 +136,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): @@ -151,6 +156,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -160,11 +170,6 @@ def __init__( 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 @@ -208,12 +213,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ diff --git a/google/cloud/dialogflowcx_v3/services/environments/async_client.py b/google/cloud/dialogflowcx_v3/services/environments/async_client.py index edf94a12..542ce93b 100644 --- a/google/cloud/dialogflowcx_v3/services/environments/async_client.py +++ b/google/cloud/dialogflowcx_v3/services/environments/async_client.py @@ -82,7 +82,36 @@ class EnvironmentsAsyncClient: EnvironmentsClient.parse_common_location_path ) - from_service_account_file = EnvironmentsClient.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: + EnvironmentsAsyncClient: The constructed client. + """ + return EnvironmentsClient.from_service_account_info.__func__(EnvironmentsAsyncClient, 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: + EnvironmentsAsyncClient: The constructed client. + """ + return EnvironmentsClient.from_service_account_file.__func__(EnvironmentsAsyncClient, filename, *args, **kwargs) # type: ignore + from_service_account_json = from_service_account_file @property @@ -159,7 +188,7 @@ async def list_environments( [Agent][google.cloud.dialogflow.cx.v3.Agent]. Args: - request (:class:`~.environment.ListEnvironmentsRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.ListEnvironmentsRequest`): The request object. The request message for [Environments.ListEnvironments][google.cloud.dialogflow.cx.v3.Environments.ListEnvironments]. parent (:class:`str`): @@ -167,6 +196,7 @@ async def list_environments( [Agent][google.cloud.dialogflow.cx.v3.Agent] to list all environments for. Format: ``projects//locations//agents/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -178,7 +208,7 @@ async def list_environments( sent along with the request as metadata. Returns: - ~.pagers.ListEnvironmentsAsyncPager: + google.cloud.dialogflowcx_v3.services.environments.pagers.ListEnvironmentsAsyncPager: The response message for [Environments.ListEnvironments][google.cloud.dialogflow.cx.v3.Environments.ListEnvironments]. @@ -243,7 +273,7 @@ async def get_environment( [Environment][google.cloud.dialogflow.cx.v3.Environment]. Args: - request (:class:`~.environment.GetEnvironmentRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.GetEnvironmentRequest`): The request object. The request message for [Environments.GetEnvironment][google.cloud.dialogflow.cx.v3.Environments.GetEnvironment]. name (:class:`str`): @@ -251,6 +281,7 @@ async def get_environment( [Environment][google.cloud.dialogflow.cx.v3.Environment]. Format: ``projects//locations//agents//environments/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -262,7 +293,7 @@ async def get_environment( sent along with the request as metadata. Returns: - ~.environment.Environment: + google.cloud.dialogflowcx_v3.types.Environment: Represents an environment for an agent. You can create multiple versions of your agent and publish them to @@ -333,7 +364,7 @@ async def create_environment( specified [Agent][google.cloud.dialogflow.cx.v3.Agent]. Args: - request (:class:`~.gcdc_environment.CreateEnvironmentRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.CreateEnvironmentRequest`): The request object. The request message for [Environments.CreateEnvironment][google.cloud.dialogflow.cx.v3.Environments.CreateEnvironment]. parent (:class:`str`): @@ -343,10 +374,11 @@ async def create_environment( [Environment][google.cloud.dialogflow.cx.v3.Environment] for. Format: ``projects//locations//agents/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - environment (:class:`~.gcdc_environment.Environment`): + environment (:class:`google.cloud.dialogflowcx_v3.types.Environment`): Required. The environment to create. This corresponds to the ``environment`` field on the ``request`` instance; if ``request`` is provided, this @@ -359,21 +391,20 @@ async def create_environment( 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:``~.gcdc_environment.Environment``: Represents an - environment for an agent. You can create multiple - versions of your agent and publish them to separate - environments. When you edit an agent, you are editing - the draft agent. At any point, you can save the draft - agent as an agent version, which is an immutable - snapshot of your agent. When you save the draft agent, - it is published to the default environment. When you - create agent versions, you can publish them to custom - environments. You can create a variety of custom - environments for testing, development, production, etc. + The result type for the operation will be :class:`google.cloud.dialogflowcx_v3.types.Environment` Represents an environment for an agent. You can create multiple versions + of your agent and publish them to separate + environments. When you edit an agent, you are editing + the draft agent. At any point, you can save the draft + agent as an agent version, which is an immutable + snapshot of your agent. When you save the draft + agent, it is published to the default environment. + When you create agent versions, you can publish them + to custom environments. You can create a variety of + custom environments for testing, development, + production, etc. """ # Create or coerce a protobuf request object. @@ -438,17 +469,18 @@ async def update_environment( [Environment][google.cloud.dialogflow.cx.v3.Environment]. Args: - request (:class:`~.gcdc_environment.UpdateEnvironmentRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.UpdateEnvironmentRequest`): The request object. The request message for [Environments.UpdateEnvironment][google.cloud.dialogflow.cx.v3.Environments.UpdateEnvironment]. - environment (:class:`~.gcdc_environment.Environment`): + environment (:class:`google.cloud.dialogflowcx_v3.types.Environment`): Required. The environment to update. This corresponds to the ``environment`` 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`): Required. The mask to control which fields get updated. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -460,21 +492,20 @@ async def update_environment( 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:``~.gcdc_environment.Environment``: Represents an - environment for an agent. You can create multiple - versions of your agent and publish them to separate - environments. When you edit an agent, you are editing - the draft agent. At any point, you can save the draft - agent as an agent version, which is an immutable - snapshot of your agent. When you save the draft agent, - it is published to the default environment. When you - create agent versions, you can publish them to custom - environments. You can create a variety of custom - environments for testing, development, production, etc. + The result type for the operation will be :class:`google.cloud.dialogflowcx_v3.types.Environment` Represents an environment for an agent. You can create multiple versions + of your agent and publish them to separate + environments. When you edit an agent, you are editing + the draft agent. At any point, you can save the draft + agent as an agent version, which is an immutable + snapshot of your agent. When you save the draft + agent, it is published to the default environment. + When you create agent versions, you can publish them + to custom environments. You can create a variety of + custom environments for testing, development, + production, etc. """ # Create or coerce a protobuf request object. @@ -540,7 +571,7 @@ async def delete_environment( [Environment][google.cloud.dialogflow.cx.v3.Environment]. Args: - request (:class:`~.environment.DeleteEnvironmentRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.DeleteEnvironmentRequest`): The request object. The request message for [Environments.DeleteEnvironment][google.cloud.dialogflow.cx.v3.Environments.DeleteEnvironment]. name (:class:`str`): @@ -548,6 +579,7 @@ async def delete_environment( [Environment][google.cloud.dialogflow.cx.v3.Environment] to delete. Format: ``projects//locations//agents//environments/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -608,13 +640,14 @@ async def lookup_environment_history( [Environment][google.cloud.dialogflow.cx.v3.Environment]. Args: - request (:class:`~.environment.LookupEnvironmentHistoryRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.LookupEnvironmentHistoryRequest`): The request object. The request message for [Environments.LookupEnvironmentHistory][google.cloud.dialogflow.cx.v3.Environments.LookupEnvironmentHistory]. name (:class:`str`): Required. Resource name of the environment to look up the history for. Format: ``projects//locations//agents//environments/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -626,7 +659,7 @@ async def lookup_environment_history( sent along with the request as metadata. Returns: - ~.pagers.LookupEnvironmentHistoryAsyncPager: + google.cloud.dialogflowcx_v3.services.environments.pagers.LookupEnvironmentHistoryAsyncPager: The response message for [Environments.LookupEnvironmentHistory][google.cloud.dialogflow.cx.v3.Environments.LookupEnvironmentHistory]. diff --git a/google/cloud/dialogflowcx_v3/services/environments/client.py b/google/cloud/dialogflowcx_v3/services/environments/client.py index 5acfe0b3..31600a28 100644 --- a/google/cloud/dialogflowcx_v3/services/environments/client.py +++ b/google/cloud/dialogflowcx_v3/services/environments/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: + EnvironmentsClient: 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. + EnvironmentsClient: The constructed client. """ credentials = service_account.Credentials.from_service_account_file(filename) kwargs["credentials"] = credentials @@ -256,10 +272,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, ~.EnvironmentsTransport]): The + transport (Union[str, EnvironmentsTransport]): 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 @@ -295,21 +311,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: @@ -352,7 +364,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, ) @@ -370,14 +382,15 @@ def list_environments( [Agent][google.cloud.dialogflow.cx.v3.Agent]. Args: - request (:class:`~.environment.ListEnvironmentsRequest`): + request (google.cloud.dialogflowcx_v3.types.ListEnvironmentsRequest): The request object. The request message for [Environments.ListEnvironments][google.cloud.dialogflow.cx.v3.Environments.ListEnvironments]. - parent (:class:`str`): + parent (str): Required. The [Agent][google.cloud.dialogflow.cx.v3.Agent] to list all environments for. Format: ``projects//locations//agents/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -389,7 +402,7 @@ def list_environments( sent along with the request as metadata. Returns: - ~.pagers.ListEnvironmentsPager: + google.cloud.dialogflowcx_v3.services.environments.pagers.ListEnvironmentsPager: The response message for [Environments.ListEnvironments][google.cloud.dialogflow.cx.v3.Environments.ListEnvironments]. @@ -455,14 +468,15 @@ def get_environment( [Environment][google.cloud.dialogflow.cx.v3.Environment]. Args: - request (:class:`~.environment.GetEnvironmentRequest`): + request (google.cloud.dialogflowcx_v3.types.GetEnvironmentRequest): The request object. The request message for [Environments.GetEnvironment][google.cloud.dialogflow.cx.v3.Environments.GetEnvironment]. - name (:class:`str`): + name (str): Required. The name of the [Environment][google.cloud.dialogflow.cx.v3.Environment]. Format: ``projects//locations//agents//environments/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -474,7 +488,7 @@ def get_environment( sent along with the request as metadata. Returns: - ~.environment.Environment: + google.cloud.dialogflowcx_v3.types.Environment: Represents an environment for an agent. You can create multiple versions of your agent and publish them to @@ -546,20 +560,21 @@ def create_environment( specified [Agent][google.cloud.dialogflow.cx.v3.Agent]. Args: - request (:class:`~.gcdc_environment.CreateEnvironmentRequest`): + request (google.cloud.dialogflowcx_v3.types.CreateEnvironmentRequest): The request object. The request message for [Environments.CreateEnvironment][google.cloud.dialogflow.cx.v3.Environments.CreateEnvironment]. - parent (:class:`str`): + parent (str): Required. The [Agent][google.cloud.dialogflow.cx.v3.Agent] to create an [Environment][google.cloud.dialogflow.cx.v3.Environment] for. Format: ``projects//locations//agents/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - environment (:class:`~.gcdc_environment.Environment`): + environment (google.cloud.dialogflowcx_v3.types.Environment): Required. The environment to create. This corresponds to the ``environment`` field on the ``request`` instance; if ``request`` is provided, this @@ -572,21 +587,20 @@ def create_environment( 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:``~.gcdc_environment.Environment``: Represents an - environment for an agent. You can create multiple - versions of your agent and publish them to separate - environments. When you edit an agent, you are editing - the draft agent. At any point, you can save the draft - agent as an agent version, which is an immutable - snapshot of your agent. When you save the draft agent, - it is published to the default environment. When you - create agent versions, you can publish them to custom - environments. You can create a variety of custom - environments for testing, development, production, etc. + The result type for the operation will be :class:`google.cloud.dialogflowcx_v3.types.Environment` Represents an environment for an agent. You can create multiple versions + of your agent and publish them to separate + environments. When you edit an agent, you are editing + the draft agent. At any point, you can save the draft + agent as an agent version, which is an immutable + snapshot of your agent. When you save the draft + agent, it is published to the default environment. + When you create agent versions, you can publish them + to custom environments. You can create a variety of + custom environments for testing, development, + production, etc. """ # Create or coerce a protobuf request object. @@ -652,17 +666,18 @@ def update_environment( [Environment][google.cloud.dialogflow.cx.v3.Environment]. Args: - request (:class:`~.gcdc_environment.UpdateEnvironmentRequest`): + request (google.cloud.dialogflowcx_v3.types.UpdateEnvironmentRequest): The request object. The request message for [Environments.UpdateEnvironment][google.cloud.dialogflow.cx.v3.Environments.UpdateEnvironment]. - environment (:class:`~.gcdc_environment.Environment`): + environment (google.cloud.dialogflowcx_v3.types.Environment): Required. The environment to update. This corresponds to the ``environment`` 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): Required. The mask to control which fields get updated. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -674,21 +689,20 @@ def update_environment( 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:``~.gcdc_environment.Environment``: Represents an - environment for an agent. You can create multiple - versions of your agent and publish them to separate - environments. When you edit an agent, you are editing - the draft agent. At any point, you can save the draft - agent as an agent version, which is an immutable - snapshot of your agent. When you save the draft agent, - it is published to the default environment. When you - create agent versions, you can publish them to custom - environments. You can create a variety of custom - environments for testing, development, production, etc. + The result type for the operation will be :class:`google.cloud.dialogflowcx_v3.types.Environment` Represents an environment for an agent. You can create multiple versions + of your agent and publish them to separate + environments. When you edit an agent, you are editing + the draft agent. At any point, you can save the draft + agent as an agent version, which is an immutable + snapshot of your agent. When you save the draft + agent, it is published to the default environment. + When you create agent versions, you can publish them + to custom environments. You can create a variety of + custom environments for testing, development, + production, etc. """ # Create or coerce a protobuf request object. @@ -755,14 +769,15 @@ def delete_environment( [Environment][google.cloud.dialogflow.cx.v3.Environment]. Args: - request (:class:`~.environment.DeleteEnvironmentRequest`): + request (google.cloud.dialogflowcx_v3.types.DeleteEnvironmentRequest): The request object. The request message for [Environments.DeleteEnvironment][google.cloud.dialogflow.cx.v3.Environments.DeleteEnvironment]. - name (:class:`str`): + name (str): Required. The name of the [Environment][google.cloud.dialogflow.cx.v3.Environment] to delete. Format: ``projects//locations//agents//environments/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -824,13 +839,14 @@ def lookup_environment_history( [Environment][google.cloud.dialogflow.cx.v3.Environment]. Args: - request (:class:`~.environment.LookupEnvironmentHistoryRequest`): + request (google.cloud.dialogflowcx_v3.types.LookupEnvironmentHistoryRequest): The request object. The request message for [Environments.LookupEnvironmentHistory][google.cloud.dialogflow.cx.v3.Environments.LookupEnvironmentHistory]. - name (:class:`str`): + name (str): Required. Resource name of the environment to look up the history for. Format: ``projects//locations//agents//environments/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -842,7 +858,7 @@ def lookup_environment_history( sent along with the request as metadata. Returns: - ~.pagers.LookupEnvironmentHistoryPager: + google.cloud.dialogflowcx_v3.services.environments.pagers.LookupEnvironmentHistoryPager: The response message for [Environments.LookupEnvironmentHistory][google.cloud.dialogflow.cx.v3.Environments.LookupEnvironmentHistory]. diff --git a/google/cloud/dialogflowcx_v3/services/environments/pagers.py b/google/cloud/dialogflowcx_v3/services/environments/pagers.py index ce8409a4..04e1b444 100644 --- a/google/cloud/dialogflowcx_v3/services/environments/pagers.py +++ b/google/cloud/dialogflowcx_v3/services/environments/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.dialogflowcx_v3.types import environment @@ -24,7 +33,7 @@ class ListEnvironmentsPager: """A pager for iterating through ``list_environments`` requests. This class thinly wraps an initial - :class:`~.environment.ListEnvironmentsResponse` object, and + :class:`google.cloud.dialogflowcx_v3.types.ListEnvironmentsResponse` object, and provides an ``__iter__`` method to iterate through its ``environments`` field. @@ -33,7 +42,7 @@ class ListEnvironmentsPager: through the ``environments`` field on the corresponding responses. - All the usual :class:`~.environment.ListEnvironmentsResponse` + All the usual :class:`google.cloud.dialogflowcx_v3.types.ListEnvironmentsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -51,9 +60,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.environment.ListEnvironmentsRequest`): + request (google.cloud.dialogflowcx_v3.types.ListEnvironmentsRequest): The initial request object. - response (:class:`~.environment.ListEnvironmentsResponse`): + response (google.cloud.dialogflowcx_v3.types.ListEnvironmentsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -86,7 +95,7 @@ class ListEnvironmentsAsyncPager: """A pager for iterating through ``list_environments`` requests. This class thinly wraps an initial - :class:`~.environment.ListEnvironmentsResponse` object, and + :class:`google.cloud.dialogflowcx_v3.types.ListEnvironmentsResponse` object, and provides an ``__aiter__`` method to iterate through its ``environments`` field. @@ -95,7 +104,7 @@ class ListEnvironmentsAsyncPager: through the ``environments`` field on the corresponding responses. - All the usual :class:`~.environment.ListEnvironmentsResponse` + All the usual :class:`google.cloud.dialogflowcx_v3.types.ListEnvironmentsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -113,9 +122,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.environment.ListEnvironmentsRequest`): + request (google.cloud.dialogflowcx_v3.types.ListEnvironmentsRequest): The initial request object. - response (:class:`~.environment.ListEnvironmentsResponse`): + response (google.cloud.dialogflowcx_v3.types.ListEnvironmentsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -152,7 +161,7 @@ class LookupEnvironmentHistoryPager: """A pager for iterating through ``lookup_environment_history`` requests. This class thinly wraps an initial - :class:`~.environment.LookupEnvironmentHistoryResponse` object, and + :class:`google.cloud.dialogflowcx_v3.types.LookupEnvironmentHistoryResponse` object, and provides an ``__iter__`` method to iterate through its ``environments`` field. @@ -161,7 +170,7 @@ class LookupEnvironmentHistoryPager: through the ``environments`` field on the corresponding responses. - All the usual :class:`~.environment.LookupEnvironmentHistoryResponse` + All the usual :class:`google.cloud.dialogflowcx_v3.types.LookupEnvironmentHistoryResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -179,9 +188,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.environment.LookupEnvironmentHistoryRequest`): + request (google.cloud.dialogflowcx_v3.types.LookupEnvironmentHistoryRequest): The initial request object. - response (:class:`~.environment.LookupEnvironmentHistoryResponse`): + response (google.cloud.dialogflowcx_v3.types.LookupEnvironmentHistoryResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -214,7 +223,7 @@ class LookupEnvironmentHistoryAsyncPager: """A pager for iterating through ``lookup_environment_history`` requests. This class thinly wraps an initial - :class:`~.environment.LookupEnvironmentHistoryResponse` object, and + :class:`google.cloud.dialogflowcx_v3.types.LookupEnvironmentHistoryResponse` object, and provides an ``__aiter__`` method to iterate through its ``environments`` field. @@ -223,7 +232,7 @@ class LookupEnvironmentHistoryAsyncPager: through the ``environments`` field on the corresponding responses. - All the usual :class:`~.environment.LookupEnvironmentHistoryResponse` + All the usual :class:`google.cloud.dialogflowcx_v3.types.LookupEnvironmentHistoryResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -241,9 +250,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.environment.LookupEnvironmentHistoryRequest`): + request (google.cloud.dialogflowcx_v3.types.LookupEnvironmentHistoryRequest): The initial request object. - response (:class:`~.environment.LookupEnvironmentHistoryResponse`): + response (google.cloud.dialogflowcx_v3.types.LookupEnvironmentHistoryResponse): 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/dialogflowcx_v3/services/environments/transports/grpc.py b/google/cloud/dialogflowcx_v3/services/environments/transports/grpc.py index 2ee7c39d..e73d51a4 100644 --- a/google/cloud/dialogflowcx_v3/services/environments/transports/grpc.py +++ b/google/cloud/dialogflowcx_v3/services/environments/transports/grpc.py @@ -62,6 +62,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: @@ -92,6 +93,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): @@ -108,6 +113,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -117,11 +127,6 @@ def __init__( 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 @@ -165,12 +170,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ diff --git a/google/cloud/dialogflowcx_v3/services/environments/transports/grpc_asyncio.py b/google/cloud/dialogflowcx_v3/services/environments/transports/grpc_asyncio.py index 4d0a66ca..b3b671e0 100644 --- a/google/cloud/dialogflowcx_v3/services/environments/transports/grpc_asyncio.py +++ b/google/cloud/dialogflowcx_v3/services/environments/transports/grpc_asyncio.py @@ -106,6 +106,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: @@ -137,6 +138,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): @@ -153,6 +158,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -162,11 +172,6 @@ def __init__( 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 @@ -210,12 +215,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ diff --git a/google/cloud/dialogflowcx_v3/services/experiments/async_client.py b/google/cloud/dialogflowcx_v3/services/experiments/async_client.py index 137f0250..045685d2 100644 --- a/google/cloud/dialogflowcx_v3/services/experiments/async_client.py +++ b/google/cloud/dialogflowcx_v3/services/experiments/async_client.py @@ -80,7 +80,36 @@ class ExperimentsAsyncClient: ExperimentsClient.parse_common_location_path ) - from_service_account_file = ExperimentsClient.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: + ExperimentsAsyncClient: The constructed client. + """ + return ExperimentsClient.from_service_account_info.__func__(ExperimentsAsyncClient, 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: + ExperimentsAsyncClient: The constructed client. + """ + return ExperimentsClient.from_service_account_file.__func__(ExperimentsAsyncClient, filename, *args, **kwargs) # type: ignore + from_service_account_json = from_service_account_file @property @@ -157,7 +186,7 @@ async def list_experiments( [Environment][google.cloud.dialogflow.cx.v3.Environment]. Args: - request (:class:`~.experiment.ListExperimentsRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.ListExperimentsRequest`): The request object. The request message for [Experiments.ListExperiments][google.cloud.dialogflow.cx.v3.Experiments.ListExperiments]. parent (:class:`str`): @@ -165,6 +194,7 @@ async def list_experiments( [Environment][google.cloud.dialogflow.cx.v3.Environment] to list all environments for. Format: ``projects//locations//agents//environments/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -176,7 +206,7 @@ async def list_experiments( sent along with the request as metadata. Returns: - ~.pagers.ListExperimentsAsyncPager: + google.cloud.dialogflowcx_v3.services.experiments.pagers.ListExperimentsAsyncPager: The response message for [Experiments.ListExperiments][google.cloud.dialogflow.cx.v3.Experiments.ListExperiments]. @@ -241,7 +271,7 @@ async def get_experiment( [Experiment][google.cloud.dialogflow.cx.v3.Experiment]. Args: - request (:class:`~.experiment.GetExperimentRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.GetExperimentRequest`): The request object. The request message for [Experiments.GetExperiment][google.cloud.dialogflow.cx.v3.Experiments.GetExperiment]. name (:class:`str`): @@ -249,6 +279,7 @@ async def get_experiment( [Environment][google.cloud.dialogflow.cx.v3.Environment]. Format: ``projects//locations//agents//environments//experiments/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -260,9 +291,9 @@ async def get_experiment( sent along with the request as metadata. Returns: - ~.experiment.Experiment: + google.cloud.dialogflowcx_v3.types.Experiment: Represents an experiment in an - environment. Next ID: 13 + environment. """ # Create or coerce a protobuf request object. @@ -319,7 +350,7 @@ async def create_experiment( [Environment][google.cloud.dialogflow.cx.v3.Environment]. Args: - request (:class:`~.gcdc_experiment.CreateExperimentRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.CreateExperimentRequest`): The request object. The request message for [Experiments.CreateExperiment][google.cloud.dialogflow.cx.v3.Experiments.CreateExperiment]. parent (:class:`str`): @@ -329,10 +360,11 @@ async def create_experiment( [Environment][google.cloud.dialogflow.cx.v3.Environment] for. Format: ``projects//locations//agents//environments/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - experiment (:class:`~.gcdc_experiment.Experiment`): + experiment (:class:`google.cloud.dialogflowcx_v3.types.Experiment`): Required. The experiment to create. This corresponds to the ``experiment`` field on the ``request`` instance; if ``request`` is provided, this @@ -345,9 +377,9 @@ async def create_experiment( sent along with the request as metadata. Returns: - ~.gcdc_experiment.Experiment: + google.cloud.dialogflowcx_v3.types.Experiment: Represents an experiment in an - environment. Next ID: 13 + environment. """ # Create or coerce a protobuf request object. @@ -404,17 +436,18 @@ async def update_experiment( [Experiment][google.cloud.dialogflow.cx.v3.Experiment]. Args: - request (:class:`~.gcdc_experiment.UpdateExperimentRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.UpdateExperimentRequest`): The request object. The request message for [Experiments.UpdateExperiment][google.cloud.dialogflow.cx.v3.Experiments.UpdateExperiment]. - experiment (:class:`~.gcdc_experiment.Experiment`): + experiment (:class:`google.cloud.dialogflowcx_v3.types.Experiment`): Required. The experiment to update. This corresponds to the ``experiment`` 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`): Required. The mask to control which fields get updated. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -426,9 +459,9 @@ async def update_experiment( sent along with the request as metadata. Returns: - ~.gcdc_experiment.Experiment: + google.cloud.dialogflowcx_v3.types.Experiment: Represents an experiment in an - environment. Next ID: 13 + environment. """ # Create or coerce a protobuf request object. @@ -486,7 +519,7 @@ async def delete_experiment( [Experiment][google.cloud.dialogflow.cx.v3.Experiment]. Args: - request (:class:`~.experiment.DeleteExperimentRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.DeleteExperimentRequest`): The request object. The request message for [Experiments.DeleteExperiment][google.cloud.dialogflow.cx.v3.Experiments.DeleteExperiment]. name (:class:`str`): @@ -494,6 +527,7 @@ async def delete_experiment( [Environment][google.cloud.dialogflow.cx.v3.Environment] to delete. Format: ``projects//locations//agents//environments//experiments/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -555,13 +589,14 @@ async def start_experiment( only changes the state of experiment from PENDING to RUNNING. Args: - request (:class:`~.experiment.StartExperimentRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.StartExperimentRequest`): The request object. The request message for [Experiments.StartExperiment][google.cloud.dialogflow.cx.v3.Experiments.StartExperiment]. name (:class:`str`): Required. Resource name of the experiment to start. Format: ``projects//locations//agents//environments//experiments/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -573,9 +608,9 @@ async def start_experiment( sent along with the request as metadata. Returns: - ~.experiment.Experiment: + google.cloud.dialogflowcx_v3.types.Experiment: Represents an experiment in an - environment. Next ID: 13 + environment. """ # Create or coerce a protobuf request object. @@ -630,13 +665,14 @@ async def stop_experiment( only changes the state of experiment from RUNNING to DONE. Args: - request (:class:`~.experiment.StopExperimentRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.StopExperimentRequest`): The request object. The request message for [Experiments.StopExperiment][google.cloud.dialogflow.cx.v3.Experiments.StopExperiment]. name (:class:`str`): Required. Resource name of the experiment to stop. Format: ``projects//locations//agents//environments//experiments/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -648,9 +684,9 @@ async def stop_experiment( sent along with the request as metadata. Returns: - ~.experiment.Experiment: + google.cloud.dialogflowcx_v3.types.Experiment: Represents an experiment in an - environment. Next ID: 13 + environment. """ # Create or coerce a protobuf request object. diff --git a/google/cloud/dialogflowcx_v3/services/experiments/client.py b/google/cloud/dialogflowcx_v3/services/experiments/client.py index 9e0984a8..2b3e5ea4 100644 --- a/google/cloud/dialogflowcx_v3/services/experiments/client.py +++ b/google/cloud/dialogflowcx_v3/services/experiments/client.py @@ -114,6 +114,22 @@ def _get_default_mtls_endpoint(api_endpoint): DEFAULT_ENDPOINT ) + @classmethod + def from_service_account_info(cls, info: dict, *args, **kwargs): + """Creates an instance of this client using the provided credentials info. + + Args: + info (dict): The service account private key info. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + ExperimentsClient: The constructed client. + """ + credentials = service_account.Credentials.from_service_account_info(info) + kwargs["credentials"] = credentials + return cls(*args, **kwargs) + @classmethod def from_service_account_file(cls, filename: str, *args, **kwargs): """Creates an instance of this client using the provided credentials @@ -126,7 +142,7 @@ def from_service_account_file(cls, filename: str, *args, **kwargs): kwargs: Additional arguments to pass to the constructor. Returns: - {@api.name}: The constructed client. + ExperimentsClient: The constructed client. """ credentials = service_account.Credentials.from_service_account_file(filename) kwargs["credentials"] = credentials @@ -258,10 +274,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, ~.ExperimentsTransport]): The + transport (Union[str, ExperimentsTransport]): 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 @@ -297,21 +313,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: @@ -354,7 +366,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, ) @@ -372,14 +384,15 @@ def list_experiments( [Environment][google.cloud.dialogflow.cx.v3.Environment]. Args: - request (:class:`~.experiment.ListExperimentsRequest`): + request (google.cloud.dialogflowcx_v3.types.ListExperimentsRequest): The request object. The request message for [Experiments.ListExperiments][google.cloud.dialogflow.cx.v3.Experiments.ListExperiments]. - parent (:class:`str`): + parent (str): Required. The [Environment][google.cloud.dialogflow.cx.v3.Environment] to list all environments for. Format: ``projects//locations//agents//environments/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -391,7 +404,7 @@ def list_experiments( sent along with the request as metadata. Returns: - ~.pagers.ListExperimentsPager: + google.cloud.dialogflowcx_v3.services.experiments.pagers.ListExperimentsPager: The response message for [Experiments.ListExperiments][google.cloud.dialogflow.cx.v3.Experiments.ListExperiments]. @@ -457,14 +470,15 @@ def get_experiment( [Experiment][google.cloud.dialogflow.cx.v3.Experiment]. Args: - request (:class:`~.experiment.GetExperimentRequest`): + request (google.cloud.dialogflowcx_v3.types.GetExperimentRequest): The request object. The request message for [Experiments.GetExperiment][google.cloud.dialogflow.cx.v3.Experiments.GetExperiment]. - name (:class:`str`): + name (str): Required. The name of the [Environment][google.cloud.dialogflow.cx.v3.Environment]. Format: ``projects//locations//agents//environments//experiments/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -476,9 +490,9 @@ def get_experiment( sent along with the request as metadata. Returns: - ~.experiment.Experiment: + google.cloud.dialogflowcx_v3.types.Experiment: Represents an experiment in an - environment. Next ID: 13 + environment. """ # Create or coerce a protobuf request object. @@ -536,20 +550,21 @@ def create_experiment( [Environment][google.cloud.dialogflow.cx.v3.Environment]. Args: - request (:class:`~.gcdc_experiment.CreateExperimentRequest`): + request (google.cloud.dialogflowcx_v3.types.CreateExperimentRequest): The request object. The request message for [Experiments.CreateExperiment][google.cloud.dialogflow.cx.v3.Experiments.CreateExperiment]. - parent (:class:`str`): + parent (str): Required. The [Agent][google.cloud.dialogflow.cx.v3.Agent] to create an [Environment][google.cloud.dialogflow.cx.v3.Environment] for. Format: ``projects//locations//agents//environments/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - experiment (:class:`~.gcdc_experiment.Experiment`): + experiment (google.cloud.dialogflowcx_v3.types.Experiment): Required. The experiment to create. This corresponds to the ``experiment`` field on the ``request`` instance; if ``request`` is provided, this @@ -562,9 +577,9 @@ def create_experiment( sent along with the request as metadata. Returns: - ~.gcdc_experiment.Experiment: + google.cloud.dialogflowcx_v3.types.Experiment: Represents an experiment in an - environment. Next ID: 13 + environment. """ # Create or coerce a protobuf request object. @@ -622,17 +637,18 @@ def update_experiment( [Experiment][google.cloud.dialogflow.cx.v3.Experiment]. Args: - request (:class:`~.gcdc_experiment.UpdateExperimentRequest`): + request (google.cloud.dialogflowcx_v3.types.UpdateExperimentRequest): The request object. The request message for [Experiments.UpdateExperiment][google.cloud.dialogflow.cx.v3.Experiments.UpdateExperiment]. - experiment (:class:`~.gcdc_experiment.Experiment`): + experiment (google.cloud.dialogflowcx_v3.types.Experiment): Required. The experiment to update. This corresponds to the ``experiment`` 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): Required. The mask to control which fields get updated. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -644,9 +660,9 @@ def update_experiment( sent along with the request as metadata. Returns: - ~.gcdc_experiment.Experiment: + google.cloud.dialogflowcx_v3.types.Experiment: Represents an experiment in an - environment. Next ID: 13 + environment. """ # Create or coerce a protobuf request object. @@ -705,14 +721,15 @@ def delete_experiment( [Experiment][google.cloud.dialogflow.cx.v3.Experiment]. Args: - request (:class:`~.experiment.DeleteExperimentRequest`): + request (google.cloud.dialogflowcx_v3.types.DeleteExperimentRequest): The request object. The request message for [Experiments.DeleteExperiment][google.cloud.dialogflow.cx.v3.Experiments.DeleteExperiment]. - name (:class:`str`): + name (str): Required. The name of the [Environment][google.cloud.dialogflow.cx.v3.Environment] to delete. Format: ``projects//locations//agents//environments//experiments/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -775,13 +792,14 @@ def start_experiment( only changes the state of experiment from PENDING to RUNNING. Args: - request (:class:`~.experiment.StartExperimentRequest`): + request (google.cloud.dialogflowcx_v3.types.StartExperimentRequest): The request object. The request message for [Experiments.StartExperiment][google.cloud.dialogflow.cx.v3.Experiments.StartExperiment]. - name (:class:`str`): + name (str): Required. Resource name of the experiment to start. Format: ``projects//locations//agents//environments//experiments/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -793,9 +811,9 @@ def start_experiment( sent along with the request as metadata. Returns: - ~.experiment.Experiment: + google.cloud.dialogflowcx_v3.types.Experiment: Represents an experiment in an - environment. Next ID: 13 + environment. """ # Create or coerce a protobuf request object. @@ -851,13 +869,14 @@ def stop_experiment( only changes the state of experiment from RUNNING to DONE. Args: - request (:class:`~.experiment.StopExperimentRequest`): + request (google.cloud.dialogflowcx_v3.types.StopExperimentRequest): The request object. The request message for [Experiments.StopExperiment][google.cloud.dialogflow.cx.v3.Experiments.StopExperiment]. - name (:class:`str`): + name (str): Required. Resource name of the experiment to stop. Format: ``projects//locations//agents//environments//experiments/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -869,9 +888,9 @@ def stop_experiment( sent along with the request as metadata. Returns: - ~.experiment.Experiment: + google.cloud.dialogflowcx_v3.types.Experiment: Represents an experiment in an - environment. Next ID: 13 + environment. """ # Create or coerce a protobuf request object. diff --git a/google/cloud/dialogflowcx_v3/services/experiments/pagers.py b/google/cloud/dialogflowcx_v3/services/experiments/pagers.py index 248a0d06..dbac2527 100644 --- a/google/cloud/dialogflowcx_v3/services/experiments/pagers.py +++ b/google/cloud/dialogflowcx_v3/services/experiments/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.dialogflowcx_v3.types import experiment @@ -24,7 +33,7 @@ class ListExperimentsPager: """A pager for iterating through ``list_experiments`` requests. This class thinly wraps an initial - :class:`~.experiment.ListExperimentsResponse` object, and + :class:`google.cloud.dialogflowcx_v3.types.ListExperimentsResponse` object, and provides an ``__iter__`` method to iterate through its ``experiments`` field. @@ -33,7 +42,7 @@ class ListExperimentsPager: through the ``experiments`` field on the corresponding responses. - All the usual :class:`~.experiment.ListExperimentsResponse` + All the usual :class:`google.cloud.dialogflowcx_v3.types.ListExperimentsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -51,9 +60,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.experiment.ListExperimentsRequest`): + request (google.cloud.dialogflowcx_v3.types.ListExperimentsRequest): The initial request object. - response (:class:`~.experiment.ListExperimentsResponse`): + response (google.cloud.dialogflowcx_v3.types.ListExperimentsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -86,7 +95,7 @@ class ListExperimentsAsyncPager: """A pager for iterating through ``list_experiments`` requests. This class thinly wraps an initial - :class:`~.experiment.ListExperimentsResponse` object, and + :class:`google.cloud.dialogflowcx_v3.types.ListExperimentsResponse` object, and provides an ``__aiter__`` method to iterate through its ``experiments`` field. @@ -95,7 +104,7 @@ class ListExperimentsAsyncPager: through the ``experiments`` field on the corresponding responses. - All the usual :class:`~.experiment.ListExperimentsResponse` + All the usual :class:`google.cloud.dialogflowcx_v3.types.ListExperimentsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -113,9 +122,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.experiment.ListExperimentsRequest`): + request (google.cloud.dialogflowcx_v3.types.ListExperimentsRequest): The initial request object. - response (:class:`~.experiment.ListExperimentsResponse`): + response (google.cloud.dialogflowcx_v3.types.ListExperimentsResponse): 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/dialogflowcx_v3/services/experiments/transports/grpc.py b/google/cloud/dialogflowcx_v3/services/experiments/transports/grpc.py index 316128d2..369bbd4c 100644 --- a/google/cloud/dialogflowcx_v3/services/experiments/transports/grpc.py +++ b/google/cloud/dialogflowcx_v3/services/experiments/transports/grpc.py @@ -60,6 +60,7 @@ def __init__( api_mtls_endpoint: str = None, client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, quota_project_id: Optional[str] = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: @@ -90,6 +91,10 @@ def __init__( ``api_mtls_endpoint`` is None. ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials for grpc channel. It is ignored if ``channel`` is provided. + client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]): + A callback to provide client certificate bytes and private key bytes, + both in PEM format. It is used to configure mutual TLS channel. It is + ignored if ``channel`` or ``ssl_channel_credentials`` is provided. quota_project_id (Optional[str]): An optional project to use for billing and quota. client_info (google.api_core.gapic_v1.client_info.ClientInfo): @@ -106,6 +111,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -115,11 +125,6 @@ def __init__( 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 @@ -163,12 +168,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ diff --git a/google/cloud/dialogflowcx_v3/services/experiments/transports/grpc_asyncio.py b/google/cloud/dialogflowcx_v3/services/experiments/transports/grpc_asyncio.py index 43f61395..237cc21c 100644 --- a/google/cloud/dialogflowcx_v3/services/experiments/transports/grpc_asyncio.py +++ b/google/cloud/dialogflowcx_v3/services/experiments/transports/grpc_asyncio.py @@ -104,6 +104,7 @@ def __init__( api_mtls_endpoint: str = None, client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, quota_project_id=None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: @@ -135,6 +136,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): @@ -151,6 +156,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -160,11 +170,6 @@ def __init__( 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 @@ -208,12 +213,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ diff --git a/google/cloud/dialogflowcx_v3/services/flows/async_client.py b/google/cloud/dialogflowcx_v3/services/flows/async_client.py index 31bfe6e6..e0235fe8 100644 --- a/google/cloud/dialogflowcx_v3/services/flows/async_client.py +++ b/google/cloud/dialogflowcx_v3/services/flows/async_client.py @@ -34,9 +34,11 @@ from google.cloud.dialogflowcx_v3.types import flow from google.cloud.dialogflowcx_v3.types import flow as gcdc_flow from google.cloud.dialogflowcx_v3.types import page +from google.cloud.dialogflowcx_v3.types import validation_message from google.protobuf import empty_pb2 as empty # type: ignore from google.protobuf import field_mask_pb2 as field_mask # type: ignore from google.protobuf import struct_pb2 as struct # type: ignore +from google.protobuf import timestamp_pb2 as timestamp # type: ignore from .transports.base import FlowsTransport, DEFAULT_CLIENT_INFO from .transports.grpc_asyncio import FlowsGrpcAsyncIOTransport @@ -53,6 +55,10 @@ class FlowsAsyncClient: flow_path = staticmethod(FlowsClient.flow_path) parse_flow_path = staticmethod(FlowsClient.parse_flow_path) + flow_validation_result_path = staticmethod(FlowsClient.flow_validation_result_path) + parse_flow_validation_result_path = staticmethod( + FlowsClient.parse_flow_validation_result_path + ) intent_path = staticmethod(FlowsClient.intent_path) parse_intent_path = staticmethod(FlowsClient.parse_intent_path) page_path = staticmethod(FlowsClient.page_path) @@ -79,7 +85,36 @@ class FlowsAsyncClient: common_location_path = staticmethod(FlowsClient.common_location_path) parse_common_location_path = staticmethod(FlowsClient.parse_common_location_path) - from_service_account_file = FlowsClient.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: + FlowsAsyncClient: The constructed client. + """ + return FlowsClient.from_service_account_info.__func__(FlowsAsyncClient, 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: + FlowsAsyncClient: The constructed client. + """ + return FlowsClient.from_service_account_file.__func__(FlowsAsyncClient, filename, *args, **kwargs) # type: ignore + from_service_account_json = from_service_account_file @property @@ -156,16 +191,17 @@ async def create_flow( r"""Creates a flow in the specified agent. Args: - request (:class:`~.gcdc_flow.CreateFlowRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.CreateFlowRequest`): The request object. The request message for [Flows.CreateFlow][google.cloud.dialogflow.cx.v3.Flows.CreateFlow]. parent (:class:`str`): Required. The agent to create a flow for. Format: ``projects//locations//agents/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - flow (:class:`~.gcdc_flow.Flow`): + flow (:class:`google.cloud.dialogflowcx_v3.types.Flow`): Required. The flow to create. This corresponds to the ``flow`` field on the ``request`` instance; if ``request`` is provided, this @@ -178,7 +214,7 @@ async def create_flow( sent along with the request as metadata. Returns: - ~.gcdc_flow.Flow: + google.cloud.dialogflowcx_v3.types.Flow: Flows represents the conversation flows when you build your chatbot agent. A flow consists of many pages connected @@ -256,12 +292,13 @@ async def delete_flow( r"""Deletes a specified flow. Args: - request (:class:`~.flow.DeleteFlowRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.DeleteFlowRequest`): The request object. The request message for [Flows.DeleteFlow][google.cloud.dialogflow.cx.v3.Flows.DeleteFlow]. name (:class:`str`): Required. The name of the flow to delete. Format: ``projects//locations//agents//flows/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -321,12 +358,13 @@ async def list_flows( r"""Returns the list of all flows in the specified agent. Args: - request (:class:`~.flow.ListFlowsRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.ListFlowsRequest`): The request object. The request message for [Flows.ListFlows][google.cloud.dialogflow.cx.v3.Flows.ListFlows]. parent (:class:`str`): Required. The agent containing the flows. Format: ``projects//locations//agents/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -338,7 +376,7 @@ async def list_flows( sent along with the request as metadata. Returns: - ~.pagers.ListFlowsAsyncPager: + google.cloud.dialogflowcx_v3.services.flows.pagers.ListFlowsAsyncPager: The response message for [Flows.ListFlows][google.cloud.dialogflow.cx.v3.Flows.ListFlows]. @@ -402,12 +440,13 @@ async def get_flow( r"""Retrieves the specified flow. Args: - request (:class:`~.flow.GetFlowRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.GetFlowRequest`): The request object. The response message for [Flows.GetFlow][google.cloud.dialogflow.cx.v3.Flows.GetFlow]. name (:class:`str`): Required. The name of the flow to get. Format: ``projects//locations//agents//flows/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -419,7 +458,7 @@ async def get_flow( sent along with the request as metadata. Returns: - ~.flow.Flow: + google.cloud.dialogflowcx_v3.types.Flow: Flows represents the conversation flows when you build your chatbot agent. A flow consists of many pages connected @@ -496,18 +535,19 @@ async def update_flow( r"""Updates the specified flow. Args: - request (:class:`~.gcdc_flow.UpdateFlowRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.UpdateFlowRequest`): The request object. The request message for [Flows.UpdateFlow][google.cloud.dialogflow.cx.v3.Flows.UpdateFlow]. - flow (:class:`~.gcdc_flow.Flow`): + flow (:class:`google.cloud.dialogflowcx_v3.types.Flow`): Required. The flow to update. This corresponds to the ``flow`` 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`): Required. The mask to control which fields get updated. If ``update_mask`` is not specified, an error will be returned. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -519,7 +559,7 @@ async def update_flow( sent along with the request as metadata. Returns: - ~.gcdc_flow.Flow: + google.cloud.dialogflowcx_v3.types.Flow: Flows represents the conversation flows when you build your chatbot agent. A flow consists of many pages connected @@ -600,12 +640,13 @@ async def train_flow( 'draft' environment is trained. Args: - request (:class:`~.flow.TrainFlowRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.TrainFlowRequest`): The request object. The request message for [Flows.TrainFlow][google.cloud.dialogflow.cx.v3.Flows.TrainFlow]. name (:class:`str`): Required. The flow to train. Format: ``projects//locations//agents//flows/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -617,24 +658,22 @@ async def train_flow( 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:``~.empty.Empty``: A generic empty message that - you can re-use to avoid defining duplicated empty - messages in your APIs. A typical example is to use it as - the request or the response type of an API method. For - instance: + The result type for the operation will be :class:`google.protobuf.empty_pb2.Empty` A generic empty message that you can re-use to avoid defining duplicated + empty messages in your APIs. A typical example is to + use it as the request or the response type of an API + method. For instance: - :: + service Foo { + rpc Bar(google.protobuf.Empty) returns + (google.protobuf.Empty); - service Foo { - rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty); - } + } - The JSON representation for ``Empty`` is empty JSON - object ``{}``. + The JSON representation for Empty is empty JSON + object {}. """ # Create or coerce a protobuf request object. @@ -683,6 +722,134 @@ async def train_flow( # Done; return the response. return response + async def validate_flow( + self, + request: flow.ValidateFlowRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> flow.FlowValidationResult: + r"""Validates the specified flow and creates or updates + validation results. Please call this API after the + training is completed to get the complete validation + results. + + Args: + request (:class:`google.cloud.dialogflowcx_v3.types.ValidateFlowRequest`): + The request object. The request message for + [Flows.ValidateFlow][google.cloud.dialogflow.cx.v3.Flows.ValidateFlow]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.dialogflowcx_v3.types.FlowValidationResult: + The response message for + [Flows.GetFlowValidationResult][google.cloud.dialogflow.cx.v3.Flows.GetFlowValidationResult]. + + """ + # Create or coerce a protobuf request object. + + request = flow.ValidateFlowRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.validate_flow, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = await rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + + async def get_flow_validation_result( + self, + request: flow.GetFlowValidationResultRequest = None, + *, + name: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> flow.FlowValidationResult: + r"""Gets the latest flow validation result. Flow + validation is performed when ValidateFlow is called. + + Args: + request (:class:`google.cloud.dialogflowcx_v3.types.GetFlowValidationResultRequest`): + The request object. The request message for + [Flows.GetFlowValidationResult][google.cloud.dialogflow.cx.v3.Flows.GetFlowValidationResult]. + name (:class:`str`): + Required. The flow name. Format: + ``projects//locations//agents//flows//validationResult``. + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.dialogflowcx_v3.types.FlowValidationResult: + The response message for + [Flows.GetFlowValidationResult][google.cloud.dialogflow.cx.v3.Flows.GetFlowValidationResult]. + + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = flow.GetFlowValidationResultRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.get_flow_validation_result, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = await rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + try: DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/google/cloud/dialogflowcx_v3/services/flows/client.py b/google/cloud/dialogflowcx_v3/services/flows/client.py index b2c5b800..6abaac84 100644 --- a/google/cloud/dialogflowcx_v3/services/flows/client.py +++ b/google/cloud/dialogflowcx_v3/services/flows/client.py @@ -38,9 +38,11 @@ from google.cloud.dialogflowcx_v3.types import flow from google.cloud.dialogflowcx_v3.types import flow as gcdc_flow from google.cloud.dialogflowcx_v3.types import page +from google.cloud.dialogflowcx_v3.types import validation_message from google.protobuf import empty_pb2 as empty # type: ignore from google.protobuf import field_mask_pb2 as field_mask # type: ignore from google.protobuf import struct_pb2 as struct # type: ignore +from google.protobuf import timestamp_pb2 as timestamp # type: ignore from .transports.base import FlowsTransport, DEFAULT_CLIENT_INFO from .transports.grpc import FlowsGrpcTransport @@ -115,6 +117,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: + FlowsClient: 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 +145,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. + FlowsClient: The constructed client. """ credentials = service_account.Credentials.from_service_account_file(filename) kwargs["credentials"] = credentials @@ -160,6 +178,24 @@ def parse_flow_path(path: str) -> Dict[str, str]: ) return m.groupdict() if m else {} + @staticmethod + def flow_validation_result_path( + project: str, location: str, agent: str, flow: str, + ) -> str: + """Return a fully-qualified flow_validation_result string.""" + return "projects/{project}/locations/{location}/agents/{agent}/flows/{flow}/validationResult".format( + project=project, location=location, agent=agent, flow=flow, + ) + + @staticmethod + def parse_flow_validation_result_path(path: str) -> Dict[str, str]: + """Parse a flow_validation_result path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/locations/(?P.+?)/agents/(?P.+?)/flows/(?P.+?)/validationResult$", + path, + ) + return m.groupdict() if m else {} + @staticmethod def intent_path(project: str, location: str, agent: str, intent: str,) -> str: """Return a fully-qualified intent string.""" @@ -285,10 +321,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, ~.FlowsTransport]): The + transport (Union[str, FlowsTransport]): 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 @@ -324,21 +360,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: @@ -381,7 +413,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, ) @@ -399,16 +431,17 @@ def create_flow( r"""Creates a flow in the specified agent. Args: - request (:class:`~.gcdc_flow.CreateFlowRequest`): + request (google.cloud.dialogflowcx_v3.types.CreateFlowRequest): The request object. The request message for [Flows.CreateFlow][google.cloud.dialogflow.cx.v3.Flows.CreateFlow]. - parent (:class:`str`): + parent (str): Required. The agent to create a flow for. Format: ``projects//locations//agents/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - flow (:class:`~.gcdc_flow.Flow`): + flow (google.cloud.dialogflowcx_v3.types.Flow): Required. The flow to create. This corresponds to the ``flow`` field on the ``request`` instance; if ``request`` is provided, this @@ -421,7 +454,7 @@ def create_flow( sent along with the request as metadata. Returns: - ~.gcdc_flow.Flow: + google.cloud.dialogflowcx_v3.types.Flow: Flows represents the conversation flows when you build your chatbot agent. A flow consists of many pages connected @@ -500,12 +533,13 @@ def delete_flow( r"""Deletes a specified flow. Args: - request (:class:`~.flow.DeleteFlowRequest`): + request (google.cloud.dialogflowcx_v3.types.DeleteFlowRequest): The request object. The request message for [Flows.DeleteFlow][google.cloud.dialogflow.cx.v3.Flows.DeleteFlow]. - name (:class:`str`): + name (str): Required. The name of the flow to delete. Format: ``projects//locations//agents//flows/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -566,12 +600,13 @@ def list_flows( r"""Returns the list of all flows in the specified agent. Args: - request (:class:`~.flow.ListFlowsRequest`): + request (google.cloud.dialogflowcx_v3.types.ListFlowsRequest): The request object. The request message for [Flows.ListFlows][google.cloud.dialogflow.cx.v3.Flows.ListFlows]. - parent (:class:`str`): + parent (str): Required. The agent containing the flows. Format: ``projects//locations//agents/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -583,7 +618,7 @@ def list_flows( sent along with the request as metadata. Returns: - ~.pagers.ListFlowsPager: + google.cloud.dialogflowcx_v3.services.flows.pagers.ListFlowsPager: The response message for [Flows.ListFlows][google.cloud.dialogflow.cx.v3.Flows.ListFlows]. @@ -648,12 +683,13 @@ def get_flow( r"""Retrieves the specified flow. Args: - request (:class:`~.flow.GetFlowRequest`): + request (google.cloud.dialogflowcx_v3.types.GetFlowRequest): The request object. The response message for [Flows.GetFlow][google.cloud.dialogflow.cx.v3.Flows.GetFlow]. - name (:class:`str`): + name (str): Required. The name of the flow to get. Format: ``projects//locations//agents//flows/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -665,7 +701,7 @@ def get_flow( sent along with the request as metadata. Returns: - ~.flow.Flow: + google.cloud.dialogflowcx_v3.types.Flow: Flows represents the conversation flows when you build your chatbot agent. A flow consists of many pages connected @@ -743,18 +779,19 @@ def update_flow( r"""Updates the specified flow. Args: - request (:class:`~.gcdc_flow.UpdateFlowRequest`): + request (google.cloud.dialogflowcx_v3.types.UpdateFlowRequest): The request object. The request message for [Flows.UpdateFlow][google.cloud.dialogflow.cx.v3.Flows.UpdateFlow]. - flow (:class:`~.gcdc_flow.Flow`): + flow (google.cloud.dialogflowcx_v3.types.Flow): Required. The flow to update. This corresponds to the ``flow`` 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): Required. The mask to control which fields get updated. If ``update_mask`` is not specified, an error will be returned. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -766,7 +803,7 @@ def update_flow( sent along with the request as metadata. Returns: - ~.gcdc_flow.Flow: + google.cloud.dialogflowcx_v3.types.Flow: Flows represents the conversation flows when you build your chatbot agent. A flow consists of many pages connected @@ -848,12 +885,13 @@ def train_flow( 'draft' environment is trained. Args: - request (:class:`~.flow.TrainFlowRequest`): + request (google.cloud.dialogflowcx_v3.types.TrainFlowRequest): The request object. The request message for [Flows.TrainFlow][google.cloud.dialogflow.cx.v3.Flows.TrainFlow]. - name (:class:`str`): + name (str): Required. The flow to train. Format: ``projects//locations//agents//flows/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -865,24 +903,22 @@ def train_flow( 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:``~.empty.Empty``: A generic empty message that - you can re-use to avoid defining duplicated empty - messages in your APIs. A typical example is to use it as - the request or the response type of an API method. For - instance: + The result type for the operation will be :class:`google.protobuf.empty_pb2.Empty` A generic empty message that you can re-use to avoid defining duplicated + empty messages in your APIs. A typical example is to + use it as the request or the response type of an API + method. For instance: - :: + service Foo { + rpc Bar(google.protobuf.Empty) returns + (google.protobuf.Empty); - service Foo { - rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty); - } + } - The JSON representation for ``Empty`` is empty JSON - object ``{}``. + The JSON representation for Empty is empty JSON + object {}. """ # Create or coerce a protobuf request object. @@ -932,6 +968,138 @@ def train_flow( # Done; return the response. return response + def validate_flow( + self, + request: flow.ValidateFlowRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> flow.FlowValidationResult: + r"""Validates the specified flow and creates or updates + validation results. Please call this API after the + training is completed to get the complete validation + results. + + Args: + request (google.cloud.dialogflowcx_v3.types.ValidateFlowRequest): + The request object. The request message for + [Flows.ValidateFlow][google.cloud.dialogflow.cx.v3.Flows.ValidateFlow]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.dialogflowcx_v3.types.FlowValidationResult: + The response message for + [Flows.GetFlowValidationResult][google.cloud.dialogflow.cx.v3.Flows.GetFlowValidationResult]. + + """ + # Create or coerce a protobuf request object. + + # Minor optimization to avoid making a copy if the user passes + # in a flow.ValidateFlowRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, flow.ValidateFlowRequest): + request = flow.ValidateFlowRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.validate_flow] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + + def get_flow_validation_result( + self, + request: flow.GetFlowValidationResultRequest = None, + *, + name: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> flow.FlowValidationResult: + r"""Gets the latest flow validation result. Flow + validation is performed when ValidateFlow is called. + + Args: + request (google.cloud.dialogflowcx_v3.types.GetFlowValidationResultRequest): + The request object. The request message for + [Flows.GetFlowValidationResult][google.cloud.dialogflow.cx.v3.Flows.GetFlowValidationResult]. + name (str): + Required. The flow name. Format: + ``projects//locations//agents//flows//validationResult``. + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.dialogflowcx_v3.types.FlowValidationResult: + The response message for + [Flows.GetFlowValidationResult][google.cloud.dialogflow.cx.v3.Flows.GetFlowValidationResult]. + + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a flow.GetFlowValidationResultRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, flow.GetFlowValidationResultRequest): + request = flow.GetFlowValidationResultRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[ + self._transport.get_flow_validation_result + ] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + try: DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/google/cloud/dialogflowcx_v3/services/flows/pagers.py b/google/cloud/dialogflowcx_v3/services/flows/pagers.py index bf55d3bb..9f4a9009 100644 --- a/google/cloud/dialogflowcx_v3/services/flows/pagers.py +++ b/google/cloud/dialogflowcx_v3/services/flows/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.dialogflowcx_v3.types import flow @@ -24,7 +33,7 @@ class ListFlowsPager: """A pager for iterating through ``list_flows`` requests. This class thinly wraps an initial - :class:`~.flow.ListFlowsResponse` object, and + :class:`google.cloud.dialogflowcx_v3.types.ListFlowsResponse` object, and provides an ``__iter__`` method to iterate through its ``flows`` field. @@ -33,7 +42,7 @@ class ListFlowsPager: through the ``flows`` field on the corresponding responses. - All the usual :class:`~.flow.ListFlowsResponse` + All the usual :class:`google.cloud.dialogflowcx_v3.types.ListFlowsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -51,9 +60,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.flow.ListFlowsRequest`): + request (google.cloud.dialogflowcx_v3.types.ListFlowsRequest): The initial request object. - response (:class:`~.flow.ListFlowsResponse`): + response (google.cloud.dialogflowcx_v3.types.ListFlowsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -86,7 +95,7 @@ class ListFlowsAsyncPager: """A pager for iterating through ``list_flows`` requests. This class thinly wraps an initial - :class:`~.flow.ListFlowsResponse` object, and + :class:`google.cloud.dialogflowcx_v3.types.ListFlowsResponse` object, and provides an ``__aiter__`` method to iterate through its ``flows`` field. @@ -95,7 +104,7 @@ class ListFlowsAsyncPager: through the ``flows`` field on the corresponding responses. - All the usual :class:`~.flow.ListFlowsResponse` + All the usual :class:`google.cloud.dialogflowcx_v3.types.ListFlowsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -113,9 +122,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.flow.ListFlowsRequest`): + request (google.cloud.dialogflowcx_v3.types.ListFlowsRequest): The initial request object. - response (:class:`~.flow.ListFlowsResponse`): + response (google.cloud.dialogflowcx_v3.types.ListFlowsResponse): 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/dialogflowcx_v3/services/flows/transports/base.py b/google/cloud/dialogflowcx_v3/services/flows/transports/base.py index 750a522e..9672aeb9 100644 --- a/google/cloud/dialogflowcx_v3/services/flows/transports/base.py +++ b/google/cloud/dialogflowcx_v3/services/flows/transports/base.py @@ -131,6 +131,14 @@ def _prep_wrapped_messages(self, client_info): self.train_flow: gapic_v1.method.wrap_method( self.train_flow, default_timeout=None, client_info=client_info, ), + self.validate_flow: gapic_v1.method.wrap_method( + self.validate_flow, default_timeout=None, client_info=client_info, + ), + self.get_flow_validation_result: gapic_v1.method.wrap_method( + self.get_flow_validation_result, + default_timeout=None, + client_info=client_info, + ), } @property @@ -191,5 +199,27 @@ def train_flow( ]: raise NotImplementedError() + @property + def validate_flow( + self, + ) -> typing.Callable[ + [flow.ValidateFlowRequest], + typing.Union[ + flow.FlowValidationResult, typing.Awaitable[flow.FlowValidationResult] + ], + ]: + raise NotImplementedError() + + @property + def get_flow_validation_result( + self, + ) -> typing.Callable[ + [flow.GetFlowValidationResultRequest], + typing.Union[ + flow.FlowValidationResult, typing.Awaitable[flow.FlowValidationResult] + ], + ]: + raise NotImplementedError() + __all__ = ("FlowsTransport",) diff --git a/google/cloud/dialogflowcx_v3/services/flows/transports/grpc.py b/google/cloud/dialogflowcx_v3/services/flows/transports/grpc.py index 3089c3bc..1c543280 100644 --- a/google/cloud/dialogflowcx_v3/services/flows/transports/grpc.py +++ b/google/cloud/dialogflowcx_v3/services/flows/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): @@ -107,6 +112,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -116,11 +126,6 @@ def __init__( 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 @@ -164,12 +169,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ @@ -401,5 +412,61 @@ def train_flow(self) -> Callable[[flow.TrainFlowRequest], operations.Operation]: ) return self._stubs["train_flow"] + @property + def validate_flow( + self, + ) -> Callable[[flow.ValidateFlowRequest], flow.FlowValidationResult]: + r"""Return a callable for the validate flow method over gRPC. + + Validates the specified flow and creates or updates + validation results. Please call this API after the + training is completed to get the complete validation + results. + + Returns: + Callable[[~.ValidateFlowRequest], + ~.FlowValidationResult]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "validate_flow" not in self._stubs: + self._stubs["validate_flow"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3.Flows/ValidateFlow", + request_serializer=flow.ValidateFlowRequest.serialize, + response_deserializer=flow.FlowValidationResult.deserialize, + ) + return self._stubs["validate_flow"] + + @property + def get_flow_validation_result( + self, + ) -> Callable[[flow.GetFlowValidationResultRequest], flow.FlowValidationResult]: + r"""Return a callable for the get flow validation result method over gRPC. + + Gets the latest flow validation result. Flow + validation is performed when ValidateFlow is called. + + Returns: + Callable[[~.GetFlowValidationResultRequest], + ~.FlowValidationResult]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_flow_validation_result" not in self._stubs: + self._stubs["get_flow_validation_result"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3.Flows/GetFlowValidationResult", + request_serializer=flow.GetFlowValidationResultRequest.serialize, + response_deserializer=flow.FlowValidationResult.deserialize, + ) + return self._stubs["get_flow_validation_result"] + __all__ = ("FlowsGrpcTransport",) diff --git a/google/cloud/dialogflowcx_v3/services/flows/transports/grpc_asyncio.py b/google/cloud/dialogflowcx_v3/services/flows/transports/grpc_asyncio.py index 67607e70..fadbc2f1 100644 --- a/google/cloud/dialogflowcx_v3/services/flows/transports/grpc_asyncio.py +++ b/google/cloud/dialogflowcx_v3/services/flows/transports/grpc_asyncio.py @@ -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,6 +137,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): @@ -152,6 +157,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -161,11 +171,6 @@ def __init__( 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 @@ -209,12 +214,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ @@ -415,5 +426,63 @@ def train_flow( ) return self._stubs["train_flow"] + @property + def validate_flow( + self, + ) -> Callable[[flow.ValidateFlowRequest], Awaitable[flow.FlowValidationResult]]: + r"""Return a callable for the validate flow method over gRPC. + + Validates the specified flow and creates or updates + validation results. Please call this API after the + training is completed to get the complete validation + results. + + Returns: + Callable[[~.ValidateFlowRequest], + Awaitable[~.FlowValidationResult]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "validate_flow" not in self._stubs: + self._stubs["validate_flow"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3.Flows/ValidateFlow", + request_serializer=flow.ValidateFlowRequest.serialize, + response_deserializer=flow.FlowValidationResult.deserialize, + ) + return self._stubs["validate_flow"] + + @property + def get_flow_validation_result( + self, + ) -> Callable[ + [flow.GetFlowValidationResultRequest], Awaitable[flow.FlowValidationResult] + ]: + r"""Return a callable for the get flow validation result method over gRPC. + + Gets the latest flow validation result. Flow + validation is performed when ValidateFlow is called. + + Returns: + Callable[[~.GetFlowValidationResultRequest], + Awaitable[~.FlowValidationResult]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_flow_validation_result" not in self._stubs: + self._stubs["get_flow_validation_result"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3.Flows/GetFlowValidationResult", + request_serializer=flow.GetFlowValidationResultRequest.serialize, + response_deserializer=flow.FlowValidationResult.deserialize, + ) + return self._stubs["get_flow_validation_result"] + __all__ = ("FlowsGrpcAsyncIOTransport",) diff --git a/google/cloud/dialogflowcx_v3/services/intents/async_client.py b/google/cloud/dialogflowcx_v3/services/intents/async_client.py index 04ee85cf..2a2d271d 100644 --- a/google/cloud/dialogflowcx_v3/services/intents/async_client.py +++ b/google/cloud/dialogflowcx_v3/services/intents/async_client.py @@ -74,7 +74,36 @@ class IntentsAsyncClient: common_location_path = staticmethod(IntentsClient.common_location_path) parse_common_location_path = staticmethod(IntentsClient.parse_common_location_path) - from_service_account_file = IntentsClient.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: + IntentsAsyncClient: The constructed client. + """ + return IntentsClient.from_service_account_info.__func__(IntentsAsyncClient, 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: + IntentsAsyncClient: The constructed client. + """ + return IntentsClient.from_service_account_file.__func__(IntentsAsyncClient, filename, *args, **kwargs) # type: ignore + from_service_account_json = from_service_account_file @property @@ -151,12 +180,13 @@ async def list_intents( agent. Args: - request (:class:`~.intent.ListIntentsRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.ListIntentsRequest`): The request object. The request message for [Intents.ListIntents][google.cloud.dialogflow.cx.v3.Intents.ListIntents]. parent (:class:`str`): Required. The agent to list all intents for. Format: ``projects//locations//agents/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -168,7 +198,7 @@ async def list_intents( sent along with the request as metadata. Returns: - ~.pagers.ListIntentsAsyncPager: + google.cloud.dialogflowcx_v3.services.intents.pagers.ListIntentsAsyncPager: The response message for [Intents.ListIntents][google.cloud.dialogflow.cx.v3.Intents.ListIntents]. @@ -232,12 +262,13 @@ async def get_intent( r"""Retrieves the specified intent. Args: - request (:class:`~.intent.GetIntentRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.GetIntentRequest`): The request object. The request message for [Intents.GetIntent][google.cloud.dialogflow.cx.v3.Intents.GetIntent]. name (:class:`str`): Required. The name of the intent. Format: ``projects//locations//agents//intents/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -249,7 +280,7 @@ async def get_intent( sent along with the request as metadata. Returns: - ~.intent.Intent: + google.cloud.dialogflowcx_v3.types.Intent: An intent represents a user's intent to interact with a conversational agent. You can provide information for the @@ -310,16 +341,17 @@ async def create_intent( r"""Creates an intent in the specified agent. Args: - request (:class:`~.gcdc_intent.CreateIntentRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.CreateIntentRequest`): The request object. The request message for [Intents.CreateIntent][google.cloud.dialogflow.cx.v3.Intents.CreateIntent]. parent (:class:`str`): Required. The agent to create an intent for. Format: ``projects//locations//agents/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - intent (:class:`~.gcdc_intent.Intent`): + intent (:class:`google.cloud.dialogflowcx_v3.types.Intent`): Required. The intent to create. This corresponds to the ``intent`` field on the ``request`` instance; if ``request`` is provided, this @@ -332,7 +364,7 @@ async def create_intent( sent along with the request as metadata. Returns: - ~.gcdc_intent.Intent: + google.cloud.dialogflowcx_v3.types.Intent: An intent represents a user's intent to interact with a conversational agent. You can provide information for the @@ -395,18 +427,19 @@ async def update_intent( r"""Updates the specified intent. Args: - request (:class:`~.gcdc_intent.UpdateIntentRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.UpdateIntentRequest`): The request object. The request message for [Intents.UpdateIntent][google.cloud.dialogflow.cx.v3.Intents.UpdateIntent]. - intent (:class:`~.gcdc_intent.Intent`): + intent (:class:`google.cloud.dialogflowcx_v3.types.Intent`): Required. The intent to update. This corresponds to the ``intent`` 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`): The mask to control which fields get updated. If the mask is not present, all fields will be updated. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -418,7 +451,7 @@ async def update_intent( sent along with the request as metadata. Returns: - ~.gcdc_intent.Intent: + google.cloud.dialogflowcx_v3.types.Intent: An intent represents a user's intent to interact with a conversational agent. You can provide information for the @@ -482,12 +515,13 @@ async def delete_intent( r"""Deletes the specified intent. Args: - request (:class:`~.intent.DeleteIntentRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.DeleteIntentRequest`): The request object. The request message for [Intents.DeleteIntent][google.cloud.dialogflow.cx.v3.Intents.DeleteIntent]. name (:class:`str`): Required. The name of the intent to delete. Format: ``projects//locations//agents//intents/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. diff --git a/google/cloud/dialogflowcx_v3/services/intents/client.py b/google/cloud/dialogflowcx_v3/services/intents/client.py index 63d5ef52..9a4e0a2b 100644 --- a/google/cloud/dialogflowcx_v3/services/intents/client.py +++ b/google/cloud/dialogflowcx_v3/services/intents/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: + IntentsClient: 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. + IntentsClient: The constructed client. """ credentials = service_account.Credentials.from_service_account_file(filename) kwargs["credentials"] = credentials @@ -250,10 +266,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, ~.IntentsTransport]): The + transport (Union[str, IntentsTransport]): 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 @@ -289,21 +305,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: @@ -346,7 +358,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,12 +376,13 @@ def list_intents( agent. Args: - request (:class:`~.intent.ListIntentsRequest`): + request (google.cloud.dialogflowcx_v3.types.ListIntentsRequest): The request object. The request message for [Intents.ListIntents][google.cloud.dialogflow.cx.v3.Intents.ListIntents]. - parent (:class:`str`): + parent (str): Required. The agent to list all intents for. Format: ``projects//locations//agents/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -381,7 +394,7 @@ def list_intents( sent along with the request as metadata. Returns: - ~.pagers.ListIntentsPager: + google.cloud.dialogflowcx_v3.services.intents.pagers.ListIntentsPager: The response message for [Intents.ListIntents][google.cloud.dialogflow.cx.v3.Intents.ListIntents]. @@ -446,12 +459,13 @@ def get_intent( r"""Retrieves the specified intent. Args: - request (:class:`~.intent.GetIntentRequest`): + request (google.cloud.dialogflowcx_v3.types.GetIntentRequest): The request object. The request message for [Intents.GetIntent][google.cloud.dialogflow.cx.v3.Intents.GetIntent]. - name (:class:`str`): + name (str): Required. The name of the intent. Format: ``projects//locations//agents//intents/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -463,7 +477,7 @@ def get_intent( sent along with the request as metadata. Returns: - ~.intent.Intent: + google.cloud.dialogflowcx_v3.types.Intent: An intent represents a user's intent to interact with a conversational agent. You can provide information for the @@ -525,16 +539,17 @@ def create_intent( r"""Creates an intent in the specified agent. Args: - request (:class:`~.gcdc_intent.CreateIntentRequest`): + request (google.cloud.dialogflowcx_v3.types.CreateIntentRequest): The request object. The request message for [Intents.CreateIntent][google.cloud.dialogflow.cx.v3.Intents.CreateIntent]. - parent (:class:`str`): + parent (str): Required. The agent to create an intent for. Format: ``projects//locations//agents/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - intent (:class:`~.gcdc_intent.Intent`): + intent (google.cloud.dialogflowcx_v3.types.Intent): Required. The intent to create. This corresponds to the ``intent`` field on the ``request`` instance; if ``request`` is provided, this @@ -547,7 +562,7 @@ def create_intent( sent along with the request as metadata. Returns: - ~.gcdc_intent.Intent: + google.cloud.dialogflowcx_v3.types.Intent: An intent represents a user's intent to interact with a conversational agent. You can provide information for the @@ -611,18 +626,19 @@ def update_intent( r"""Updates the specified intent. Args: - request (:class:`~.gcdc_intent.UpdateIntentRequest`): + request (google.cloud.dialogflowcx_v3.types.UpdateIntentRequest): The request object. The request message for [Intents.UpdateIntent][google.cloud.dialogflow.cx.v3.Intents.UpdateIntent]. - intent (:class:`~.gcdc_intent.Intent`): + intent (google.cloud.dialogflowcx_v3.types.Intent): Required. The intent to update. This corresponds to the ``intent`` 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): The mask to control which fields get updated. If the mask is not present, all fields will be updated. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -634,7 +650,7 @@ def update_intent( sent along with the request as metadata. Returns: - ~.gcdc_intent.Intent: + google.cloud.dialogflowcx_v3.types.Intent: An intent represents a user's intent to interact with a conversational agent. You can provide information for the @@ -699,12 +715,13 @@ def delete_intent( r"""Deletes the specified intent. Args: - request (:class:`~.intent.DeleteIntentRequest`): + request (google.cloud.dialogflowcx_v3.types.DeleteIntentRequest): The request object. The request message for [Intents.DeleteIntent][google.cloud.dialogflow.cx.v3.Intents.DeleteIntent]. - name (:class:`str`): + name (str): Required. The name of the intent to delete. Format: ``projects//locations//agents//intents/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. diff --git a/google/cloud/dialogflowcx_v3/services/intents/pagers.py b/google/cloud/dialogflowcx_v3/services/intents/pagers.py index 1e3f29dd..c7bd6591 100644 --- a/google/cloud/dialogflowcx_v3/services/intents/pagers.py +++ b/google/cloud/dialogflowcx_v3/services/intents/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.dialogflowcx_v3.types import intent @@ -24,7 +33,7 @@ class ListIntentsPager: """A pager for iterating through ``list_intents`` requests. This class thinly wraps an initial - :class:`~.intent.ListIntentsResponse` object, and + :class:`google.cloud.dialogflowcx_v3.types.ListIntentsResponse` object, and provides an ``__iter__`` method to iterate through its ``intents`` field. @@ -33,7 +42,7 @@ class ListIntentsPager: through the ``intents`` field on the corresponding responses. - All the usual :class:`~.intent.ListIntentsResponse` + All the usual :class:`google.cloud.dialogflowcx_v3.types.ListIntentsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -51,9 +60,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.intent.ListIntentsRequest`): + request (google.cloud.dialogflowcx_v3.types.ListIntentsRequest): The initial request object. - response (:class:`~.intent.ListIntentsResponse`): + response (google.cloud.dialogflowcx_v3.types.ListIntentsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -86,7 +95,7 @@ class ListIntentsAsyncPager: """A pager for iterating through ``list_intents`` requests. This class thinly wraps an initial - :class:`~.intent.ListIntentsResponse` object, and + :class:`google.cloud.dialogflowcx_v3.types.ListIntentsResponse` object, and provides an ``__aiter__`` method to iterate through its ``intents`` field. @@ -95,7 +104,7 @@ class ListIntentsAsyncPager: through the ``intents`` field on the corresponding responses. - All the usual :class:`~.intent.ListIntentsResponse` + All the usual :class:`google.cloud.dialogflowcx_v3.types.ListIntentsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -113,9 +122,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.intent.ListIntentsRequest`): + request (google.cloud.dialogflowcx_v3.types.ListIntentsRequest): The initial request object. - response (:class:`~.intent.ListIntentsResponse`): + response (google.cloud.dialogflowcx_v3.types.ListIntentsResponse): 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/dialogflowcx_v3/services/intents/transports/grpc.py b/google/cloud/dialogflowcx_v3/services/intents/transports/grpc.py index a5f67339..db8768da 100644 --- a/google/cloud/dialogflowcx_v3/services/intents/transports/grpc.py +++ b/google/cloud/dialogflowcx_v3/services/intents/transports/grpc.py @@ -60,6 +60,7 @@ def __init__( api_mtls_endpoint: str = None, client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, quota_project_id: Optional[str] = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: @@ -90,6 +91,10 @@ def __init__( ``api_mtls_endpoint`` is None. ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials for grpc channel. It is ignored if ``channel`` is provided. + client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]): + A callback to provide client certificate bytes and private key bytes, + both in PEM format. It is used to configure mutual TLS channel. It is + ignored if ``channel`` or ``ssl_channel_credentials`` is provided. quota_project_id (Optional[str]): An optional project to use for billing and quota. client_info (google.api_core.gapic_v1.client_info.ClientInfo): @@ -106,6 +111,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -115,11 +125,6 @@ def __init__( 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 @@ -163,12 +168,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ diff --git a/google/cloud/dialogflowcx_v3/services/intents/transports/grpc_asyncio.py b/google/cloud/dialogflowcx_v3/services/intents/transports/grpc_asyncio.py index 8511e4eb..f66c9c4e 100644 --- a/google/cloud/dialogflowcx_v3/services/intents/transports/grpc_asyncio.py +++ b/google/cloud/dialogflowcx_v3/services/intents/transports/grpc_asyncio.py @@ -104,6 +104,7 @@ def __init__( api_mtls_endpoint: str = None, client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, quota_project_id=None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: @@ -135,6 +136,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): @@ -151,6 +156,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -160,11 +170,6 @@ def __init__( 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 @@ -208,12 +213,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ diff --git a/google/cloud/dialogflowcx_v3/services/pages/async_client.py b/google/cloud/dialogflowcx_v3/services/pages/async_client.py index 3a900c6f..eb761cff 100644 --- a/google/cloud/dialogflowcx_v3/services/pages/async_client.py +++ b/google/cloud/dialogflowcx_v3/services/pages/async_client.py @@ -81,7 +81,36 @@ class PagesAsyncClient: common_location_path = staticmethod(PagesClient.common_location_path) parse_common_location_path = staticmethod(PagesClient.parse_common_location_path) - from_service_account_file = PagesClient.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: + PagesAsyncClient: The constructed client. + """ + return PagesClient.from_service_account_info.__func__(PagesAsyncClient, 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: + PagesAsyncClient: The constructed client. + """ + return PagesClient.from_service_account_file.__func__(PagesAsyncClient, filename, *args, **kwargs) # type: ignore + from_service_account_json = from_service_account_file @property @@ -157,12 +186,13 @@ async def list_pages( r"""Returns the list of all pages in the specified flow. Args: - request (:class:`~.page.ListPagesRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.ListPagesRequest`): The request object. The request message for [Pages.ListPages][google.cloud.dialogflow.cx.v3.Pages.ListPages]. parent (:class:`str`): Required. The flow to list all pages for. Format: ``projects//locations//agents//flows/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -174,7 +204,7 @@ async def list_pages( sent along with the request as metadata. Returns: - ~.pagers.ListPagesAsyncPager: + google.cloud.dialogflowcx_v3.services.pages.pagers.ListPagesAsyncPager: The response message for [Pages.ListPages][google.cloud.dialogflow.cx.v3.Pages.ListPages]. @@ -238,12 +268,13 @@ async def get_page( r"""Retrieves the specified page. Args: - request (:class:`~.page.GetPageRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.GetPageRequest`): The request object. The request message for [Pages.GetPage][google.cloud.dialogflow.cx.v3.Pages.GetPage]. name (:class:`str`): Required. The name of the page. Format: ``projects//locations//agents//flows//pages/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -255,28 +286,29 @@ async def get_page( sent along with the request as metadata. Returns: - ~.page.Page: - A Dialogflow CX conversation (session) can be described - and visualized as a state machine. The states of a CX - session are represented by pages. - - For each flow, you define many pages, where your - combined pages can handle a complete conversation on the - topics the flow is designed for. At any given moment, - exactly one page is the current page, the current page - is considered active, and the flow associated with that - page is considered active. Every flow has a special - start page. When a flow initially becomes active, the - start page page becomes the current page. For each - conversational turn, the current page will either stay - the same or transition to another page. - - You configure each page to collect information from the - end-user that is relevant for the conversational state - represented by the page. - - For more information, see the `Page - guide `__. + google.cloud.dialogflowcx_v3.types.Page: + A Dialogflow CX conversation (session) can be described and visualized as a + state machine. The states of a CX session are + represented by pages. + + For each flow, you define many pages, where your + combined pages can handle a complete conversation on + the topics the flow is designed for. At any given + moment, exactly one page is the current page, the + current page is considered active, and the flow + associated with that page is considered active. Every + flow has a special start page. When a flow initially + becomes active, the start page page becomes the + current page. For each conversational turn, the + current page will either stay the same or transition + to another page. + + You configure each page to collect information from + the end-user that is relevant for the conversational + state represented by the page. + + For more information, see the [Page + guide](\ https://cloud.google.com/dialogflow/cx/docs/concept/page). """ # Create or coerce a protobuf request object. @@ -330,16 +362,17 @@ async def create_page( r"""Creates a page in the specified flow. Args: - request (:class:`~.gcdc_page.CreatePageRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.CreatePageRequest`): The request object. The request message for [Pages.CreatePage][google.cloud.dialogflow.cx.v3.Pages.CreatePage]. parent (:class:`str`): Required. The flow to create a page for. Format: ``projects//locations//agents//flows/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - page (:class:`~.gcdc_page.Page`): + page (:class:`google.cloud.dialogflowcx_v3.types.Page`): Required. The page to create. This corresponds to the ``page`` field on the ``request`` instance; if ``request`` is provided, this @@ -352,28 +385,29 @@ async def create_page( sent along with the request as metadata. Returns: - ~.gcdc_page.Page: - A Dialogflow CX conversation (session) can be described - and visualized as a state machine. The states of a CX - session are represented by pages. - - For each flow, you define many pages, where your - combined pages can handle a complete conversation on the - topics the flow is designed for. At any given moment, - exactly one page is the current page, the current page - is considered active, and the flow associated with that - page is considered active. Every flow has a special - start page. When a flow initially becomes active, the - start page page becomes the current page. For each - conversational turn, the current page will either stay - the same or transition to another page. - - You configure each page to collect information from the - end-user that is relevant for the conversational state - represented by the page. - - For more information, see the `Page - guide `__. + google.cloud.dialogflowcx_v3.types.Page: + A Dialogflow CX conversation (session) can be described and visualized as a + state machine. The states of a CX session are + represented by pages. + + For each flow, you define many pages, where your + combined pages can handle a complete conversation on + the topics the flow is designed for. At any given + moment, exactly one page is the current page, the + current page is considered active, and the flow + associated with that page is considered active. Every + flow has a special start page. When a flow initially + becomes active, the start page page becomes the + current page. For each conversational turn, the + current page will either stay the same or transition + to another page. + + You configure each page to collect information from + the end-user that is relevant for the conversational + state represented by the page. + + For more information, see the [Page + guide](\ https://cloud.google.com/dialogflow/cx/docs/concept/page). """ # Create or coerce a protobuf request object. @@ -429,18 +463,19 @@ async def update_page( r"""Updates the specified page. Args: - request (:class:`~.gcdc_page.UpdatePageRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.UpdatePageRequest`): The request object. The request message for [Pages.UpdatePage][google.cloud.dialogflow.cx.v3.Pages.UpdatePage]. - page (:class:`~.gcdc_page.Page`): + page (:class:`google.cloud.dialogflowcx_v3.types.Page`): Required. The page to update. This corresponds to the ``page`` 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`): The mask to control which fields get updated. If the mask is not present, all fields will be updated. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -452,28 +487,29 @@ async def update_page( sent along with the request as metadata. Returns: - ~.gcdc_page.Page: - A Dialogflow CX conversation (session) can be described - and visualized as a state machine. The states of a CX - session are represented by pages. - - For each flow, you define many pages, where your - combined pages can handle a complete conversation on the - topics the flow is designed for. At any given moment, - exactly one page is the current page, the current page - is considered active, and the flow associated with that - page is considered active. Every flow has a special - start page. When a flow initially becomes active, the - start page page becomes the current page. For each - conversational turn, the current page will either stay - the same or transition to another page. - - You configure each page to collect information from the - end-user that is relevant for the conversational state - represented by the page. - - For more information, see the `Page - guide `__. + google.cloud.dialogflowcx_v3.types.Page: + A Dialogflow CX conversation (session) can be described and visualized as a + state machine. The states of a CX session are + represented by pages. + + For each flow, you define many pages, where your + combined pages can handle a complete conversation on + the topics the flow is designed for. At any given + moment, exactly one page is the current page, the + current page is considered active, and the flow + associated with that page is considered active. Every + flow has a special start page. When a flow initially + becomes active, the start page page becomes the + current page. For each conversational turn, the + current page will either stay the same or transition + to another page. + + You configure each page to collect information from + the end-user that is relevant for the conversational + state represented by the page. + + For more information, see the [Page + guide](\ https://cloud.google.com/dialogflow/cx/docs/concept/page). """ # Create or coerce a protobuf request object. @@ -530,12 +566,13 @@ async def delete_page( r"""Deletes the specified page. Args: - request (:class:`~.page.DeletePageRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.DeletePageRequest`): The request object. The request message for [Pages.DeletePage][google.cloud.dialogflow.cx.v3.Pages.DeletePage]. name (:class:`str`): Required. The name of the page to delete. Format: ``projects//locations//agents//Flows//pages/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. diff --git a/google/cloud/dialogflowcx_v3/services/pages/client.py b/google/cloud/dialogflowcx_v3/services/pages/client.py index 3a5c376f..25c1d30c 100644 --- a/google/cloud/dialogflowcx_v3/services/pages/client.py +++ b/google/cloud/dialogflowcx_v3/services/pages/client.py @@ -111,6 +111,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: + PagesClient: 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 @@ -123,7 +139,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. + PagesClient: The constructed client. """ credentials = service_account.Credentials.from_service_account_file(filename) kwargs["credentials"] = credentials @@ -321,10 +337,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, ~.PagesTransport]): The + transport (Union[str, PagesTransport]): 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 @@ -360,21 +376,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: @@ -417,7 +429,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, ) @@ -434,12 +446,13 @@ def list_pages( r"""Returns the list of all pages in the specified flow. Args: - request (:class:`~.page.ListPagesRequest`): + request (google.cloud.dialogflowcx_v3.types.ListPagesRequest): The request object. The request message for [Pages.ListPages][google.cloud.dialogflow.cx.v3.Pages.ListPages]. - parent (:class:`str`): + parent (str): Required. The flow to list all pages for. Format: ``projects//locations//agents//flows/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -451,7 +464,7 @@ def list_pages( sent along with the request as metadata. Returns: - ~.pagers.ListPagesPager: + google.cloud.dialogflowcx_v3.services.pages.pagers.ListPagesPager: The response message for [Pages.ListPages][google.cloud.dialogflow.cx.v3.Pages.ListPages]. @@ -516,12 +529,13 @@ def get_page( r"""Retrieves the specified page. Args: - request (:class:`~.page.GetPageRequest`): + request (google.cloud.dialogflowcx_v3.types.GetPageRequest): The request object. The request message for [Pages.GetPage][google.cloud.dialogflow.cx.v3.Pages.GetPage]. - name (:class:`str`): + name (str): Required. The name of the page. Format: ``projects//locations//agents//flows//pages/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -533,28 +547,29 @@ def get_page( sent along with the request as metadata. Returns: - ~.page.Page: - A Dialogflow CX conversation (session) can be described - and visualized as a state machine. The states of a CX - session are represented by pages. - - For each flow, you define many pages, where your - combined pages can handle a complete conversation on the - topics the flow is designed for. At any given moment, - exactly one page is the current page, the current page - is considered active, and the flow associated with that - page is considered active. Every flow has a special - start page. When a flow initially becomes active, the - start page page becomes the current page. For each - conversational turn, the current page will either stay - the same or transition to another page. - - You configure each page to collect information from the - end-user that is relevant for the conversational state - represented by the page. - - For more information, see the `Page - guide `__. + google.cloud.dialogflowcx_v3.types.Page: + A Dialogflow CX conversation (session) can be described and visualized as a + state machine. The states of a CX session are + represented by pages. + + For each flow, you define many pages, where your + combined pages can handle a complete conversation on + the topics the flow is designed for. At any given + moment, exactly one page is the current page, the + current page is considered active, and the flow + associated with that page is considered active. Every + flow has a special start page. When a flow initially + becomes active, the start page page becomes the + current page. For each conversational turn, the + current page will either stay the same or transition + to another page. + + You configure each page to collect information from + the end-user that is relevant for the conversational + state represented by the page. + + For more information, see the [Page + guide](\ https://cloud.google.com/dialogflow/cx/docs/concept/page). """ # Create or coerce a protobuf request object. @@ -609,16 +624,17 @@ def create_page( r"""Creates a page in the specified flow. Args: - request (:class:`~.gcdc_page.CreatePageRequest`): + request (google.cloud.dialogflowcx_v3.types.CreatePageRequest): The request object. The request message for [Pages.CreatePage][google.cloud.dialogflow.cx.v3.Pages.CreatePage]. - parent (:class:`str`): + parent (str): Required. The flow to create a page for. Format: ``projects//locations//agents//flows/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - page (:class:`~.gcdc_page.Page`): + page (google.cloud.dialogflowcx_v3.types.Page): Required. The page to create. This corresponds to the ``page`` field on the ``request`` instance; if ``request`` is provided, this @@ -631,28 +647,29 @@ def create_page( sent along with the request as metadata. Returns: - ~.gcdc_page.Page: - A Dialogflow CX conversation (session) can be described - and visualized as a state machine. The states of a CX - session are represented by pages. - - For each flow, you define many pages, where your - combined pages can handle a complete conversation on the - topics the flow is designed for. At any given moment, - exactly one page is the current page, the current page - is considered active, and the flow associated with that - page is considered active. Every flow has a special - start page. When a flow initially becomes active, the - start page page becomes the current page. For each - conversational turn, the current page will either stay - the same or transition to another page. - - You configure each page to collect information from the - end-user that is relevant for the conversational state - represented by the page. - - For more information, see the `Page - guide `__. + google.cloud.dialogflowcx_v3.types.Page: + A Dialogflow CX conversation (session) can be described and visualized as a + state machine. The states of a CX session are + represented by pages. + + For each flow, you define many pages, where your + combined pages can handle a complete conversation on + the topics the flow is designed for. At any given + moment, exactly one page is the current page, the + current page is considered active, and the flow + associated with that page is considered active. Every + flow has a special start page. When a flow initially + becomes active, the start page page becomes the + current page. For each conversational turn, the + current page will either stay the same or transition + to another page. + + You configure each page to collect information from + the end-user that is relevant for the conversational + state represented by the page. + + For more information, see the [Page + guide](\ https://cloud.google.com/dialogflow/cx/docs/concept/page). """ # Create or coerce a protobuf request object. @@ -709,18 +726,19 @@ def update_page( r"""Updates the specified page. Args: - request (:class:`~.gcdc_page.UpdatePageRequest`): + request (google.cloud.dialogflowcx_v3.types.UpdatePageRequest): The request object. The request message for [Pages.UpdatePage][google.cloud.dialogflow.cx.v3.Pages.UpdatePage]. - page (:class:`~.gcdc_page.Page`): + page (google.cloud.dialogflowcx_v3.types.Page): Required. The page to update. This corresponds to the ``page`` 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): The mask to control which fields get updated. If the mask is not present, all fields will be updated. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -732,28 +750,29 @@ def update_page( sent along with the request as metadata. Returns: - ~.gcdc_page.Page: - A Dialogflow CX conversation (session) can be described - and visualized as a state machine. The states of a CX - session are represented by pages. - - For each flow, you define many pages, where your - combined pages can handle a complete conversation on the - topics the flow is designed for. At any given moment, - exactly one page is the current page, the current page - is considered active, and the flow associated with that - page is considered active. Every flow has a special - start page. When a flow initially becomes active, the - start page page becomes the current page. For each - conversational turn, the current page will either stay - the same or transition to another page. - - You configure each page to collect information from the - end-user that is relevant for the conversational state - represented by the page. - - For more information, see the `Page - guide `__. + google.cloud.dialogflowcx_v3.types.Page: + A Dialogflow CX conversation (session) can be described and visualized as a + state machine. The states of a CX session are + represented by pages. + + For each flow, you define many pages, where your + combined pages can handle a complete conversation on + the topics the flow is designed for. At any given + moment, exactly one page is the current page, the + current page is considered active, and the flow + associated with that page is considered active. Every + flow has a special start page. When a flow initially + becomes active, the start page page becomes the + current page. For each conversational turn, the + current page will either stay the same or transition + to another page. + + You configure each page to collect information from + the end-user that is relevant for the conversational + state represented by the page. + + For more information, see the [Page + guide](\ https://cloud.google.com/dialogflow/cx/docs/concept/page). """ # Create or coerce a protobuf request object. @@ -811,12 +830,13 @@ def delete_page( r"""Deletes the specified page. Args: - request (:class:`~.page.DeletePageRequest`): + request (google.cloud.dialogflowcx_v3.types.DeletePageRequest): The request object. The request message for [Pages.DeletePage][google.cloud.dialogflow.cx.v3.Pages.DeletePage]. - name (:class:`str`): + name (str): Required. The name of the page to delete. Format: ``projects//locations//agents//Flows//pages/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. diff --git a/google/cloud/dialogflowcx_v3/services/pages/pagers.py b/google/cloud/dialogflowcx_v3/services/pages/pagers.py index 40d758e7..6334e82a 100644 --- a/google/cloud/dialogflowcx_v3/services/pages/pagers.py +++ b/google/cloud/dialogflowcx_v3/services/pages/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.dialogflowcx_v3.types import page @@ -24,7 +33,7 @@ class ListPagesPager: """A pager for iterating through ``list_pages`` requests. This class thinly wraps an initial - :class:`~.page.ListPagesResponse` object, and + :class:`google.cloud.dialogflowcx_v3.types.ListPagesResponse` object, and provides an ``__iter__`` method to iterate through its ``pages`` field. @@ -33,7 +42,7 @@ class ListPagesPager: through the ``pages`` field on the corresponding responses. - All the usual :class:`~.page.ListPagesResponse` + All the usual :class:`google.cloud.dialogflowcx_v3.types.ListPagesResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -51,9 +60,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.page.ListPagesRequest`): + request (google.cloud.dialogflowcx_v3.types.ListPagesRequest): The initial request object. - response (:class:`~.page.ListPagesResponse`): + response (google.cloud.dialogflowcx_v3.types.ListPagesResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -86,7 +95,7 @@ class ListPagesAsyncPager: """A pager for iterating through ``list_pages`` requests. This class thinly wraps an initial - :class:`~.page.ListPagesResponse` object, and + :class:`google.cloud.dialogflowcx_v3.types.ListPagesResponse` object, and provides an ``__aiter__`` method to iterate through its ``pages`` field. @@ -95,7 +104,7 @@ class ListPagesAsyncPager: through the ``pages`` field on the corresponding responses. - All the usual :class:`~.page.ListPagesResponse` + All the usual :class:`google.cloud.dialogflowcx_v3.types.ListPagesResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -113,9 +122,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.page.ListPagesRequest`): + request (google.cloud.dialogflowcx_v3.types.ListPagesRequest): The initial request object. - response (:class:`~.page.ListPagesResponse`): + response (google.cloud.dialogflowcx_v3.types.ListPagesResponse): 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/dialogflowcx_v3/services/pages/transports/grpc.py b/google/cloud/dialogflowcx_v3/services/pages/transports/grpc.py index 141d4bdf..07854d83 100644 --- a/google/cloud/dialogflowcx_v3/services/pages/transports/grpc.py +++ b/google/cloud/dialogflowcx_v3/services/pages/transports/grpc.py @@ -59,6 +59,7 @@ def __init__( api_mtls_endpoint: str = None, client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, quota_project_id: Optional[str] = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: @@ -89,6 +90,10 @@ def __init__( ``api_mtls_endpoint`` is None. ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials for grpc channel. It is ignored if ``channel`` is provided. + client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]): + A callback to provide client certificate bytes and private key bytes, + both in PEM format. It is used to configure mutual TLS channel. It is + ignored if ``channel`` or ``ssl_channel_credentials`` is provided. quota_project_id (Optional[str]): An optional project to use for billing and quota. client_info (google.api_core.gapic_v1.client_info.ClientInfo): @@ -105,6 +110,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -114,11 +124,6 @@ def __init__( 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 @@ -162,12 +167,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ diff --git a/google/cloud/dialogflowcx_v3/services/pages/transports/grpc_asyncio.py b/google/cloud/dialogflowcx_v3/services/pages/transports/grpc_asyncio.py index 6de688fe..077eaa33 100644 --- a/google/cloud/dialogflowcx_v3/services/pages/transports/grpc_asyncio.py +++ b/google/cloud/dialogflowcx_v3/services/pages/transports/grpc_asyncio.py @@ -103,6 +103,7 @@ def __init__( api_mtls_endpoint: str = None, client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, quota_project_id=None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: @@ -134,6 +135,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): @@ -150,6 +155,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -159,11 +169,6 @@ def __init__( 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 @@ -207,12 +212,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ diff --git a/google/cloud/dialogflowcx_v3/services/security_settings_service/async_client.py b/google/cloud/dialogflowcx_v3/services/security_settings_service/async_client.py index 40af98e0..4d2b0dc0 100644 --- a/google/cloud/dialogflowcx_v3/services/security_settings_service/async_client.py +++ b/google/cloud/dialogflowcx_v3/services/security_settings_service/async_client.py @@ -88,7 +88,36 @@ class SecuritySettingsServiceAsyncClient: SecuritySettingsServiceClient.parse_common_location_path ) - from_service_account_file = SecuritySettingsServiceClient.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: + SecuritySettingsServiceAsyncClient: The constructed client. + """ + return SecuritySettingsServiceClient.from_service_account_info.__func__(SecuritySettingsServiceAsyncClient, 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: + SecuritySettingsServiceAsyncClient: The constructed client. + """ + return SecuritySettingsServiceClient.from_service_account_file.__func__(SecuritySettingsServiceAsyncClient, filename, *args, **kwargs) # type: ignore + from_service_account_json = from_service_account_file @property @@ -166,7 +195,7 @@ async def create_security_settings( r"""Create security settings in the specified location. Args: - request (:class:`~.gcdc_security_settings.CreateSecuritySettingsRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.CreateSecuritySettingsRequest`): The request object. The request message for [SecuritySettings.CreateSecuritySettings][]. parent (:class:`str`): @@ -174,12 +203,14 @@ async def create_security_settings( [SecuritySettings][google.cloud.dialogflow.cx.v3.SecuritySettings] for. Format: ``projects//locations/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - security_settings (:class:`~.gcdc_security_settings.SecuritySettings`): + security_settings (:class:`google.cloud.dialogflowcx_v3.types.SecuritySettings`): Required. The security settings to create. + This corresponds to the ``security_settings`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -191,7 +222,7 @@ async def create_security_settings( sent along with the request as metadata. Returns: - ~.gcdc_security_settings.SecuritySettings: + google.cloud.dialogflowcx_v3.types.SecuritySettings: Represents the settings related to security issues, such as data redaction and data retention. It may take hours @@ -254,12 +285,13 @@ async def get_security_settings( The returned settings may be stale by up to 1 minute. Args: - request (:class:`~.security_settings.GetSecuritySettingsRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.GetSecuritySettingsRequest`): The request object. The request message for [SecuritySettingsService.GetSecuritySettings][google.cloud.dialogflow.cx.v3.SecuritySettingsService.GetSecuritySettings]. name (:class:`str`): Required. Resource name of the settings. Format: ``projects//locations//securitySettings/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -271,7 +303,7 @@ async def get_security_settings( sent along with the request as metadata. Returns: - ~.security_settings.SecuritySettings: + google.cloud.dialogflowcx_v3.types.SecuritySettings: Represents the settings related to security issues, such as data redaction and data retention. It may take hours @@ -332,19 +364,21 @@ async def update_security_settings( [SecuritySettings][google.cloud.dialogflow.cx.v3.SecuritySettings]. Args: - request (:class:`~.gcdc_security_settings.UpdateSecuritySettingsRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.UpdateSecuritySettingsRequest`): The request object. The request message for [SecuritySettingsService.UpdateSecuritySettings][google.cloud.dialogflow.cx.v3.SecuritySettingsService.UpdateSecuritySettings]. - security_settings (:class:`~.gcdc_security_settings.SecuritySettings`): + security_settings (:class:`google.cloud.dialogflowcx_v3.types.SecuritySettings`): Required. [SecuritySettings] object that contains values for each of the fields to update. + This corresponds to the ``security_settings`` 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`): Required. The mask to control which fields get updated. If the mask is not present, all fields will be updated. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -356,7 +390,7 @@ async def update_security_settings( sent along with the request as metadata. Returns: - ~.gcdc_security_settings.SecuritySettings: + google.cloud.dialogflowcx_v3.types.SecuritySettings: Represents the settings related to security issues, such as data redaction and data retention. It may take hours @@ -420,13 +454,14 @@ async def list_security_settings( specified location. Args: - request (:class:`~.security_settings.ListSecuritySettingsRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.ListSecuritySettingsRequest`): The request object. The request message for [SecuritySettings.ListSecuritySettings][]. parent (:class:`str`): Required. The location to list all security settings for. Format: ``projects//locations/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -438,7 +473,7 @@ async def list_security_settings( sent along with the request as metadata. Returns: - ~.pagers.ListSecuritySettingsAsyncPager: + google.cloud.dialogflowcx_v3.services.security_settings_service.pagers.ListSecuritySettingsAsyncPager: The response message for [SecuritySettings.ListSecuritySettings][]. @@ -503,7 +538,7 @@ async def delete_security_settings( [SecuritySettings][google.cloud.dialogflow.cx.v3.SecuritySettings]. Args: - request (:class:`~.security_settings.DeleteSecuritySettingsRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.DeleteSecuritySettingsRequest`): The request object. The request message for [SecuritySettings.DeleteSecuritySettings][]. name (:class:`str`): @@ -511,6 +546,7 @@ async def delete_security_settings( [SecuritySettings][google.cloud.dialogflow.cx.v3.SecuritySettings] to delete. Format: ``projects//locations//securitySettings/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. diff --git a/google/cloud/dialogflowcx_v3/services/security_settings_service/client.py b/google/cloud/dialogflowcx_v3/services/security_settings_service/client.py index 1111403a..792e4ac1 100644 --- a/google/cloud/dialogflowcx_v3/services/security_settings_service/client.py +++ b/google/cloud/dialogflowcx_v3/services/security_settings_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: + SecuritySettingsServiceClient: 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. + SecuritySettingsServiceClient: The constructed client. """ credentials = service_account.Credentials.from_service_account_file(filename) kwargs["credentials"] = credentials @@ -238,10 +254,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, ~.SecuritySettingsServiceTransport]): The + transport (Union[str, SecuritySettingsServiceTransport]): 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 @@ -277,21 +293,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: @@ -334,7 +346,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, ) @@ -352,20 +364,22 @@ def create_security_settings( r"""Create security settings in the specified location. Args: - request (:class:`~.gcdc_security_settings.CreateSecuritySettingsRequest`): + request (google.cloud.dialogflowcx_v3.types.CreateSecuritySettingsRequest): The request object. The request message for [SecuritySettings.CreateSecuritySettings][]. - parent (:class:`str`): + parent (str): Required. The location to create an [SecuritySettings][google.cloud.dialogflow.cx.v3.SecuritySettings] for. Format: ``projects//locations/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - security_settings (:class:`~.gcdc_security_settings.SecuritySettings`): + security_settings (google.cloud.dialogflowcx_v3.types.SecuritySettings): Required. The security settings to create. + This corresponds to the ``security_settings`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -377,7 +391,7 @@ def create_security_settings( sent along with the request as metadata. Returns: - ~.gcdc_security_settings.SecuritySettings: + google.cloud.dialogflowcx_v3.types.SecuritySettings: Represents the settings related to security issues, such as data redaction and data retention. It may take hours @@ -443,12 +457,13 @@ def get_security_settings( The returned settings may be stale by up to 1 minute. Args: - request (:class:`~.security_settings.GetSecuritySettingsRequest`): + request (google.cloud.dialogflowcx_v3.types.GetSecuritySettingsRequest): The request object. The request message for [SecuritySettingsService.GetSecuritySettings][google.cloud.dialogflow.cx.v3.SecuritySettingsService.GetSecuritySettings]. - name (:class:`str`): + name (str): Required. Resource name of the settings. Format: ``projects//locations//securitySettings/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -460,7 +475,7 @@ def get_security_settings( sent along with the request as metadata. Returns: - ~.security_settings.SecuritySettings: + google.cloud.dialogflowcx_v3.types.SecuritySettings: Represents the settings related to security issues, such as data redaction and data retention. It may take hours @@ -522,19 +537,21 @@ def update_security_settings( [SecuritySettings][google.cloud.dialogflow.cx.v3.SecuritySettings]. Args: - request (:class:`~.gcdc_security_settings.UpdateSecuritySettingsRequest`): + request (google.cloud.dialogflowcx_v3.types.UpdateSecuritySettingsRequest): The request object. The request message for [SecuritySettingsService.UpdateSecuritySettings][google.cloud.dialogflow.cx.v3.SecuritySettingsService.UpdateSecuritySettings]. - security_settings (:class:`~.gcdc_security_settings.SecuritySettings`): + security_settings (google.cloud.dialogflowcx_v3.types.SecuritySettings): Required. [SecuritySettings] object that contains values for each of the fields to update. + This corresponds to the ``security_settings`` 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): Required. The mask to control which fields get updated. If the mask is not present, all fields will be updated. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -546,7 +563,7 @@ def update_security_settings( sent along with the request as metadata. Returns: - ~.gcdc_security_settings.SecuritySettings: + google.cloud.dialogflowcx_v3.types.SecuritySettings: Represents the settings related to security issues, such as data redaction and data retention. It may take hours @@ -613,13 +630,14 @@ def list_security_settings( specified location. Args: - request (:class:`~.security_settings.ListSecuritySettingsRequest`): + request (google.cloud.dialogflowcx_v3.types.ListSecuritySettingsRequest): The request object. The request message for [SecuritySettings.ListSecuritySettings][]. - parent (:class:`str`): + parent (str): Required. The location to list all security settings for. Format: ``projects//locations/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -631,7 +649,7 @@ def list_security_settings( sent along with the request as metadata. Returns: - ~.pagers.ListSecuritySettingsPager: + google.cloud.dialogflowcx_v3.services.security_settings_service.pagers.ListSecuritySettingsPager: The response message for [SecuritySettings.ListSecuritySettings][]. @@ -697,14 +715,15 @@ def delete_security_settings( [SecuritySettings][google.cloud.dialogflow.cx.v3.SecuritySettings]. Args: - request (:class:`~.security_settings.DeleteSecuritySettingsRequest`): + request (google.cloud.dialogflowcx_v3.types.DeleteSecuritySettingsRequest): The request object. The request message for [SecuritySettings.DeleteSecuritySettings][]. - name (:class:`str`): + name (str): Required. The name of the [SecuritySettings][google.cloud.dialogflow.cx.v3.SecuritySettings] to delete. Format: ``projects//locations//securitySettings/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. diff --git a/google/cloud/dialogflowcx_v3/services/security_settings_service/pagers.py b/google/cloud/dialogflowcx_v3/services/security_settings_service/pagers.py index a195a16b..92dadcce 100644 --- a/google/cloud/dialogflowcx_v3/services/security_settings_service/pagers.py +++ b/google/cloud/dialogflowcx_v3/services/security_settings_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.dialogflowcx_v3.types import security_settings @@ -24,7 +33,7 @@ class ListSecuritySettingsPager: """A pager for iterating through ``list_security_settings`` requests. This class thinly wraps an initial - :class:`~.security_settings.ListSecuritySettingsResponse` object, and + :class:`google.cloud.dialogflowcx_v3.types.ListSecuritySettingsResponse` object, and provides an ``__iter__`` method to iterate through its ``security_settings`` field. @@ -33,7 +42,7 @@ class ListSecuritySettingsPager: through the ``security_settings`` field on the corresponding responses. - All the usual :class:`~.security_settings.ListSecuritySettingsResponse` + All the usual :class:`google.cloud.dialogflowcx_v3.types.ListSecuritySettingsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -51,9 +60,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.security_settings.ListSecuritySettingsRequest`): + request (google.cloud.dialogflowcx_v3.types.ListSecuritySettingsRequest): The initial request object. - response (:class:`~.security_settings.ListSecuritySettingsResponse`): + response (google.cloud.dialogflowcx_v3.types.ListSecuritySettingsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -86,7 +95,7 @@ class ListSecuritySettingsAsyncPager: """A pager for iterating through ``list_security_settings`` requests. This class thinly wraps an initial - :class:`~.security_settings.ListSecuritySettingsResponse` object, and + :class:`google.cloud.dialogflowcx_v3.types.ListSecuritySettingsResponse` object, and provides an ``__aiter__`` method to iterate through its ``security_settings`` field. @@ -95,7 +104,7 @@ class ListSecuritySettingsAsyncPager: through the ``security_settings`` field on the corresponding responses. - All the usual :class:`~.security_settings.ListSecuritySettingsResponse` + All the usual :class:`google.cloud.dialogflowcx_v3.types.ListSecuritySettingsResponse` 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:`~.security_settings.ListSecuritySettingsRequest`): + request (google.cloud.dialogflowcx_v3.types.ListSecuritySettingsRequest): The initial request object. - response (:class:`~.security_settings.ListSecuritySettingsResponse`): + response (google.cloud.dialogflowcx_v3.types.ListSecuritySettingsResponse): 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/dialogflowcx_v3/services/security_settings_service/transports/grpc.py b/google/cloud/dialogflowcx_v3/services/security_settings_service/transports/grpc.py index b1534262..411496f9 100644 --- a/google/cloud/dialogflowcx_v3/services/security_settings_service/transports/grpc.py +++ b/google/cloud/dialogflowcx_v3/services/security_settings_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): @@ -107,6 +112,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -116,11 +126,6 @@ def __init__( 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 @@ -164,12 +169,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ diff --git a/google/cloud/dialogflowcx_v3/services/security_settings_service/transports/grpc_asyncio.py b/google/cloud/dialogflowcx_v3/services/security_settings_service/transports/grpc_asyncio.py index 5110a0da..0464daac 100644 --- a/google/cloud/dialogflowcx_v3/services/security_settings_service/transports/grpc_asyncio.py +++ b/google/cloud/dialogflowcx_v3/services/security_settings_service/transports/grpc_asyncio.py @@ -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,6 +137,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): @@ -152,6 +157,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -161,11 +171,6 @@ def __init__( 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 @@ -209,12 +214,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ diff --git a/google/cloud/dialogflowcx_v3/services/session_entity_types/async_client.py b/google/cloud/dialogflowcx_v3/services/session_entity_types/async_client.py index 1e3c1f38..5a5ac1f7 100644 --- a/google/cloud/dialogflowcx_v3/services/session_entity_types/async_client.py +++ b/google/cloud/dialogflowcx_v3/services/session_entity_types/async_client.py @@ -87,7 +87,36 @@ class SessionEntityTypesAsyncClient: SessionEntityTypesClient.parse_common_location_path ) - from_service_account_file = SessionEntityTypesClient.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: + SessionEntityTypesAsyncClient: The constructed client. + """ + return SessionEntityTypesClient.from_service_account_info.__func__(SessionEntityTypesAsyncClient, 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: + SessionEntityTypesAsyncClient: The constructed client. + """ + return SessionEntityTypesClient.from_service_account_file.__func__(SessionEntityTypesAsyncClient, filename, *args, **kwargs) # type: ignore + from_service_account_json = from_service_account_file @property @@ -165,7 +194,7 @@ async def list_session_entity_types( specified session. Args: - request (:class:`~.session_entity_type.ListSessionEntityTypesRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.ListSessionEntityTypesRequest`): The request object. The request message for [SessionEntityTypes.ListSessionEntityTypes][google.cloud.dialogflow.cx.v3.SessionEntityTypes.ListSessionEntityTypes]. parent (:class:`str`): @@ -176,6 +205,7 @@ async def list_session_entity_types( ``projects//locations//agents//environments//sessions/``. If ``Environment ID`` is not specified, we assume default 'draft' environment. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -187,7 +217,7 @@ async def list_session_entity_types( sent along with the request as metadata. Returns: - ~.pagers.ListSessionEntityTypesAsyncPager: + google.cloud.dialogflowcx_v3.services.session_entity_types.pagers.ListSessionEntityTypesAsyncPager: The response message for [SessionEntityTypes.ListSessionEntityTypes][google.cloud.dialogflow.cx.v3.SessionEntityTypes.ListSessionEntityTypes]. @@ -251,7 +281,7 @@ async def get_session_entity_type( r"""Retrieves the specified session entity type. Args: - request (:class:`~.session_entity_type.GetSessionEntityTypeRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.GetSessionEntityTypeRequest`): The request object. The request message for [SessionEntityTypes.GetSessionEntityType][google.cloud.dialogflow.cx.v3.SessionEntityTypes.GetSessionEntityType]. name (:class:`str`): @@ -261,6 +291,7 @@ async def get_session_entity_type( ``projects//locations//agents//environments//sessions//entityTypes/``. If ``Environment ID`` is not specified, we assume default 'draft' environment. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -272,24 +303,23 @@ async def get_session_entity_type( sent along with the request as metadata. Returns: - ~.session_entity_type.SessionEntityType: - Session entity types are referred to as **User** entity - types and are entities that are built for an individual - user such as favorites, preferences, playlists, and so - on. + google.cloud.dialogflowcx_v3.types.SessionEntityType: + Session entity types are referred to as **User** entity types and are + entities that are built for an individual user such + as favorites, preferences, playlists, and so on. - You can redefine a session entity type at the session - level to extend or replace a [custom entity - type][google.cloud.dialogflow.cx.v3.EntityType] at the - user session level (we refer to the entity types defined - at the agent level as "custom entity types"). + You can redefine a session entity type at the session + level to extend or replace a [custom entity + type][google.cloud.dialogflow.cx.v3.EntityType] at + the user session level (we refer to the entity types + defined at the agent level as "custom entity types"). - Note: session entity types apply to all queries, - regardless of the language. + Note: session entity types apply to all queries, + regardless of the language. - For more information about entity types, see the - `Dialogflow - documentation `__. + For more information about entity types, see the + [Dialogflow + documentation](\ https://cloud.google.com/dialogflow/docs/entities-overview). """ # Create or coerce a protobuf request object. @@ -345,7 +375,7 @@ async def create_session_entity_type( overrides the session entity type. Args: - request (:class:`~.gcdc_session_entity_type.CreateSessionEntityTypeRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.CreateSessionEntityTypeRequest`): The request object. The request message for [SessionEntityTypes.CreateSessionEntityType][google.cloud.dialogflow.cx.v3.SessionEntityTypes.CreateSessionEntityType]. parent (:class:`str`): @@ -356,12 +386,14 @@ async def create_session_entity_type( ``projects//locations//agents//environments//sessions/``. If ``Environment ID`` is not specified, we assume default 'draft' environment. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - session_entity_type (:class:`~.gcdc_session_entity_type.SessionEntityType`): + session_entity_type (:class:`google.cloud.dialogflowcx_v3.types.SessionEntityType`): Required. The session entity type to create. + This corresponds to the ``session_entity_type`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -373,24 +405,23 @@ async def create_session_entity_type( sent along with the request as metadata. Returns: - ~.gcdc_session_entity_type.SessionEntityType: - Session entity types are referred to as **User** entity - types and are entities that are built for an individual - user such as favorites, preferences, playlists, and so - on. + google.cloud.dialogflowcx_v3.types.SessionEntityType: + Session entity types are referred to as **User** entity types and are + entities that are built for an individual user such + as favorites, preferences, playlists, and so on. - You can redefine a session entity type at the session - level to extend or replace a [custom entity - type][google.cloud.dialogflow.cx.v3.EntityType] at the - user session level (we refer to the entity types defined - at the agent level as "custom entity types"). + You can redefine a session entity type at the session + level to extend or replace a [custom entity + type][google.cloud.dialogflow.cx.v3.EntityType] at + the user session level (we refer to the entity types + defined at the agent level as "custom entity types"). - Note: session entity types apply to all queries, - regardless of the language. + Note: session entity types apply to all queries, + regardless of the language. - For more information about entity types, see the - `Dialogflow - documentation `__. + For more information about entity types, see the + [Dialogflow + documentation](\ https://cloud.google.com/dialogflow/docs/entities-overview). """ # Create or coerce a protobuf request object. @@ -446,22 +477,24 @@ async def update_session_entity_type( r"""Updates the specified session entity type. Args: - request (:class:`~.gcdc_session_entity_type.UpdateSessionEntityTypeRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.UpdateSessionEntityTypeRequest`): The request object. The request message for [SessionEntityTypes.UpdateSessionEntityType][google.cloud.dialogflow.cx.v3.SessionEntityTypes.UpdateSessionEntityType]. - session_entity_type (:class:`~.gcdc_session_entity_type.SessionEntityType`): + session_entity_type (:class:`google.cloud.dialogflowcx_v3.types.SessionEntityType`): Required. The session entity type to update. Format: ``projects//locations//agents//sessions//entityTypes/`` or ``projects//locations//agents//environments//sessions//entityTypes/``. If ``Environment ID`` is not specified, we assume default 'draft' environment. + This corresponds to the ``session_entity_type`` 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`): The mask to control which fields get updated. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -473,24 +506,23 @@ async def update_session_entity_type( sent along with the request as metadata. Returns: - ~.gcdc_session_entity_type.SessionEntityType: - Session entity types are referred to as **User** entity - types and are entities that are built for an individual - user such as favorites, preferences, playlists, and so - on. + google.cloud.dialogflowcx_v3.types.SessionEntityType: + Session entity types are referred to as **User** entity types and are + entities that are built for an individual user such + as favorites, preferences, playlists, and so on. - You can redefine a session entity type at the session - level to extend or replace a [custom entity - type][google.cloud.dialogflow.cx.v3.EntityType] at the - user session level (we refer to the entity types defined - at the agent level as "custom entity types"). + You can redefine a session entity type at the session + level to extend or replace a [custom entity + type][google.cloud.dialogflow.cx.v3.EntityType] at + the user session level (we refer to the entity types + defined at the agent level as "custom entity types"). - Note: session entity types apply to all queries, - regardless of the language. + Note: session entity types apply to all queries, + regardless of the language. - For more information about entity types, see the - `Dialogflow - documentation `__. + For more information about entity types, see the + [Dialogflow + documentation](\ https://cloud.google.com/dialogflow/docs/entities-overview). """ # Create or coerce a protobuf request object. @@ -547,7 +579,7 @@ async def delete_session_entity_type( r"""Deletes the specified session entity type. Args: - request (:class:`~.session_entity_type.DeleteSessionEntityTypeRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.DeleteSessionEntityTypeRequest`): The request object. The request message for [SessionEntityTypes.DeleteSessionEntityType][google.cloud.dialogflow.cx.v3.SessionEntityTypes.DeleteSessionEntityType]. name (:class:`str`): @@ -558,6 +590,7 @@ async def delete_session_entity_type( ``projects//locations//agents//environments//sessions//entityTypes/``. If ``Environment ID`` is not specified, we assume default 'draft' environment. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. diff --git a/google/cloud/dialogflowcx_v3/services/session_entity_types/client.py b/google/cloud/dialogflowcx_v3/services/session_entity_types/client.py index ec12fca3..ee3ac536 100644 --- a/google/cloud/dialogflowcx_v3/services/session_entity_types/client.py +++ b/google/cloud/dialogflowcx_v3/services/session_entity_types/client.py @@ -119,6 +119,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: + SessionEntityTypesClient: 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 @@ -131,7 +147,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. + SessionEntityTypesClient: The constructed client. """ credentials = service_account.Credentials.from_service_account_file(filename) kwargs["credentials"] = credentials @@ -245,10 +261,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, ~.SessionEntityTypesTransport]): The + transport (Union[str, SessionEntityTypesTransport]): 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 @@ -284,21 +300,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: @@ -341,7 +353,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, ) @@ -359,10 +371,10 @@ def list_session_entity_types( specified session. Args: - request (:class:`~.session_entity_type.ListSessionEntityTypesRequest`): + request (google.cloud.dialogflowcx_v3.types.ListSessionEntityTypesRequest): The request object. The request message for [SessionEntityTypes.ListSessionEntityTypes][google.cloud.dialogflow.cx.v3.SessionEntityTypes.ListSessionEntityTypes]. - parent (:class:`str`): + parent (str): Required. The session to list all session entity types from. Format: ``projects//locations//agents//sessions/`` @@ -370,6 +382,7 @@ def list_session_entity_types( ``projects//locations//agents//environments//sessions/``. If ``Environment ID`` is not specified, we assume default 'draft' environment. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -381,7 +394,7 @@ def list_session_entity_types( sent along with the request as metadata. Returns: - ~.pagers.ListSessionEntityTypesPager: + google.cloud.dialogflowcx_v3.services.session_entity_types.pagers.ListSessionEntityTypesPager: The response message for [SessionEntityTypes.ListSessionEntityTypes][google.cloud.dialogflow.cx.v3.SessionEntityTypes.ListSessionEntityTypes]. @@ -448,16 +461,17 @@ def get_session_entity_type( r"""Retrieves the specified session entity type. Args: - request (:class:`~.session_entity_type.GetSessionEntityTypeRequest`): + request (google.cloud.dialogflowcx_v3.types.GetSessionEntityTypeRequest): The request object. The request message for [SessionEntityTypes.GetSessionEntityType][google.cloud.dialogflow.cx.v3.SessionEntityTypes.GetSessionEntityType]. - name (:class:`str`): + name (str): Required. The name of the session entity type. Format: ``projects//locations//agents//sessions//entityTypes/`` or ``projects//locations//agents//environments//sessions//entityTypes/``. If ``Environment ID`` is not specified, we assume default 'draft' environment. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -469,24 +483,23 @@ def get_session_entity_type( sent along with the request as metadata. Returns: - ~.session_entity_type.SessionEntityType: - Session entity types are referred to as **User** entity - types and are entities that are built for an individual - user such as favorites, preferences, playlists, and so - on. + google.cloud.dialogflowcx_v3.types.SessionEntityType: + Session entity types are referred to as **User** entity types and are + entities that are built for an individual user such + as favorites, preferences, playlists, and so on. - You can redefine a session entity type at the session - level to extend or replace a [custom entity - type][google.cloud.dialogflow.cx.v3.EntityType] at the - user session level (we refer to the entity types defined - at the agent level as "custom entity types"). + You can redefine a session entity type at the session + level to extend or replace a [custom entity + type][google.cloud.dialogflow.cx.v3.EntityType] at + the user session level (we refer to the entity types + defined at the agent level as "custom entity types"). - Note: session entity types apply to all queries, - regardless of the language. + Note: session entity types apply to all queries, + regardless of the language. - For more information about entity types, see the - `Dialogflow - documentation `__. + For more information about entity types, see the + [Dialogflow + documentation](\ https://cloud.google.com/dialogflow/docs/entities-overview). """ # Create or coerce a protobuf request object. @@ -543,10 +556,10 @@ def create_session_entity_type( overrides the session entity type. Args: - request (:class:`~.gcdc_session_entity_type.CreateSessionEntityTypeRequest`): + request (google.cloud.dialogflowcx_v3.types.CreateSessionEntityTypeRequest): The request object. The request message for [SessionEntityTypes.CreateSessionEntityType][google.cloud.dialogflow.cx.v3.SessionEntityTypes.CreateSessionEntityType]. - parent (:class:`str`): + parent (str): Required. The session to create a session entity type for. Format: ``projects//locations//agents//sessions/`` @@ -554,12 +567,14 @@ def create_session_entity_type( ``projects//locations//agents//environments//sessions/``. If ``Environment ID`` is not specified, we assume default 'draft' environment. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - session_entity_type (:class:`~.gcdc_session_entity_type.SessionEntityType`): + session_entity_type (google.cloud.dialogflowcx_v3.types.SessionEntityType): Required. The session entity type to create. + This corresponds to the ``session_entity_type`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -571,24 +586,23 @@ def create_session_entity_type( sent along with the request as metadata. Returns: - ~.gcdc_session_entity_type.SessionEntityType: - Session entity types are referred to as **User** entity - types and are entities that are built for an individual - user such as favorites, preferences, playlists, and so - on. + google.cloud.dialogflowcx_v3.types.SessionEntityType: + Session entity types are referred to as **User** entity types and are + entities that are built for an individual user such + as favorites, preferences, playlists, and so on. - You can redefine a session entity type at the session - level to extend or replace a [custom entity - type][google.cloud.dialogflow.cx.v3.EntityType] at the - user session level (we refer to the entity types defined - at the agent level as "custom entity types"). + You can redefine a session entity type at the session + level to extend or replace a [custom entity + type][google.cloud.dialogflow.cx.v3.EntityType] at + the user session level (we refer to the entity types + defined at the agent level as "custom entity types"). - Note: session entity types apply to all queries, - regardless of the language. + Note: session entity types apply to all queries, + regardless of the language. - For more information about entity types, see the - `Dialogflow - documentation `__. + For more information about entity types, see the + [Dialogflow + documentation](\ https://cloud.google.com/dialogflow/docs/entities-overview). """ # Create or coerce a protobuf request object. @@ -649,22 +663,24 @@ def update_session_entity_type( r"""Updates the specified session entity type. Args: - request (:class:`~.gcdc_session_entity_type.UpdateSessionEntityTypeRequest`): + request (google.cloud.dialogflowcx_v3.types.UpdateSessionEntityTypeRequest): The request object. The request message for [SessionEntityTypes.UpdateSessionEntityType][google.cloud.dialogflow.cx.v3.SessionEntityTypes.UpdateSessionEntityType]. - session_entity_type (:class:`~.gcdc_session_entity_type.SessionEntityType`): + session_entity_type (google.cloud.dialogflowcx_v3.types.SessionEntityType): Required. The session entity type to update. Format: ``projects//locations//agents//sessions//entityTypes/`` or ``projects//locations//agents//environments//sessions//entityTypes/``. If ``Environment ID`` is not specified, we assume default 'draft' environment. + This corresponds to the ``session_entity_type`` 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): The mask to control which fields get updated. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -676,24 +692,23 @@ def update_session_entity_type( sent along with the request as metadata. Returns: - ~.gcdc_session_entity_type.SessionEntityType: - Session entity types are referred to as **User** entity - types and are entities that are built for an individual - user such as favorites, preferences, playlists, and so - on. + google.cloud.dialogflowcx_v3.types.SessionEntityType: + Session entity types are referred to as **User** entity types and are + entities that are built for an individual user such + as favorites, preferences, playlists, and so on. - You can redefine a session entity type at the session - level to extend or replace a [custom entity - type][google.cloud.dialogflow.cx.v3.EntityType] at the - user session level (we refer to the entity types defined - at the agent level as "custom entity types"). + You can redefine a session entity type at the session + level to extend or replace a [custom entity + type][google.cloud.dialogflow.cx.v3.EntityType] at + the user session level (we refer to the entity types + defined at the agent level as "custom entity types"). - Note: session entity types apply to all queries, - regardless of the language. + Note: session entity types apply to all queries, + regardless of the language. - For more information about entity types, see the - `Dialogflow - documentation `__. + For more information about entity types, see the + [Dialogflow + documentation](\ https://cloud.google.com/dialogflow/docs/entities-overview). """ # Create or coerce a protobuf request object. @@ -755,10 +770,10 @@ def delete_session_entity_type( r"""Deletes the specified session entity type. Args: - request (:class:`~.session_entity_type.DeleteSessionEntityTypeRequest`): + request (google.cloud.dialogflowcx_v3.types.DeleteSessionEntityTypeRequest): The request object. The request message for [SessionEntityTypes.DeleteSessionEntityType][google.cloud.dialogflow.cx.v3.SessionEntityTypes.DeleteSessionEntityType]. - name (:class:`str`): + name (str): Required. The name of the session entity type to delete. Format: ``projects//locations//agents//sessions//entityTypes/`` @@ -766,6 +781,7 @@ def delete_session_entity_type( ``projects//locations//agents//environments//sessions//entityTypes/``. If ``Environment ID`` is not specified, we assume default 'draft' environment. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. diff --git a/google/cloud/dialogflowcx_v3/services/session_entity_types/pagers.py b/google/cloud/dialogflowcx_v3/services/session_entity_types/pagers.py index 89264424..3c6d5582 100644 --- a/google/cloud/dialogflowcx_v3/services/session_entity_types/pagers.py +++ b/google/cloud/dialogflowcx_v3/services/session_entity_types/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.dialogflowcx_v3.types import session_entity_type @@ -24,7 +33,7 @@ class ListSessionEntityTypesPager: """A pager for iterating through ``list_session_entity_types`` requests. This class thinly wraps an initial - :class:`~.session_entity_type.ListSessionEntityTypesResponse` object, and + :class:`google.cloud.dialogflowcx_v3.types.ListSessionEntityTypesResponse` object, and provides an ``__iter__`` method to iterate through its ``session_entity_types`` field. @@ -33,7 +42,7 @@ class ListSessionEntityTypesPager: through the ``session_entity_types`` field on the corresponding responses. - All the usual :class:`~.session_entity_type.ListSessionEntityTypesResponse` + All the usual :class:`google.cloud.dialogflowcx_v3.types.ListSessionEntityTypesResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -51,9 +60,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.session_entity_type.ListSessionEntityTypesRequest`): + request (google.cloud.dialogflowcx_v3.types.ListSessionEntityTypesRequest): The initial request object. - response (:class:`~.session_entity_type.ListSessionEntityTypesResponse`): + response (google.cloud.dialogflowcx_v3.types.ListSessionEntityTypesResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -86,7 +95,7 @@ class ListSessionEntityTypesAsyncPager: """A pager for iterating through ``list_session_entity_types`` requests. This class thinly wraps an initial - :class:`~.session_entity_type.ListSessionEntityTypesResponse` object, and + :class:`google.cloud.dialogflowcx_v3.types.ListSessionEntityTypesResponse` object, and provides an ``__aiter__`` method to iterate through its ``session_entity_types`` field. @@ -95,7 +104,7 @@ class ListSessionEntityTypesAsyncPager: through the ``session_entity_types`` field on the corresponding responses. - All the usual :class:`~.session_entity_type.ListSessionEntityTypesResponse` + All the usual :class:`google.cloud.dialogflowcx_v3.types.ListSessionEntityTypesResponse` 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:`~.session_entity_type.ListSessionEntityTypesRequest`): + request (google.cloud.dialogflowcx_v3.types.ListSessionEntityTypesRequest): The initial request object. - response (:class:`~.session_entity_type.ListSessionEntityTypesResponse`): + response (google.cloud.dialogflowcx_v3.types.ListSessionEntityTypesResponse): 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/dialogflowcx_v3/services/session_entity_types/transports/grpc.py b/google/cloud/dialogflowcx_v3/services/session_entity_types/transports/grpc.py index dde1f9ab..ff48f310 100644 --- a/google/cloud/dialogflowcx_v3/services/session_entity_types/transports/grpc.py +++ b/google/cloud/dialogflowcx_v3/services/session_entity_types/transports/grpc.py @@ -62,6 +62,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: @@ -92,6 +93,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): @@ -108,6 +113,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -117,11 +127,6 @@ def __init__( 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 @@ -165,12 +170,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ diff --git a/google/cloud/dialogflowcx_v3/services/session_entity_types/transports/grpc_asyncio.py b/google/cloud/dialogflowcx_v3/services/session_entity_types/transports/grpc_asyncio.py index 6ede83ac..ded1d164 100644 --- a/google/cloud/dialogflowcx_v3/services/session_entity_types/transports/grpc_asyncio.py +++ b/google/cloud/dialogflowcx_v3/services/session_entity_types/transports/grpc_asyncio.py @@ -106,6 +106,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: @@ -137,6 +138,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): @@ -153,6 +158,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -162,11 +172,6 @@ def __init__( 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 @@ -210,12 +215,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ diff --git a/google/cloud/dialogflowcx_v3/services/sessions/async_client.py b/google/cloud/dialogflowcx_v3/services/sessions/async_client.py index fe65ea1d..b11caaa2 100644 --- a/google/cloud/dialogflowcx_v3/services/sessions/async_client.py +++ b/google/cloud/dialogflowcx_v3/services/sessions/async_client.py @@ -102,7 +102,36 @@ class SessionsAsyncClient: common_location_path = staticmethod(SessionsClient.common_location_path) parse_common_location_path = staticmethod(SessionsClient.parse_common_location_path) - from_service_account_file = SessionsClient.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: + SessionsAsyncClient: The constructed client. + """ + return SessionsClient.from_service_account_info.__func__(SessionsAsyncClient, 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: + SessionsAsyncClient: The constructed client. + """ + return SessionsClient.from_service_account_file.__func__(SessionsAsyncClient, filename, *args, **kwargs) # type: ignore + from_service_account_json = from_service_account_file @property @@ -184,7 +213,7 @@ async def detect_intent( environments `__. Args: - request (:class:`~.session.DetectIntentRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.DetectIntentRequest`): The request object. The request to detect user's intent. retry (google.api_core.retry.Retry): Designation of what errors, if any, @@ -194,7 +223,7 @@ async def detect_intent( sent along with the request as metadata. Returns: - ~.session.DetectIntentResponse: + google.cloud.dialogflowcx_v3.types.DetectIntentResponse: The message returned from the DetectIntent method. @@ -247,7 +276,7 @@ def streaming_detect_intent( environments `__. Args: - requests (AsyncIterator[`~.session.StreamingDetectIntentRequest`]): + requests (AsyncIterator[`google.cloud.dialogflowcx_v3.types.StreamingDetectIntentRequest`]): The request object AsyncIterator. The top-level message sent by the client to the [Sessions.StreamingDetectIntent][google.cloud.dialogflow.cx.v3.Sessions.StreamingDetectIntent] @@ -289,20 +318,18 @@ def streaming_detect_intent( sent along with the request as metadata. Returns: - AsyncIterable[~.session.StreamingDetectIntentResponse]: + AsyncIterable[google.cloud.dialogflowcx_v3.types.StreamingDetectIntentResponse]: The top-level message returned from the - ``StreamingDetectIntent`` method. - - Multiple response messages can be returned in order: + StreamingDetectIntent method. - 1. If the input was set to streaming audio, the first - one or more messages contain ``recognition_result``. - Each ``recognition_result`` represents a more - complete transcript of what the user said. The last - ``recognition_result`` has ``is_final`` set to - ``true``. + Multiple response messages can be returned in order: - 2. The last message contains ``detect_intent_response``. + 1. If the input was set to streaming audio, the first + one or more messages contain recognition_result. + Each recognition_result represents a more complete + transcript of what the user said. The last + recognition_result has is_final set to true. + 2. The last message contains detect_intent_response. """ @@ -332,7 +359,7 @@ async def match_intent( change the session status. Args: - request (:class:`~.session.MatchIntentRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.MatchIntentRequest`): The request object. Request of [MatchIntent][]. retry (google.api_core.retry.Retry): Designation of what errors, if any, @@ -342,7 +369,7 @@ async def match_intent( sent along with the request as metadata. Returns: - ~.session.MatchIntentResponse: + google.cloud.dialogflowcx_v3.types.MatchIntentResponse: Response of [MatchIntent][]. """ # Create or coerce a protobuf request object. @@ -386,7 +413,7 @@ async def fulfill_intent( Otherwise, the behavior is undefined. Args: - request (:class:`~.session.FulfillIntentRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.FulfillIntentRequest`): The request object. Request of [FulfillIntent][] retry (google.api_core.retry.Retry): Designation of what errors, if any, @@ -396,7 +423,7 @@ async def fulfill_intent( sent along with the request as metadata. Returns: - ~.session.FulfillIntentResponse: + google.cloud.dialogflowcx_v3.types.FulfillIntentResponse: Response of [FulfillIntent][] """ # Create or coerce a protobuf request object. diff --git a/google/cloud/dialogflowcx_v3/services/sessions/client.py b/google/cloud/dialogflowcx_v3/services/sessions/client.py index e9fcdbca..9090501e 100644 --- a/google/cloud/dialogflowcx_v3/services/sessions/client.py +++ b/google/cloud/dialogflowcx_v3/services/sessions/client.py @@ -123,6 +123,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: + SessionsClient: 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 @@ -135,7 +151,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. + SessionsClient: The constructed client. """ credentials = service_account.Credentials.from_service_account_file(filename) kwargs["credentials"] = credentials @@ -371,10 +387,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, ~.SessionsTransport]): The + transport (Union[str, SessionsTransport]): 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 @@ -410,21 +426,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: @@ -467,7 +479,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, ) @@ -490,7 +502,7 @@ def detect_intent( environments `__. Args: - request (:class:`~.session.DetectIntentRequest`): + request (google.cloud.dialogflowcx_v3.types.DetectIntentRequest): The request object. The request to detect user's intent. retry (google.api_core.retry.Retry): Designation of what errors, if any, @@ -500,7 +512,7 @@ def detect_intent( sent along with the request as metadata. Returns: - ~.session.DetectIntentResponse: + google.cloud.dialogflowcx_v3.types.DetectIntentResponse: The message returned from the DetectIntent method. @@ -548,7 +560,7 @@ def streaming_detect_intent( environments `__. Args: - requests (Iterator[`~.session.StreamingDetectIntentRequest`]): + requests (Iterator[google.cloud.dialogflowcx_v3.types.StreamingDetectIntentRequest]): The request object iterator. The top-level message sent by the client to the [Sessions.StreamingDetectIntent][google.cloud.dialogflow.cx.v3.Sessions.StreamingDetectIntent] @@ -590,20 +602,18 @@ def streaming_detect_intent( sent along with the request as metadata. Returns: - Iterable[~.session.StreamingDetectIntentResponse]: + Iterable[google.cloud.dialogflowcx_v3.types.StreamingDetectIntentResponse]: The top-level message returned from the - ``StreamingDetectIntent`` method. - - Multiple response messages can be returned in order: + StreamingDetectIntent method. - 1. If the input was set to streaming audio, the first - one or more messages contain ``recognition_result``. - Each ``recognition_result`` represents a more - complete transcript of what the user said. The last - ``recognition_result`` has ``is_final`` set to - ``true``. + Multiple response messages can be returned in order: - 2. The last message contains ``detect_intent_response``. + 1. If the input was set to streaming audio, the first + one or more messages contain recognition_result. + Each recognition_result represents a more complete + transcript of what the user said. The last + recognition_result has is_final set to true. + 2. The last message contains detect_intent_response. """ @@ -629,7 +639,7 @@ def match_intent( change the session status. Args: - request (:class:`~.session.MatchIntentRequest`): + request (google.cloud.dialogflowcx_v3.types.MatchIntentRequest): The request object. Request of [MatchIntent][]. retry (google.api_core.retry.Retry): Designation of what errors, if any, @@ -639,7 +649,7 @@ def match_intent( sent along with the request as metadata. Returns: - ~.session.MatchIntentResponse: + google.cloud.dialogflowcx_v3.types.MatchIntentResponse: Response of [MatchIntent][]. """ # Create or coerce a protobuf request object. @@ -684,7 +694,7 @@ def fulfill_intent( Otherwise, the behavior is undefined. Args: - request (:class:`~.session.FulfillIntentRequest`): + request (google.cloud.dialogflowcx_v3.types.FulfillIntentRequest): The request object. Request of [FulfillIntent][] retry (google.api_core.retry.Retry): Designation of what errors, if any, @@ -694,7 +704,7 @@ def fulfill_intent( sent along with the request as metadata. Returns: - ~.session.FulfillIntentResponse: + google.cloud.dialogflowcx_v3.types.FulfillIntentResponse: Response of [FulfillIntent][] """ # Create or coerce a protobuf request object. diff --git a/google/cloud/dialogflowcx_v3/services/sessions/transports/grpc.py b/google/cloud/dialogflowcx_v3/services/sessions/transports/grpc.py index b12713d7..b3d708f1 100644 --- a/google/cloud/dialogflowcx_v3/services/sessions/transports/grpc.py +++ b/google/cloud/dialogflowcx_v3/services/sessions/transports/grpc.py @@ -60,6 +60,7 @@ def __init__( api_mtls_endpoint: str = None, client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, quota_project_id: Optional[str] = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: @@ -90,6 +91,10 @@ def __init__( ``api_mtls_endpoint`` is None. ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials for grpc channel. It is ignored if ``channel`` is provided. + client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]): + A callback to provide client certificate bytes and private key bytes, + both in PEM format. It is used to configure mutual TLS channel. It is + ignored if ``channel`` or ``ssl_channel_credentials`` is provided. quota_project_id (Optional[str]): An optional project to use for billing and quota. client_info (google.api_core.gapic_v1.client_info.ClientInfo): @@ -106,6 +111,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -115,11 +125,6 @@ def __init__( 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 @@ -163,12 +168,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ diff --git a/google/cloud/dialogflowcx_v3/services/sessions/transports/grpc_asyncio.py b/google/cloud/dialogflowcx_v3/services/sessions/transports/grpc_asyncio.py index f8e6e3dd..eb290674 100644 --- a/google/cloud/dialogflowcx_v3/services/sessions/transports/grpc_asyncio.py +++ b/google/cloud/dialogflowcx_v3/services/sessions/transports/grpc_asyncio.py @@ -104,6 +104,7 @@ def __init__( api_mtls_endpoint: str = None, client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, quota_project_id=None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: @@ -135,6 +136,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): @@ -151,6 +156,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -160,11 +170,6 @@ def __init__( 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 @@ -208,12 +213,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ diff --git a/google/cloud/dialogflowcx_v3/services/test_cases/__init__.py b/google/cloud/dialogflowcx_v3/services/test_cases/__init__.py new file mode 100644 index 00000000..77517b44 --- /dev/null +++ b/google/cloud/dialogflowcx_v3/services/test_cases/__init__.py @@ -0,0 +1,24 @@ +# -*- 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. +# + +from .client import TestCasesClient +from .async_client import TestCasesAsyncClient + +__all__ = ( + "TestCasesClient", + "TestCasesAsyncClient", +) diff --git a/google/cloud/dialogflowcx_v3/services/test_cases/async_client.py b/google/cloud/dialogflowcx_v3/services/test_cases/async_client.py new file mode 100644 index 00000000..4f8262ae --- /dev/null +++ b/google/cloud/dialogflowcx_v3/services/test_cases/async_client.py @@ -0,0 +1,984 @@ +# -*- 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. +# + +from collections import OrderedDict +import functools +import re +from typing import Dict, Sequence, Tuple, Type, Union +import pkg_resources + +import google.api_core.client_options as ClientOptions # type: ignore +from google.api_core import exceptions # type: ignore +from google.api_core import gapic_v1 # type: ignore +from google.api_core import retry as retries # type: ignore +from google.auth import credentials # type: ignore +from google.oauth2 import service_account # type: ignore + +from google.api_core import operation # type: ignore +from google.api_core import operation_async # type: ignore +from google.cloud.dialogflowcx_v3.services.test_cases import pagers +from google.cloud.dialogflowcx_v3.types import test_case +from google.cloud.dialogflowcx_v3.types import test_case as gcdc_test_case +from google.protobuf import field_mask_pb2 as field_mask # type: ignore +from google.protobuf import timestamp_pb2 as timestamp # type: ignore + +from .transports.base import TestCasesTransport, DEFAULT_CLIENT_INFO +from .transports.grpc_asyncio import TestCasesGrpcAsyncIOTransport +from .client import TestCasesClient + + +class TestCasesAsyncClient: + """Service for managing [Test + Cases][google.cloud.dialogflow.cx.v3.TestCase] and [Test Case + Results][google.cloud.dialogflow.cx.v3.TestCaseResult]. + """ + + _client: TestCasesClient + + DEFAULT_ENDPOINT = TestCasesClient.DEFAULT_ENDPOINT + DEFAULT_MTLS_ENDPOINT = TestCasesClient.DEFAULT_MTLS_ENDPOINT + + agent_path = staticmethod(TestCasesClient.agent_path) + parse_agent_path = staticmethod(TestCasesClient.parse_agent_path) + entity_type_path = staticmethod(TestCasesClient.entity_type_path) + parse_entity_type_path = staticmethod(TestCasesClient.parse_entity_type_path) + environment_path = staticmethod(TestCasesClient.environment_path) + parse_environment_path = staticmethod(TestCasesClient.parse_environment_path) + flow_path = staticmethod(TestCasesClient.flow_path) + parse_flow_path = staticmethod(TestCasesClient.parse_flow_path) + intent_path = staticmethod(TestCasesClient.intent_path) + parse_intent_path = staticmethod(TestCasesClient.parse_intent_path) + page_path = staticmethod(TestCasesClient.page_path) + parse_page_path = staticmethod(TestCasesClient.parse_page_path) + test_case_path = staticmethod(TestCasesClient.test_case_path) + parse_test_case_path = staticmethod(TestCasesClient.parse_test_case_path) + test_case_result_path = staticmethod(TestCasesClient.test_case_result_path) + parse_test_case_result_path = staticmethod( + TestCasesClient.parse_test_case_result_path + ) + transition_route_group_path = staticmethod( + TestCasesClient.transition_route_group_path + ) + parse_transition_route_group_path = staticmethod( + TestCasesClient.parse_transition_route_group_path + ) + webhook_path = staticmethod(TestCasesClient.webhook_path) + parse_webhook_path = staticmethod(TestCasesClient.parse_webhook_path) + + common_billing_account_path = staticmethod( + TestCasesClient.common_billing_account_path + ) + parse_common_billing_account_path = staticmethod( + TestCasesClient.parse_common_billing_account_path + ) + + common_folder_path = staticmethod(TestCasesClient.common_folder_path) + parse_common_folder_path = staticmethod(TestCasesClient.parse_common_folder_path) + + common_organization_path = staticmethod(TestCasesClient.common_organization_path) + parse_common_organization_path = staticmethod( + TestCasesClient.parse_common_organization_path + ) + + common_project_path = staticmethod(TestCasesClient.common_project_path) + parse_common_project_path = staticmethod(TestCasesClient.parse_common_project_path) + + common_location_path = staticmethod(TestCasesClient.common_location_path) + parse_common_location_path = staticmethod( + TestCasesClient.parse_common_location_path + ) + + @classmethod + def from_service_account_info(cls, info: dict, *args, **kwargs): + """Creates an instance of this client using the provided credentials info. + + Args: + info (dict): The service account private key info. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + TestCasesAsyncClient: The constructed client. + """ + return TestCasesClient.from_service_account_info.__func__(TestCasesAsyncClient, 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: + TestCasesAsyncClient: The constructed client. + """ + return TestCasesClient.from_service_account_file.__func__(TestCasesAsyncClient, filename, *args, **kwargs) # type: ignore + + from_service_account_json = from_service_account_file + + @property + def transport(self) -> TestCasesTransport: + """Return the transport used by the client instance. + + Returns: + TestCasesTransport: The transport used by the client instance. + """ + return self._client.transport + + get_transport_class = functools.partial( + type(TestCasesClient).get_transport_class, type(TestCasesClient) + ) + + def __init__( + self, + *, + credentials: credentials.Credentials = None, + transport: Union[str, TestCasesTransport] = "grpc_asyncio", + client_options: ClientOptions = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + ) -> None: + """Instantiate the test cases client. + + Args: + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + transport (Union[str, ~.TestCasesTransport]): The + transport to use. If set to None, a transport is chosen + automatically. + client_options (ClientOptions): Custom options for the client. It + won't take effect if a ``transport`` instance is provided. + (1) The ``api_endpoint`` property can be used to override the + default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT + environment variable can also be used to override the endpoint: + "always" (always use the default mTLS endpoint), "never" (always + use the default regular endpoint) and "auto" (auto switch to the + default mTLS endpoint if client certificate is present, this is + the default value). However, the ``api_endpoint`` property takes + precedence if provided. + (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable + is "true", then the ``client_cert_source`` property can be used + to provide client certificate for mutual TLS transport. If + not provided, the default SSL client certificate will be used if + present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not + set, no client certificate will be used. + + Raises: + google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport + creation failed for any reason. + """ + + self._client = TestCasesClient( + credentials=credentials, + transport=transport, + client_options=client_options, + client_info=client_info, + ) + + async def list_test_cases( + self, + request: test_case.ListTestCasesRequest = None, + *, + parent: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListTestCasesAsyncPager: + r"""Fetches a list of test cases for a given agent. + + Args: + request (:class:`google.cloud.dialogflowcx_v3.types.ListTestCasesRequest`): + The request object. The request message for + [TestCases.ListTestCases][google.cloud.dialogflow.cx.v3.TestCases.ListTestCases]. + parent (:class:`str`): + Required. The agent to list all pages for. Format: + ``projects//locations//agents/``. + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.dialogflowcx_v3.services.test_cases.pagers.ListTestCasesAsyncPager: + The response message for + [TestCases.ListTestCases][google.cloud.dialogflow.cx.v3.TestCases.ListTestCases]. + + Iterating over this object will yield results and + resolve additional pages automatically. + + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([parent]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = test_case.ListTestCasesRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + + if parent is not None: + request.parent = parent + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.list_test_cases, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = await rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # This method is paged; wrap the response in a pager, which provides + # an `__aiter__` convenience method. + response = pagers.ListTestCasesAsyncPager( + method=rpc, request=request, response=response, metadata=metadata, + ) + + # Done; return the response. + return response + + async def batch_delete_test_cases( + self, + request: test_case.BatchDeleteTestCasesRequest = None, + *, + parent: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + r"""Batch deletes test cases. + + Args: + request (:class:`google.cloud.dialogflowcx_v3.types.BatchDeleteTestCasesRequest`): + The request object. The request message for + [TestCases.BatchDeleteTestCases][google.cloud.dialogflow.cx.v3.TestCases.BatchDeleteTestCases]. + parent (:class:`str`): + Required. The agent to delete test cases from. Format: + ``projects//locations//agents/``. + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([parent]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = test_case.BatchDeleteTestCasesRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + + if parent is not None: + request.parent = parent + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.batch_delete_test_cases, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + await rpc( + request, retry=retry, timeout=timeout, metadata=metadata, + ) + + async def get_test_case( + self, + request: test_case.GetTestCaseRequest = None, + *, + name: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> test_case.TestCase: + r"""Gets a test case. + + Args: + request (:class:`google.cloud.dialogflowcx_v3.types.GetTestCaseRequest`): + The request object. The request message for + [TestCases.GetTestCase][google.cloud.dialogflow.cx.v3.TestCases.GetTestCase]. + name (:class:`str`): + Required. The name of the testcase. Format: + ``projects//locations//agents//testCases/``. + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.dialogflowcx_v3.types.TestCase: + Represents a test case. + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = test_case.GetTestCaseRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.get_test_case, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = await rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + + async def create_test_case( + self, + request: gcdc_test_case.CreateTestCaseRequest = None, + *, + parent: str = None, + test_case: gcdc_test_case.TestCase = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_test_case.TestCase: + r"""Creates a test case for the given agent. + + Args: + request (:class:`google.cloud.dialogflowcx_v3.types.CreateTestCaseRequest`): + The request object. The request message for + [TestCases.CreateTestCase][google.cloud.dialogflow.cx.v3.TestCases.CreateTestCase]. + parent (:class:`str`): + Required. The agent to create the test case for. Format: + ``projects//locations//agents/``. + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + test_case (:class:`google.cloud.dialogflowcx_v3.types.TestCase`): + Required. The test case to create. + This corresponds to the ``test_case`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.dialogflowcx_v3.types.TestCase: + Represents a test case. + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([parent, test_case]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = gcdc_test_case.CreateTestCaseRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + + if parent is not None: + request.parent = parent + if test_case is not None: + request.test_case = test_case + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.create_test_case, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = await rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + + async def update_test_case( + self, + request: gcdc_test_case.UpdateTestCaseRequest = None, + *, + test_case: gcdc_test_case.TestCase = None, + update_mask: field_mask.FieldMask = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_test_case.TestCase: + r"""Updates the specified test case. + + Args: + request (:class:`google.cloud.dialogflowcx_v3.types.UpdateTestCaseRequest`): + The request object. The request message for + [TestCases.UpdateTestCase][google.cloud.dialogflow.cx.v3.TestCases.UpdateTestCase]. + test_case (:class:`google.cloud.dialogflowcx_v3.types.TestCase`): + Required. The test case to update. + This corresponds to the ``test_case`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + update_mask (:class:`google.protobuf.field_mask_pb2.FieldMask`): + Required. The mask to specify which fields should be + updated. The + [``creationTime``][google.cloud.dialogflow.cx.v3.TestCase.creation_time] + and + [``lastTestResult``][google.cloud.dialogflow.cx.v3.TestCase.last_test_result] + cannot be updated. + + This corresponds to the ``update_mask`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.dialogflowcx_v3.types.TestCase: + Represents a test case. + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([test_case, update_mask]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = gcdc_test_case.UpdateTestCaseRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + + if test_case is not None: + request.test_case = test_case + if update_mask is not None: + request.update_mask = update_mask + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.update_test_case, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("test_case.name", request.test_case.name),) + ), + ) + + # Send the request. + response = await rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + + async def run_test_case( + self, + request: test_case.RunTestCaseRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operation_async.AsyncOperation: + r"""Kicks off a test case run. + + Args: + request (:class:`google.cloud.dialogflowcx_v3.types.RunTestCaseRequest`): + The request object. The request message for + [TestCases.RunTestCase][google.cloud.dialogflow.cx.v3.TestCases.RunTestCase]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.api_core.operation_async.AsyncOperation: + An object representing a long-running operation. + + The result type for the operation will be + :class:`google.cloud.dialogflowcx_v3.types.RunTestCaseResponse` + The response message for + [TestCases.RunTestCase][google.cloud.dialogflow.cx.v3.TestCases.RunTestCase]. + + """ + # Create or coerce a protobuf request object. + + request = test_case.RunTestCaseRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.run_test_case, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = await rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Wrap the response in an operation future. + response = operation_async.from_gapic( + response, + self._client._transport.operations_client, + test_case.RunTestCaseResponse, + metadata_type=test_case.RunTestCaseMetadata, + ) + + # Done; return the response. + return response + + async def batch_run_test_cases( + self, + request: test_case.BatchRunTestCasesRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operation_async.AsyncOperation: + r"""Kicks off a batch run of test cases. + + Args: + request (:class:`google.cloud.dialogflowcx_v3.types.BatchRunTestCasesRequest`): + The request object. The request message for + [TestCases.BatchRunTestCases][google.cloud.dialogflow.cx.v3.TestCases.BatchRunTestCases]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.api_core.operation_async.AsyncOperation: + An object representing a long-running operation. + + The result type for the operation will be + :class:`google.cloud.dialogflowcx_v3.types.BatchRunTestCasesResponse` + The response message for + [TestCases.BatchRunTestCases][google.cloud.dialogflow.cx.v3.TestCases.BatchRunTestCases]. + + """ + # Create or coerce a protobuf request object. + + request = test_case.BatchRunTestCasesRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.batch_run_test_cases, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = await rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Wrap the response in an operation future. + response = operation_async.from_gapic( + response, + self._client._transport.operations_client, + test_case.BatchRunTestCasesResponse, + metadata_type=test_case.BatchRunTestCasesMetadata, + ) + + # Done; return the response. + return response + + async def calculate_coverage( + self, + request: test_case.CalculateCoverageRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> test_case.CalculateCoverageResponse: + r"""Calculates the test coverage for an agent. + + Args: + request (:class:`google.cloud.dialogflowcx_v3.types.CalculateCoverageRequest`): + The request object. The request message for + [TestCases.CalculateCoverage][google.cloud.dialogflow.cx.v3.TestCases.CalculateCoverage]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.dialogflowcx_v3.types.CalculateCoverageResponse: + The response message for + [TestCases.CalculateCoverage][google.cloud.dialogflow.cx.v3.TestCases.CalculateCoverage]. + + """ + # Create or coerce a protobuf request object. + + request = test_case.CalculateCoverageRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.calculate_coverage, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("agent", request.agent),)), + ) + + # Send the request. + response = await rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + + async def import_test_cases( + self, + request: test_case.ImportTestCasesRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operation_async.AsyncOperation: + r"""Imports the test cases from a Cloud Storage bucket or + a local file. It always creates new test cases and won't + overwite any existing ones. The provided ID in the + imported test case is neglected. + + Args: + request (:class:`google.cloud.dialogflowcx_v3.types.ImportTestCasesRequest`): + The request object. The request message for + [TestCases.ImportTestCases][google.cloud.dialogflow.cx.v3.TestCases.ImportTestCases]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.api_core.operation_async.AsyncOperation: + An object representing a long-running operation. + + The result type for the operation will be + :class:`google.cloud.dialogflowcx_v3.types.ImportTestCasesResponse` + The response message for + [TestCases.ImportTestCases][google.cloud.dialogflow.cx.v3.TestCases.ImportTestCases]. + + """ + # Create or coerce a protobuf request object. + + request = test_case.ImportTestCasesRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.import_test_cases, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = await rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Wrap the response in an operation future. + response = operation_async.from_gapic( + response, + self._client._transport.operations_client, + test_case.ImportTestCasesResponse, + metadata_type=test_case.ImportTestCasesMetadata, + ) + + # Done; return the response. + return response + + async def export_test_cases( + self, + request: test_case.ExportTestCasesRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operation_async.AsyncOperation: + r"""Exports the test cases under the agent to a Cloud + Storage bucket or a local file. Filter can be applied to + export a subset of test cases. + + Args: + request (:class:`google.cloud.dialogflowcx_v3.types.ExportTestCasesRequest`): + The request object. The request message for + [TestCases.ExportTestCases][google.cloud.dialogflow.cx.v3.TestCases.ExportTestCases]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.api_core.operation_async.AsyncOperation: + An object representing a long-running operation. + + The result type for the operation will be + :class:`google.cloud.dialogflowcx_v3.types.ExportTestCasesResponse` + The response message for + [TestCases.ExportTestCases][google.cloud.dialogflow.cx.v3.TestCases.ExportTestCases]. + + """ + # Create or coerce a protobuf request object. + + request = test_case.ExportTestCasesRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.export_test_cases, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = await rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Wrap the response in an operation future. + response = operation_async.from_gapic( + response, + self._client._transport.operations_client, + test_case.ExportTestCasesResponse, + metadata_type=test_case.ExportTestCasesMetadata, + ) + + # Done; return the response. + return response + + async def list_test_case_results( + self, + request: test_case.ListTestCaseResultsRequest = None, + *, + parent: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListTestCaseResultsAsyncPager: + r"""Fetches a list of results for a given test case. + + Args: + request (:class:`google.cloud.dialogflowcx_v3.types.ListTestCaseResultsRequest`): + The request object. The request message for + [TestCases.ListTestCaseResults][google.cloud.dialogflow.cx.v3.TestCases.ListTestCaseResults]. + parent (:class:`str`): + Required. The test case to list results for. Format: + ``projects//locations//agents// testCases/``. + Specify a ``-`` as a wildcard for TestCase ID to list + results across multiple test cases. + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.dialogflowcx_v3.services.test_cases.pagers.ListTestCaseResultsAsyncPager: + The response message for + [TestCases.ListTestCaseResults][google.cloud.dialogflow.cx.v3.TestCases.ListTestCaseResults]. + + Iterating over this object will yield results and + resolve additional pages automatically. + + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([parent]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = test_case.ListTestCaseResultsRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + + if parent is not None: + request.parent = parent + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.list_test_case_results, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = await rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # This method is paged; wrap the response in a pager, which provides + # an `__aiter__` convenience method. + response = pagers.ListTestCaseResultsAsyncPager( + method=rpc, request=request, response=response, metadata=metadata, + ) + + # Done; return the response. + return response + + +try: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=pkg_resources.get_distribution( + "google-cloud-dialogflowcx", + ).version, + ) +except pkg_resources.DistributionNotFound: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() + + +__all__ = ("TestCasesAsyncClient",) diff --git a/google/cloud/dialogflowcx_v3/services/test_cases/client.py b/google/cloud/dialogflowcx_v3/services/test_cases/client.py new file mode 100644 index 00000000..0d882cc7 --- /dev/null +++ b/google/cloud/dialogflowcx_v3/services/test_cases/client.py @@ -0,0 +1,1311 @@ +# -*- 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. +# + +from collections import OrderedDict +from distutils import util +import os +import re +from typing import Callable, Dict, Optional, Sequence, Tuple, Type, Union +import pkg_resources + +from google.api_core import client_options as client_options_lib # type: ignore +from google.api_core import exceptions # type: ignore +from google.api_core import gapic_v1 # type: ignore +from google.api_core import retry as retries # type: ignore +from google.auth import credentials # type: ignore +from google.auth.transport import mtls # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth.exceptions import MutualTLSChannelError # type: ignore +from google.oauth2 import service_account # type: ignore + +from google.api_core import operation # type: ignore +from google.api_core import operation_async # type: ignore +from google.cloud.dialogflowcx_v3.services.test_cases import pagers +from google.cloud.dialogflowcx_v3.types import test_case +from google.cloud.dialogflowcx_v3.types import test_case as gcdc_test_case +from google.protobuf import field_mask_pb2 as field_mask # type: ignore +from google.protobuf import timestamp_pb2 as timestamp # type: ignore + +from .transports.base import TestCasesTransport, DEFAULT_CLIENT_INFO +from .transports.grpc import TestCasesGrpcTransport +from .transports.grpc_asyncio import TestCasesGrpcAsyncIOTransport + + +class TestCasesClientMeta(type): + """Metaclass for the TestCases client. + + This provides class-level methods for building and retrieving + support objects (e.g. transport) without polluting the client instance + objects. + """ + + _transport_registry = OrderedDict() # type: Dict[str, Type[TestCasesTransport]] + _transport_registry["grpc"] = TestCasesGrpcTransport + _transport_registry["grpc_asyncio"] = TestCasesGrpcAsyncIOTransport + + def get_transport_class(cls, label: str = None,) -> Type[TestCasesTransport]: + """Return an appropriate transport class. + + Args: + label: The name of the desired transport. If none is + provided, then the first transport in the registry is used. + + Returns: + The transport class to use. + """ + # If a specific transport is requested, return that one. + if label: + return cls._transport_registry[label] + + # No transport is requested; return the default (that is, the first one + # in the dictionary). + return next(iter(cls._transport_registry.values())) + + +class TestCasesClient(metaclass=TestCasesClientMeta): + """Service for managing [Test + Cases][google.cloud.dialogflow.cx.v3.TestCase] and [Test Case + Results][google.cloud.dialogflow.cx.v3.TestCaseResult]. + """ + + @staticmethod + def _get_default_mtls_endpoint(api_endpoint): + """Convert api endpoint to mTLS endpoint. + Convert "*.sandbox.googleapis.com" and "*.googleapis.com" to + "*.mtls.sandbox.googleapis.com" and "*.mtls.googleapis.com" respectively. + Args: + api_endpoint (Optional[str]): the api endpoint to convert. + Returns: + str: converted mTLS api endpoint. + """ + if not api_endpoint: + return api_endpoint + + mtls_endpoint_re = re.compile( + r"(?P[^.]+)(?P\.mtls)?(?P\.sandbox)?(?P\.googleapis\.com)?" + ) + + m = mtls_endpoint_re.match(api_endpoint) + name, mtls, sandbox, googledomain = m.groups() + if mtls or not googledomain: + return api_endpoint + + if sandbox: + return api_endpoint.replace( + "sandbox.googleapis.com", "mtls.sandbox.googleapis.com" + ) + + return api_endpoint.replace(".googleapis.com", ".mtls.googleapis.com") + + DEFAULT_ENDPOINT = "dialogflow.googleapis.com" + DEFAULT_MTLS_ENDPOINT = _get_default_mtls_endpoint.__func__( # type: ignore + DEFAULT_ENDPOINT + ) + + @classmethod + def from_service_account_info(cls, info: dict, *args, **kwargs): + """Creates an instance of this client using the provided credentials info. + + Args: + info (dict): The service account private key info. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + TestCasesClient: The constructed client. + """ + credentials = service_account.Credentials.from_service_account_info(info) + kwargs["credentials"] = credentials + return cls(*args, **kwargs) + + @classmethod + def from_service_account_file(cls, filename: str, *args, **kwargs): + """Creates an instance of this client using the provided credentials + file. + + Args: + filename (str): The path to the service account private key json + file. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + TestCasesClient: The constructed client. + """ + credentials = service_account.Credentials.from_service_account_file(filename) + kwargs["credentials"] = credentials + return cls(*args, **kwargs) + + from_service_account_json = from_service_account_file + + @property + def transport(self) -> TestCasesTransport: + """Return the transport used by the client instance. + + Returns: + TestCasesTransport: The transport used by the client instance. + """ + return self._transport + + @staticmethod + def agent_path(project: str, location: str, agent: str,) -> str: + """Return a fully-qualified agent string.""" + return "projects/{project}/locations/{location}/agents/{agent}".format( + project=project, location=location, agent=agent, + ) + + @staticmethod + def parse_agent_path(path: str) -> Dict[str, str]: + """Parse a agent path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/locations/(?P.+?)/agents/(?P.+?)$", + path, + ) + return m.groupdict() if m else {} + + @staticmethod + def entity_type_path( + project: str, location: str, agent: str, entity_type: str, + ) -> str: + """Return a fully-qualified entity_type string.""" + return "projects/{project}/locations/{location}/agents/{agent}/entityTypes/{entity_type}".format( + project=project, location=location, agent=agent, entity_type=entity_type, + ) + + @staticmethod + def parse_entity_type_path(path: str) -> Dict[str, str]: + """Parse a entity_type path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/locations/(?P.+?)/agents/(?P.+?)/entityTypes/(?P.+?)$", + path, + ) + return m.groupdict() if m else {} + + @staticmethod + def environment_path( + project: str, location: str, agent: str, environment: str, + ) -> str: + """Return a fully-qualified environment string.""" + return "projects/{project}/locations/{location}/agents/{agent}/environments/{environment}".format( + project=project, location=location, agent=agent, environment=environment, + ) + + @staticmethod + def parse_environment_path(path: str) -> Dict[str, str]: + """Parse a environment path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/locations/(?P.+?)/agents/(?P.+?)/environments/(?P.+?)$", + path, + ) + return m.groupdict() if m else {} + + @staticmethod + def flow_path(project: str, location: str, agent: str, flow: str,) -> str: + """Return a fully-qualified flow string.""" + return "projects/{project}/locations/{location}/agents/{agent}/flows/{flow}".format( + project=project, location=location, agent=agent, flow=flow, + ) + + @staticmethod + def parse_flow_path(path: str) -> Dict[str, str]: + """Parse a flow path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/locations/(?P.+?)/agents/(?P.+?)/flows/(?P.+?)$", + path, + ) + return m.groupdict() if m else {} + + @staticmethod + def intent_path(project: str, location: str, agent: str, intent: str,) -> str: + """Return a fully-qualified intent string.""" + return "projects/{project}/locations/{location}/agents/{agent}/intents/{intent}".format( + project=project, location=location, agent=agent, intent=intent, + ) + + @staticmethod + def parse_intent_path(path: str) -> Dict[str, str]: + """Parse a intent path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/locations/(?P.+?)/agents/(?P.+?)/intents/(?P.+?)$", + path, + ) + return m.groupdict() if m else {} + + @staticmethod + def page_path( + project: str, location: str, agent: str, flow: str, page: str, + ) -> str: + """Return a fully-qualified page string.""" + return "projects/{project}/locations/{location}/agents/{agent}/flows/{flow}/pages/{page}".format( + project=project, location=location, agent=agent, flow=flow, page=page, + ) + + @staticmethod + def parse_page_path(path: str) -> Dict[str, str]: + """Parse a page path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/locations/(?P.+?)/agents/(?P.+?)/flows/(?P.+?)/pages/(?P.+?)$", + path, + ) + return m.groupdict() if m else {} + + @staticmethod + def test_case_path(project: str, location: str, agent: str, test_case: str,) -> str: + """Return a fully-qualified test_case string.""" + return "projects/{project}/locations/{location}/agents/{agent}/testCases/{test_case}".format( + project=project, location=location, agent=agent, test_case=test_case, + ) + + @staticmethod + def parse_test_case_path(path: str) -> Dict[str, str]: + """Parse a test_case path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/locations/(?P.+?)/agents/(?P.+?)/testCases/(?P.+?)$", + path, + ) + return m.groupdict() if m else {} + + @staticmethod + def test_case_result_path( + project: str, location: str, agent: str, test_case: str, result: str, + ) -> str: + """Return a fully-qualified test_case_result string.""" + return "projects/{project}/locations/{location}/agents/{agent}/testCases/{test_case}/results/{result}".format( + project=project, + location=location, + agent=agent, + test_case=test_case, + result=result, + ) + + @staticmethod + def parse_test_case_result_path(path: str) -> Dict[str, str]: + """Parse a test_case_result path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/locations/(?P.+?)/agents/(?P.+?)/testCases/(?P.+?)/results/(?P.+?)$", + path, + ) + return m.groupdict() if m else {} + + @staticmethod + def transition_route_group_path( + project: str, location: str, agent: str, flow: str, transition_route_group: str, + ) -> str: + """Return a fully-qualified transition_route_group string.""" + return "projects/{project}/locations/{location}/agents/{agent}/flows/{flow}/transitionRouteGroups/{transition_route_group}".format( + project=project, + location=location, + agent=agent, + flow=flow, + transition_route_group=transition_route_group, + ) + + @staticmethod + def parse_transition_route_group_path(path: str) -> Dict[str, str]: + """Parse a transition_route_group path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/locations/(?P.+?)/agents/(?P.+?)/flows/(?P.+?)/transitionRouteGroups/(?P.+?)$", + path, + ) + return m.groupdict() if m else {} + + @staticmethod + def webhook_path(project: str, location: str, agent: str, webhook: str,) -> str: + """Return a fully-qualified webhook string.""" + return "projects/{project}/locations/{location}/agents/{agent}/webhooks/{webhook}".format( + project=project, location=location, agent=agent, webhook=webhook, + ) + + @staticmethod + def parse_webhook_path(path: str) -> Dict[str, str]: + """Parse a webhook path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/locations/(?P.+?)/agents/(?P.+?)/webhooks/(?P.+?)$", + path, + ) + return m.groupdict() if m else {} + + @staticmethod + def common_billing_account_path(billing_account: str,) -> str: + """Return a fully-qualified billing_account string.""" + return "billingAccounts/{billing_account}".format( + billing_account=billing_account, + ) + + @staticmethod + def parse_common_billing_account_path(path: str) -> Dict[str, str]: + """Parse a billing_account path into its component segments.""" + m = re.match(r"^billingAccounts/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_folder_path(folder: str,) -> str: + """Return a fully-qualified folder string.""" + return "folders/{folder}".format(folder=folder,) + + @staticmethod + def parse_common_folder_path(path: str) -> Dict[str, str]: + """Parse a folder path into its component segments.""" + m = re.match(r"^folders/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_organization_path(organization: str,) -> str: + """Return a fully-qualified organization string.""" + return "organizations/{organization}".format(organization=organization,) + + @staticmethod + def parse_common_organization_path(path: str) -> Dict[str, str]: + """Parse a organization path into its component segments.""" + m = re.match(r"^organizations/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_project_path(project: str,) -> str: + """Return a fully-qualified project string.""" + return "projects/{project}".format(project=project,) + + @staticmethod + def parse_common_project_path(path: str) -> Dict[str, str]: + """Parse a project path into its component segments.""" + m = re.match(r"^projects/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_location_path(project: str, location: str,) -> str: + """Return a fully-qualified location string.""" + return "projects/{project}/locations/{location}".format( + project=project, location=location, + ) + + @staticmethod + def parse_common_location_path(path: str) -> Dict[str, str]: + """Parse a location path into its component segments.""" + m = re.match(r"^projects/(?P.+?)/locations/(?P.+?)$", path) + return m.groupdict() if m else {} + + def __init__( + self, + *, + credentials: Optional[credentials.Credentials] = None, + transport: Union[str, TestCasesTransport, None] = None, + client_options: Optional[client_options_lib.ClientOptions] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + ) -> None: + """Instantiate the test cases client. + + Args: + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + transport (Union[str, TestCasesTransport]): The + transport to use. If set to None, a transport is chosen + automatically. + client_options (google.api_core.client_options.ClientOptions): Custom options for the + client. It won't take effect if a ``transport`` instance is provided. + (1) The ``api_endpoint`` property can be used to override the + default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT + environment variable can also be used to override the endpoint: + "always" (always use the default mTLS endpoint), "never" (always + use the default regular endpoint) and "auto" (auto switch to the + default mTLS endpoint if client certificate is present, this is + the default value). However, the ``api_endpoint`` property takes + precedence if provided. + (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable + is "true", then the ``client_cert_source`` property can be used + to provide client certificate for mutual TLS transport. If + not provided, the default SSL client certificate will be used if + present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not + set, no client certificate will be used. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport + creation failed for any reason. + """ + if isinstance(client_options, dict): + client_options = client_options_lib.from_dict(client_options) + if client_options is None: + client_options = client_options_lib.ClientOptions() + + # Create SSL credentials for mutual TLS if needed. + use_client_cert = bool( + util.strtobool(os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false")) + ) + + client_cert_source_func = None + is_mtls = False + if use_client_cert: + if client_options.client_cert_source: + is_mtls = True + client_cert_source_func = client_options.client_cert_source + else: + 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: + api_endpoint = client_options.api_endpoint + else: + use_mtls_env = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto") + if use_mtls_env == "never": + api_endpoint = self.DEFAULT_ENDPOINT + elif use_mtls_env == "always": + api_endpoint = self.DEFAULT_MTLS_ENDPOINT + elif use_mtls_env == "auto": + api_endpoint = ( + self.DEFAULT_MTLS_ENDPOINT if is_mtls else self.DEFAULT_ENDPOINT + ) + else: + raise MutualTLSChannelError( + "Unsupported GOOGLE_API_USE_MTLS_ENDPOINT value. Accepted values: never, auto, always" + ) + + # Save or instantiate the transport. + # Ordinarily, we provide the transport, but allowing a custom transport + # instance provides an extensibility point for unusual situations. + if isinstance(transport, TestCasesTransport): + # transport is a TestCasesTransport instance. + if credentials or client_options.credentials_file: + raise ValueError( + "When providing a transport instance, " + "provide its credentials directly." + ) + if client_options.scopes: + raise ValueError( + "When providing a transport instance, " + "provide its scopes directly." + ) + self._transport = transport + else: + Transport = type(self).get_transport_class(transport) + self._transport = Transport( + credentials=credentials, + credentials_file=client_options.credentials_file, + host=api_endpoint, + scopes=client_options.scopes, + client_cert_source_for_mtls=client_cert_source_func, + quota_project_id=client_options.quota_project_id, + client_info=client_info, + ) + + def list_test_cases( + self, + request: test_case.ListTestCasesRequest = None, + *, + parent: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListTestCasesPager: + r"""Fetches a list of test cases for a given agent. + + Args: + request (google.cloud.dialogflowcx_v3.types.ListTestCasesRequest): + The request object. The request message for + [TestCases.ListTestCases][google.cloud.dialogflow.cx.v3.TestCases.ListTestCases]. + parent (str): + Required. The agent to list all pages for. Format: + ``projects//locations//agents/``. + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.dialogflowcx_v3.services.test_cases.pagers.ListTestCasesPager: + The response message for + [TestCases.ListTestCases][google.cloud.dialogflow.cx.v3.TestCases.ListTestCases]. + + Iterating over this object will yield results and + resolve additional pages automatically. + + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([parent]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a test_case.ListTestCasesRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, test_case.ListTestCasesRequest): + request = test_case.ListTestCasesRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + + if parent is not None: + request.parent = parent + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.list_test_cases] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # This method is paged; wrap the response in a pager, which provides + # an `__iter__` convenience method. + response = pagers.ListTestCasesPager( + method=rpc, request=request, response=response, metadata=metadata, + ) + + # Done; return the response. + return response + + def batch_delete_test_cases( + self, + request: test_case.BatchDeleteTestCasesRequest = None, + *, + parent: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + r"""Batch deletes test cases. + + Args: + request (google.cloud.dialogflowcx_v3.types.BatchDeleteTestCasesRequest): + The request object. The request message for + [TestCases.BatchDeleteTestCases][google.cloud.dialogflow.cx.v3.TestCases.BatchDeleteTestCases]. + parent (str): + Required. The agent to delete test cases from. Format: + ``projects//locations//agents/``. + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([parent]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a test_case.BatchDeleteTestCasesRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, test_case.BatchDeleteTestCasesRequest): + request = test_case.BatchDeleteTestCasesRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + + if parent is not None: + request.parent = parent + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.batch_delete_test_cases] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + rpc( + request, retry=retry, timeout=timeout, metadata=metadata, + ) + + def get_test_case( + self, + request: test_case.GetTestCaseRequest = None, + *, + name: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> test_case.TestCase: + r"""Gets a test case. + + Args: + request (google.cloud.dialogflowcx_v3.types.GetTestCaseRequest): + The request object. The request message for + [TestCases.GetTestCase][google.cloud.dialogflow.cx.v3.TestCases.GetTestCase]. + name (str): + Required. The name of the testcase. Format: + ``projects//locations//agents//testCases/``. + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.dialogflowcx_v3.types.TestCase: + Represents a test case. + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a test_case.GetTestCaseRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, test_case.GetTestCaseRequest): + request = test_case.GetTestCaseRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.get_test_case] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + + def create_test_case( + self, + request: gcdc_test_case.CreateTestCaseRequest = None, + *, + parent: str = None, + test_case: gcdc_test_case.TestCase = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_test_case.TestCase: + r"""Creates a test case for the given agent. + + Args: + request (google.cloud.dialogflowcx_v3.types.CreateTestCaseRequest): + The request object. The request message for + [TestCases.CreateTestCase][google.cloud.dialogflow.cx.v3.TestCases.CreateTestCase]. + parent (str): + Required. The agent to create the test case for. Format: + ``projects//locations//agents/``. + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + test_case (google.cloud.dialogflowcx_v3.types.TestCase): + Required. The test case to create. + This corresponds to the ``test_case`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.dialogflowcx_v3.types.TestCase: + Represents a test case. + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([parent, test_case]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a gcdc_test_case.CreateTestCaseRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, gcdc_test_case.CreateTestCaseRequest): + request = gcdc_test_case.CreateTestCaseRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + + if parent is not None: + request.parent = parent + if test_case is not None: + request.test_case = test_case + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.create_test_case] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + + def update_test_case( + self, + request: gcdc_test_case.UpdateTestCaseRequest = None, + *, + test_case: gcdc_test_case.TestCase = None, + update_mask: field_mask.FieldMask = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_test_case.TestCase: + r"""Updates the specified test case. + + Args: + request (google.cloud.dialogflowcx_v3.types.UpdateTestCaseRequest): + The request object. The request message for + [TestCases.UpdateTestCase][google.cloud.dialogflow.cx.v3.TestCases.UpdateTestCase]. + test_case (google.cloud.dialogflowcx_v3.types.TestCase): + Required. The test case to update. + This corresponds to the ``test_case`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + update_mask (google.protobuf.field_mask_pb2.FieldMask): + Required. The mask to specify which fields should be + updated. The + [``creationTime``][google.cloud.dialogflow.cx.v3.TestCase.creation_time] + and + [``lastTestResult``][google.cloud.dialogflow.cx.v3.TestCase.last_test_result] + cannot be updated. + + This corresponds to the ``update_mask`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.dialogflowcx_v3.types.TestCase: + Represents a test case. + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([test_case, update_mask]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a gcdc_test_case.UpdateTestCaseRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, gcdc_test_case.UpdateTestCaseRequest): + request = gcdc_test_case.UpdateTestCaseRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + + if test_case is not None: + request.test_case = test_case + if update_mask is not None: + request.update_mask = update_mask + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.update_test_case] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("test_case.name", request.test_case.name),) + ), + ) + + # Send the request. + response = rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + + def run_test_case( + self, + request: test_case.RunTestCaseRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operation.Operation: + r"""Kicks off a test case run. + + Args: + request (google.cloud.dialogflowcx_v3.types.RunTestCaseRequest): + The request object. The request message for + [TestCases.RunTestCase][google.cloud.dialogflow.cx.v3.TestCases.RunTestCase]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.api_core.operation.Operation: + An object representing a long-running operation. + + The result type for the operation will be + :class:`google.cloud.dialogflowcx_v3.types.RunTestCaseResponse` + The response message for + [TestCases.RunTestCase][google.cloud.dialogflow.cx.v3.TestCases.RunTestCase]. + + """ + # Create or coerce a protobuf request object. + + # Minor optimization to avoid making a copy if the user passes + # in a test_case.RunTestCaseRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, test_case.RunTestCaseRequest): + request = test_case.RunTestCaseRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.run_test_case] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Wrap the response in an operation future. + response = operation.from_gapic( + response, + self._transport.operations_client, + test_case.RunTestCaseResponse, + metadata_type=test_case.RunTestCaseMetadata, + ) + + # Done; return the response. + return response + + def batch_run_test_cases( + self, + request: test_case.BatchRunTestCasesRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operation.Operation: + r"""Kicks off a batch run of test cases. + + Args: + request (google.cloud.dialogflowcx_v3.types.BatchRunTestCasesRequest): + The request object. The request message for + [TestCases.BatchRunTestCases][google.cloud.dialogflow.cx.v3.TestCases.BatchRunTestCases]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.api_core.operation.Operation: + An object representing a long-running operation. + + The result type for the operation will be + :class:`google.cloud.dialogflowcx_v3.types.BatchRunTestCasesResponse` + The response message for + [TestCases.BatchRunTestCases][google.cloud.dialogflow.cx.v3.TestCases.BatchRunTestCases]. + + """ + # Create or coerce a protobuf request object. + + # Minor optimization to avoid making a copy if the user passes + # in a test_case.BatchRunTestCasesRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, test_case.BatchRunTestCasesRequest): + request = test_case.BatchRunTestCasesRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.batch_run_test_cases] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Wrap the response in an operation future. + response = operation.from_gapic( + response, + self._transport.operations_client, + test_case.BatchRunTestCasesResponse, + metadata_type=test_case.BatchRunTestCasesMetadata, + ) + + # Done; return the response. + return response + + def calculate_coverage( + self, + request: test_case.CalculateCoverageRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> test_case.CalculateCoverageResponse: + r"""Calculates the test coverage for an agent. + + Args: + request (google.cloud.dialogflowcx_v3.types.CalculateCoverageRequest): + The request object. The request message for + [TestCases.CalculateCoverage][google.cloud.dialogflow.cx.v3.TestCases.CalculateCoverage]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.dialogflowcx_v3.types.CalculateCoverageResponse: + The response message for + [TestCases.CalculateCoverage][google.cloud.dialogflow.cx.v3.TestCases.CalculateCoverage]. + + """ + # Create or coerce a protobuf request object. + + # Minor optimization to avoid making a copy if the user passes + # in a test_case.CalculateCoverageRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, test_case.CalculateCoverageRequest): + request = test_case.CalculateCoverageRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.calculate_coverage] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("agent", request.agent),)), + ) + + # Send the request. + response = rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + + def import_test_cases( + self, + request: test_case.ImportTestCasesRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operation.Operation: + r"""Imports the test cases from a Cloud Storage bucket or + a local file. It always creates new test cases and won't + overwite any existing ones. The provided ID in the + imported test case is neglected. + + Args: + request (google.cloud.dialogflowcx_v3.types.ImportTestCasesRequest): + The request object. The request message for + [TestCases.ImportTestCases][google.cloud.dialogflow.cx.v3.TestCases.ImportTestCases]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.api_core.operation.Operation: + An object representing a long-running operation. + + The result type for the operation will be + :class:`google.cloud.dialogflowcx_v3.types.ImportTestCasesResponse` + The response message for + [TestCases.ImportTestCases][google.cloud.dialogflow.cx.v3.TestCases.ImportTestCases]. + + """ + # Create or coerce a protobuf request object. + + # Minor optimization to avoid making a copy if the user passes + # in a test_case.ImportTestCasesRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, test_case.ImportTestCasesRequest): + request = test_case.ImportTestCasesRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.import_test_cases] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Wrap the response in an operation future. + response = operation.from_gapic( + response, + self._transport.operations_client, + test_case.ImportTestCasesResponse, + metadata_type=test_case.ImportTestCasesMetadata, + ) + + # Done; return the response. + return response + + def export_test_cases( + self, + request: test_case.ExportTestCasesRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operation.Operation: + r"""Exports the test cases under the agent to a Cloud + Storage bucket or a local file. Filter can be applied to + export a subset of test cases. + + Args: + request (google.cloud.dialogflowcx_v3.types.ExportTestCasesRequest): + The request object. The request message for + [TestCases.ExportTestCases][google.cloud.dialogflow.cx.v3.TestCases.ExportTestCases]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.api_core.operation.Operation: + An object representing a long-running operation. + + The result type for the operation will be + :class:`google.cloud.dialogflowcx_v3.types.ExportTestCasesResponse` + The response message for + [TestCases.ExportTestCases][google.cloud.dialogflow.cx.v3.TestCases.ExportTestCases]. + + """ + # Create or coerce a protobuf request object. + + # Minor optimization to avoid making a copy if the user passes + # in a test_case.ExportTestCasesRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, test_case.ExportTestCasesRequest): + request = test_case.ExportTestCasesRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.export_test_cases] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Wrap the response in an operation future. + response = operation.from_gapic( + response, + self._transport.operations_client, + test_case.ExportTestCasesResponse, + metadata_type=test_case.ExportTestCasesMetadata, + ) + + # Done; return the response. + return response + + def list_test_case_results( + self, + request: test_case.ListTestCaseResultsRequest = None, + *, + parent: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListTestCaseResultsPager: + r"""Fetches a list of results for a given test case. + + Args: + request (google.cloud.dialogflowcx_v3.types.ListTestCaseResultsRequest): + The request object. The request message for + [TestCases.ListTestCaseResults][google.cloud.dialogflow.cx.v3.TestCases.ListTestCaseResults]. + parent (str): + Required. The test case to list results for. Format: + ``projects//locations//agents// testCases/``. + Specify a ``-`` as a wildcard for TestCase ID to list + results across multiple test cases. + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.dialogflowcx_v3.services.test_cases.pagers.ListTestCaseResultsPager: + The response message for + [TestCases.ListTestCaseResults][google.cloud.dialogflow.cx.v3.TestCases.ListTestCaseResults]. + + Iterating over this object will yield results and + resolve additional pages automatically. + + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([parent]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a test_case.ListTestCaseResultsRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, test_case.ListTestCaseResultsRequest): + request = test_case.ListTestCaseResultsRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + + if parent is not None: + request.parent = parent + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.list_test_case_results] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # This method is paged; wrap the response in a pager, which provides + # an `__iter__` convenience method. + response = pagers.ListTestCaseResultsPager( + method=rpc, request=request, response=response, metadata=metadata, + ) + + # Done; return the response. + return response + + +try: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=pkg_resources.get_distribution( + "google-cloud-dialogflowcx", + ).version, + ) +except pkg_resources.DistributionNotFound: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() + + +__all__ = ("TestCasesClient",) diff --git a/google/cloud/dialogflowcx_v3/services/test_cases/pagers.py b/google/cloud/dialogflowcx_v3/services/test_cases/pagers.py new file mode 100644 index 00000000..e037052a --- /dev/null +++ b/google/cloud/dialogflowcx_v3/services/test_cases/pagers.py @@ -0,0 +1,285 @@ +# -*- 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. +# + +from typing import ( + Any, + AsyncIterable, + Awaitable, + Callable, + Iterable, + Sequence, + Tuple, + Optional, +) + +from google.cloud.dialogflowcx_v3.types import test_case + + +class ListTestCasesPager: + """A pager for iterating through ``list_test_cases`` requests. + + This class thinly wraps an initial + :class:`google.cloud.dialogflowcx_v3.types.ListTestCasesResponse` object, and + provides an ``__iter__`` method to iterate through its + ``test_cases`` field. + + If there are more pages, the ``__iter__`` method will make additional + ``ListTestCases`` requests and continue to iterate + through the ``test_cases`` field on the + corresponding responses. + + All the usual :class:`google.cloud.dialogflowcx_v3.types.ListTestCasesResponse` + attributes are available on the pager. If multiple requests are made, only + the most recent response is retained, and thus used for attribute lookup. + """ + + def __init__( + self, + method: Callable[..., test_case.ListTestCasesResponse], + request: test_case.ListTestCasesRequest, + response: test_case.ListTestCasesResponse, + *, + metadata: Sequence[Tuple[str, str]] = () + ): + """Instantiate the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.cloud.dialogflowcx_v3.types.ListTestCasesRequest): + The initial request object. + response (google.cloud.dialogflowcx_v3.types.ListTestCasesResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = test_case.ListTestCasesRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + def pages(self) -> Iterable[test_case.ListTestCasesResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = self._method(self._request, metadata=self._metadata) + yield self._response + + def __iter__(self) -> Iterable[test_case.TestCase]: + for page in self.pages: + yield from page.test_cases + + def __repr__(self) -> str: + return "{0}<{1!r}>".format(self.__class__.__name__, self._response) + + +class ListTestCasesAsyncPager: + """A pager for iterating through ``list_test_cases`` requests. + + This class thinly wraps an initial + :class:`google.cloud.dialogflowcx_v3.types.ListTestCasesResponse` object, and + provides an ``__aiter__`` method to iterate through its + ``test_cases`` field. + + If there are more pages, the ``__aiter__`` method will make additional + ``ListTestCases`` requests and continue to iterate + through the ``test_cases`` field on the + corresponding responses. + + All the usual :class:`google.cloud.dialogflowcx_v3.types.ListTestCasesResponse` + attributes are available on the pager. If multiple requests are made, only + the most recent response is retained, and thus used for attribute lookup. + """ + + def __init__( + self, + method: Callable[..., Awaitable[test_case.ListTestCasesResponse]], + request: test_case.ListTestCasesRequest, + response: test_case.ListTestCasesResponse, + *, + metadata: Sequence[Tuple[str, str]] = () + ): + """Instantiate the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.cloud.dialogflowcx_v3.types.ListTestCasesRequest): + The initial request object. + response (google.cloud.dialogflowcx_v3.types.ListTestCasesResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = test_case.ListTestCasesRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + async def pages(self) -> AsyncIterable[test_case.ListTestCasesResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = await self._method(self._request, metadata=self._metadata) + yield self._response + + def __aiter__(self) -> AsyncIterable[test_case.TestCase]: + async def async_generator(): + async for page in self.pages: + for response in page.test_cases: + yield response + + return async_generator() + + def __repr__(self) -> str: + return "{0}<{1!r}>".format(self.__class__.__name__, self._response) + + +class ListTestCaseResultsPager: + """A pager for iterating through ``list_test_case_results`` requests. + + This class thinly wraps an initial + :class:`google.cloud.dialogflowcx_v3.types.ListTestCaseResultsResponse` object, and + provides an ``__iter__`` method to iterate through its + ``test_case_results`` field. + + If there are more pages, the ``__iter__`` method will make additional + ``ListTestCaseResults`` requests and continue to iterate + through the ``test_case_results`` field on the + corresponding responses. + + All the usual :class:`google.cloud.dialogflowcx_v3.types.ListTestCaseResultsResponse` + attributes are available on the pager. If multiple requests are made, only + the most recent response is retained, and thus used for attribute lookup. + """ + + def __init__( + self, + method: Callable[..., test_case.ListTestCaseResultsResponse], + request: test_case.ListTestCaseResultsRequest, + response: test_case.ListTestCaseResultsResponse, + *, + metadata: Sequence[Tuple[str, str]] = () + ): + """Instantiate the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.cloud.dialogflowcx_v3.types.ListTestCaseResultsRequest): + The initial request object. + response (google.cloud.dialogflowcx_v3.types.ListTestCaseResultsResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = test_case.ListTestCaseResultsRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + def pages(self) -> Iterable[test_case.ListTestCaseResultsResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = self._method(self._request, metadata=self._metadata) + yield self._response + + def __iter__(self) -> Iterable[test_case.TestCaseResult]: + for page in self.pages: + yield from page.test_case_results + + def __repr__(self) -> str: + return "{0}<{1!r}>".format(self.__class__.__name__, self._response) + + +class ListTestCaseResultsAsyncPager: + """A pager for iterating through ``list_test_case_results`` requests. + + This class thinly wraps an initial + :class:`google.cloud.dialogflowcx_v3.types.ListTestCaseResultsResponse` object, and + provides an ``__aiter__`` method to iterate through its + ``test_case_results`` field. + + If there are more pages, the ``__aiter__`` method will make additional + ``ListTestCaseResults`` requests and continue to iterate + through the ``test_case_results`` field on the + corresponding responses. + + All the usual :class:`google.cloud.dialogflowcx_v3.types.ListTestCaseResultsResponse` + attributes are available on the pager. If multiple requests are made, only + the most recent response is retained, and thus used for attribute lookup. + """ + + def __init__( + self, + method: Callable[..., Awaitable[test_case.ListTestCaseResultsResponse]], + request: test_case.ListTestCaseResultsRequest, + response: test_case.ListTestCaseResultsResponse, + *, + metadata: Sequence[Tuple[str, str]] = () + ): + """Instantiate the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.cloud.dialogflowcx_v3.types.ListTestCaseResultsRequest): + The initial request object. + response (google.cloud.dialogflowcx_v3.types.ListTestCaseResultsResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = test_case.ListTestCaseResultsRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + async def pages(self) -> AsyncIterable[test_case.ListTestCaseResultsResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = await self._method(self._request, metadata=self._metadata) + yield self._response + + def __aiter__(self) -> AsyncIterable[test_case.TestCaseResult]: + async def async_generator(): + async for page in self.pages: + for response in page.test_case_results: + yield response + + return async_generator() + + def __repr__(self) -> str: + return "{0}<{1!r}>".format(self.__class__.__name__, self._response) diff --git a/google/cloud/dialogflowcx_v3/services/test_cases/transports/__init__.py b/google/cloud/dialogflowcx_v3/services/test_cases/transports/__init__.py new file mode 100644 index 00000000..0c356952 --- /dev/null +++ b/google/cloud/dialogflowcx_v3/services/test_cases/transports/__init__.py @@ -0,0 +1,35 @@ +# -*- 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. +# + +from collections import OrderedDict +from typing import Dict, Type + +from .base import TestCasesTransport +from .grpc import TestCasesGrpcTransport +from .grpc_asyncio import TestCasesGrpcAsyncIOTransport + + +# Compile a registry of transports. +_transport_registry = OrderedDict() # type: Dict[str, Type[TestCasesTransport]] +_transport_registry["grpc"] = TestCasesGrpcTransport +_transport_registry["grpc_asyncio"] = TestCasesGrpcAsyncIOTransport + +__all__ = ( + "TestCasesTransport", + "TestCasesGrpcTransport", + "TestCasesGrpcAsyncIOTransport", +) diff --git a/google/cloud/dialogflowcx_v3/services/test_cases/transports/base.py b/google/cloud/dialogflowcx_v3/services/test_cases/transports/base.py new file mode 100644 index 00000000..a4b8f4e6 --- /dev/null +++ b/google/cloud/dialogflowcx_v3/services/test_cases/transports/base.py @@ -0,0 +1,275 @@ +# -*- 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. +# + +import abc +import typing +import pkg_resources + +from google import auth # type: ignore +from google.api_core import exceptions # type: ignore +from google.api_core import gapic_v1 # type: ignore +from google.api_core import retry as retries # type: ignore +from google.api_core import operations_v1 # type: ignore +from google.auth import credentials # type: ignore + +from google.cloud.dialogflowcx_v3.types import test_case +from google.cloud.dialogflowcx_v3.types import test_case as gcdc_test_case +from google.longrunning import operations_pb2 as operations # type: ignore +from google.protobuf import empty_pb2 as empty # type: ignore + + +try: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=pkg_resources.get_distribution( + "google-cloud-dialogflowcx", + ).version, + ) +except pkg_resources.DistributionNotFound: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() + + +class TestCasesTransport(abc.ABC): + """Abstract transport class for TestCases.""" + + AUTH_SCOPES = ( + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/dialogflow", + ) + + def __init__( + self, + *, + host: str = "dialogflow.googleapis.com", + credentials: credentials.Credentials = None, + credentials_file: typing.Optional[str] = None, + scopes: typing.Optional[typing.Sequence[str]] = AUTH_SCOPES, + quota_project_id: typing.Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + **kwargs, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is mutually exclusive with credentials. + 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 + your own client library. + """ + # Save the hostname. Default to port 443 (HTTPS) if none is specified. + if ":" not in host: + host += ":443" + self._host = host + + # If no credentials are provided, then determine the appropriate + # defaults. + if credentials and credentials_file: + raise exceptions.DuplicateCredentialArgs( + "'credentials_file' and 'credentials' are mutually exclusive" + ) + + if credentials_file is not None: + credentials, _ = auth.load_credentials_from_file( + credentials_file, scopes=scopes, quota_project_id=quota_project_id + ) + + elif credentials is None: + credentials, _ = auth.default( + scopes=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 = { + self.list_test_cases: gapic_v1.method.wrap_method( + self.list_test_cases, default_timeout=None, client_info=client_info, + ), + self.batch_delete_test_cases: gapic_v1.method.wrap_method( + self.batch_delete_test_cases, + default_timeout=None, + client_info=client_info, + ), + self.get_test_case: gapic_v1.method.wrap_method( + self.get_test_case, default_timeout=None, client_info=client_info, + ), + self.create_test_case: gapic_v1.method.wrap_method( + self.create_test_case, default_timeout=None, client_info=client_info, + ), + self.update_test_case: gapic_v1.method.wrap_method( + self.update_test_case, default_timeout=None, client_info=client_info, + ), + self.run_test_case: gapic_v1.method.wrap_method( + self.run_test_case, default_timeout=None, client_info=client_info, + ), + self.batch_run_test_cases: gapic_v1.method.wrap_method( + self.batch_run_test_cases, + default_timeout=None, + client_info=client_info, + ), + self.calculate_coverage: gapic_v1.method.wrap_method( + self.calculate_coverage, default_timeout=None, client_info=client_info, + ), + self.import_test_cases: gapic_v1.method.wrap_method( + self.import_test_cases, default_timeout=None, client_info=client_info, + ), + self.export_test_cases: gapic_v1.method.wrap_method( + self.export_test_cases, default_timeout=None, client_info=client_info, + ), + self.list_test_case_results: gapic_v1.method.wrap_method( + self.list_test_case_results, + default_timeout=None, + client_info=client_info, + ), + } + + @property + def operations_client(self) -> operations_v1.OperationsClient: + """Return the client designed to process long-running operations.""" + raise NotImplementedError() + + @property + def list_test_cases( + self, + ) -> typing.Callable[ + [test_case.ListTestCasesRequest], + typing.Union[ + test_case.ListTestCasesResponse, + typing.Awaitable[test_case.ListTestCasesResponse], + ], + ]: + raise NotImplementedError() + + @property + def batch_delete_test_cases( + self, + ) -> typing.Callable[ + [test_case.BatchDeleteTestCasesRequest], + typing.Union[empty.Empty, typing.Awaitable[empty.Empty]], + ]: + raise NotImplementedError() + + @property + def get_test_case( + self, + ) -> typing.Callable[ + [test_case.GetTestCaseRequest], + typing.Union[test_case.TestCase, typing.Awaitable[test_case.TestCase]], + ]: + raise NotImplementedError() + + @property + def create_test_case( + self, + ) -> typing.Callable[ + [gcdc_test_case.CreateTestCaseRequest], + typing.Union[ + gcdc_test_case.TestCase, typing.Awaitable[gcdc_test_case.TestCase] + ], + ]: + raise NotImplementedError() + + @property + def update_test_case( + self, + ) -> typing.Callable[ + [gcdc_test_case.UpdateTestCaseRequest], + typing.Union[ + gcdc_test_case.TestCase, typing.Awaitable[gcdc_test_case.TestCase] + ], + ]: + raise NotImplementedError() + + @property + def run_test_case( + self, + ) -> typing.Callable[ + [test_case.RunTestCaseRequest], + typing.Union[operations.Operation, typing.Awaitable[operations.Operation]], + ]: + raise NotImplementedError() + + @property + def batch_run_test_cases( + self, + ) -> typing.Callable[ + [test_case.BatchRunTestCasesRequest], + typing.Union[operations.Operation, typing.Awaitable[operations.Operation]], + ]: + raise NotImplementedError() + + @property + def calculate_coverage( + self, + ) -> typing.Callable[ + [test_case.CalculateCoverageRequest], + typing.Union[ + test_case.CalculateCoverageResponse, + typing.Awaitable[test_case.CalculateCoverageResponse], + ], + ]: + raise NotImplementedError() + + @property + def import_test_cases( + self, + ) -> typing.Callable[ + [test_case.ImportTestCasesRequest], + typing.Union[operations.Operation, typing.Awaitable[operations.Operation]], + ]: + raise NotImplementedError() + + @property + def export_test_cases( + self, + ) -> typing.Callable[ + [test_case.ExportTestCasesRequest], + typing.Union[operations.Operation, typing.Awaitable[operations.Operation]], + ]: + raise NotImplementedError() + + @property + def list_test_case_results( + self, + ) -> typing.Callable[ + [test_case.ListTestCaseResultsRequest], + typing.Union[ + test_case.ListTestCaseResultsResponse, + typing.Awaitable[test_case.ListTestCaseResultsResponse], + ], + ]: + raise NotImplementedError() + + +__all__ = ("TestCasesTransport",) diff --git a/google/cloud/dialogflowcx_v3/services/test_cases/transports/grpc.py b/google/cloud/dialogflowcx_v3/services/test_cases/transports/grpc.py new file mode 100644 index 00000000..a3b40f14 --- /dev/null +++ b/google/cloud/dialogflowcx_v3/services/test_cases/transports/grpc.py @@ -0,0 +1,568 @@ +# -*- 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. +# + +import warnings +from typing import Callable, Dict, Optional, Sequence, Tuple + +from google.api_core import grpc_helpers # type: ignore +from google.api_core import operations_v1 # type: ignore +from google.api_core import gapic_v1 # type: ignore +from google import auth # type: ignore +from google.auth import credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore + +import grpc # type: ignore + +from google.cloud.dialogflowcx_v3.types import test_case +from google.cloud.dialogflowcx_v3.types import test_case as gcdc_test_case +from google.longrunning import operations_pb2 as operations # type: ignore +from google.protobuf import empty_pb2 as empty # type: ignore + +from .base import TestCasesTransport, DEFAULT_CLIENT_INFO + + +class TestCasesGrpcTransport(TestCasesTransport): + """gRPC backend transport for TestCases. + + Service for managing [Test + Cases][google.cloud.dialogflow.cx.v3.TestCase] and [Test Case + Results][google.cloud.dialogflow.cx.v3.TestCaseResult]. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends protocol buffers over the wire using gRPC (which is built on + top of HTTP/2); the ``grpcio`` package must be installed. + """ + + _stubs: Dict[str, Callable] + + def __init__( + self, + *, + host: str = "dialogflow.googleapis.com", + credentials: credentials.Credentials = None, + credentials_file: str = None, + scopes: Sequence[str] = None, + channel: grpc.Channel = None, + api_mtls_endpoint: str = None, + client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, + ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + This argument is ignored if ``channel`` is provided. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + channel (Optional[grpc.Channel]): A ``Channel`` instance through + which to make calls. + api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. + If provided, it overrides the ``host`` argument and tries to create + a mutual TLS channel with client SSL credentials from + ``client_cert_source`` or applicatin default SSL credentials. + client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): + Deprecated. A callback to provide client SSL certificate bytes and + private key bytes, both in PEM format. It is ignored if + ``api_mtls_endpoint`` is None. + ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials + for 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 + your own client library. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport + creation failed for any reason. + google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` + and ``credentials_file`` are passed. + """ + self._ssl_channel_credentials = ssl_channel_credentials + + 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. + credentials = False + + # If a channel was explicitly provided, set it. + self._grpc_channel = channel + self._ssl_channel_credentials = None + elif api_mtls_endpoint: + 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 + ) + + # 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 credentials is None: + credentials, _ = auth.default( + scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id + ) + + 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=self._ssl_channel_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._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, + ) + + @classmethod + def create_channel( + cls, + host: str = "dialogflow.googleapis.com", + credentials: credentials.Credentials = None, + credentials_file: str = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, + **kwargs, + ) -> grpc.Channel: + """Create and return a gRPC channel object. + Args: + address (Optional[str]): The host for the channel to use. + credentials (Optional[~.Credentials]): The + authorization credentials to attach to requests. These + credentials identify this application to the service. If + none are specified, the client will attempt to ascertain + the credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is mutually exclusive with credentials. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + kwargs (Optional[dict]): Keyword arguments, which are passed to the + channel creation. + Returns: + grpc.Channel: A gRPC channel object. + + Raises: + google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` + and ``credentials_file`` are passed. + """ + scopes = scopes or cls.AUTH_SCOPES + return grpc_helpers.create_channel( + host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + **kwargs, + ) + + @property + def grpc_channel(self) -> grpc.Channel: + """Return the channel designed to connect to this service. + """ + return self._grpc_channel + + @property + def operations_client(self) -> operations_v1.OperationsClient: + """Create the client designed to process long-running operations. + + This property caches on the instance; repeated calls return the same + client. + """ + # Sanity check: Only create a new client if we do not already have one. + if self._operations_client is None: + self._operations_client = operations_v1.OperationsClient(self.grpc_channel) + + # Return the client from cache. + return self._operations_client + + @property + def list_test_cases( + self, + ) -> Callable[[test_case.ListTestCasesRequest], test_case.ListTestCasesResponse]: + r"""Return a callable for the list test cases method over gRPC. + + Fetches a list of test cases for a given agent. + + Returns: + Callable[[~.ListTestCasesRequest], + ~.ListTestCasesResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_test_cases" not in self._stubs: + self._stubs["list_test_cases"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3.TestCases/ListTestCases", + request_serializer=test_case.ListTestCasesRequest.serialize, + response_deserializer=test_case.ListTestCasesResponse.deserialize, + ) + return self._stubs["list_test_cases"] + + @property + def batch_delete_test_cases( + self, + ) -> Callable[[test_case.BatchDeleteTestCasesRequest], empty.Empty]: + r"""Return a callable for the batch delete test cases method over gRPC. + + Batch deletes test cases. + + Returns: + Callable[[~.BatchDeleteTestCasesRequest], + ~.Empty]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "batch_delete_test_cases" not in self._stubs: + self._stubs["batch_delete_test_cases"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3.TestCases/BatchDeleteTestCases", + request_serializer=test_case.BatchDeleteTestCasesRequest.serialize, + response_deserializer=empty.Empty.FromString, + ) + return self._stubs["batch_delete_test_cases"] + + @property + def get_test_case( + self, + ) -> Callable[[test_case.GetTestCaseRequest], test_case.TestCase]: + r"""Return a callable for the get test case method over gRPC. + + Gets a test case. + + Returns: + Callable[[~.GetTestCaseRequest], + ~.TestCase]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_test_case" not in self._stubs: + self._stubs["get_test_case"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3.TestCases/GetTestCase", + request_serializer=test_case.GetTestCaseRequest.serialize, + response_deserializer=test_case.TestCase.deserialize, + ) + return self._stubs["get_test_case"] + + @property + def create_test_case( + self, + ) -> Callable[[gcdc_test_case.CreateTestCaseRequest], gcdc_test_case.TestCase]: + r"""Return a callable for the create test case method over gRPC. + + Creates a test case for the given agent. + + Returns: + Callable[[~.CreateTestCaseRequest], + ~.TestCase]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "create_test_case" not in self._stubs: + self._stubs["create_test_case"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3.TestCases/CreateTestCase", + request_serializer=gcdc_test_case.CreateTestCaseRequest.serialize, + response_deserializer=gcdc_test_case.TestCase.deserialize, + ) + return self._stubs["create_test_case"] + + @property + def update_test_case( + self, + ) -> Callable[[gcdc_test_case.UpdateTestCaseRequest], gcdc_test_case.TestCase]: + r"""Return a callable for the update test case method over gRPC. + + Updates the specified test case. + + Returns: + Callable[[~.UpdateTestCaseRequest], + ~.TestCase]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "update_test_case" not in self._stubs: + self._stubs["update_test_case"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3.TestCases/UpdateTestCase", + request_serializer=gcdc_test_case.UpdateTestCaseRequest.serialize, + response_deserializer=gcdc_test_case.TestCase.deserialize, + ) + return self._stubs["update_test_case"] + + @property + def run_test_case( + self, + ) -> Callable[[test_case.RunTestCaseRequest], operations.Operation]: + r"""Return a callable for the run test case method over gRPC. + + Kicks off a test case run. + + Returns: + Callable[[~.RunTestCaseRequest], + ~.Operation]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "run_test_case" not in self._stubs: + self._stubs["run_test_case"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3.TestCases/RunTestCase", + request_serializer=test_case.RunTestCaseRequest.serialize, + response_deserializer=operations.Operation.FromString, + ) + return self._stubs["run_test_case"] + + @property + def batch_run_test_cases( + self, + ) -> Callable[[test_case.BatchRunTestCasesRequest], operations.Operation]: + r"""Return a callable for the batch run test cases method over gRPC. + + Kicks off a batch run of test cases. + + Returns: + Callable[[~.BatchRunTestCasesRequest], + ~.Operation]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "batch_run_test_cases" not in self._stubs: + self._stubs["batch_run_test_cases"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3.TestCases/BatchRunTestCases", + request_serializer=test_case.BatchRunTestCasesRequest.serialize, + response_deserializer=operations.Operation.FromString, + ) + return self._stubs["batch_run_test_cases"] + + @property + def calculate_coverage( + self, + ) -> Callable[ + [test_case.CalculateCoverageRequest], test_case.CalculateCoverageResponse + ]: + r"""Return a callable for the calculate coverage method over gRPC. + + Calculates the test coverage for an agent. + + Returns: + Callable[[~.CalculateCoverageRequest], + ~.CalculateCoverageResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "calculate_coverage" not in self._stubs: + self._stubs["calculate_coverage"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3.TestCases/CalculateCoverage", + request_serializer=test_case.CalculateCoverageRequest.serialize, + response_deserializer=test_case.CalculateCoverageResponse.deserialize, + ) + return self._stubs["calculate_coverage"] + + @property + def import_test_cases( + self, + ) -> Callable[[test_case.ImportTestCasesRequest], operations.Operation]: + r"""Return a callable for the import test cases method over gRPC. + + Imports the test cases from a Cloud Storage bucket or + a local file. It always creates new test cases and won't + overwite any existing ones. The provided ID in the + imported test case is neglected. + + Returns: + Callable[[~.ImportTestCasesRequest], + ~.Operation]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "import_test_cases" not in self._stubs: + self._stubs["import_test_cases"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3.TestCases/ImportTestCases", + request_serializer=test_case.ImportTestCasesRequest.serialize, + response_deserializer=operations.Operation.FromString, + ) + return self._stubs["import_test_cases"] + + @property + def export_test_cases( + self, + ) -> Callable[[test_case.ExportTestCasesRequest], operations.Operation]: + r"""Return a callable for the export test cases method over gRPC. + + Exports the test cases under the agent to a Cloud + Storage bucket or a local file. Filter can be applied to + export a subset of test cases. + + Returns: + Callable[[~.ExportTestCasesRequest], + ~.Operation]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "export_test_cases" not in self._stubs: + self._stubs["export_test_cases"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3.TestCases/ExportTestCases", + request_serializer=test_case.ExportTestCasesRequest.serialize, + response_deserializer=operations.Operation.FromString, + ) + return self._stubs["export_test_cases"] + + @property + def list_test_case_results( + self, + ) -> Callable[ + [test_case.ListTestCaseResultsRequest], test_case.ListTestCaseResultsResponse + ]: + r"""Return a callable for the list test case results method over gRPC. + + Fetches a list of results for a given test case. + + Returns: + Callable[[~.ListTestCaseResultsRequest], + ~.ListTestCaseResultsResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_test_case_results" not in self._stubs: + self._stubs["list_test_case_results"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3.TestCases/ListTestCaseResults", + request_serializer=test_case.ListTestCaseResultsRequest.serialize, + response_deserializer=test_case.ListTestCaseResultsResponse.deserialize, + ) + return self._stubs["list_test_case_results"] + + +__all__ = ("TestCasesGrpcTransport",) diff --git a/google/cloud/dialogflowcx_v3/services/test_cases/transports/grpc_asyncio.py b/google/cloud/dialogflowcx_v3/services/test_cases/transports/grpc_asyncio.py new file mode 100644 index 00000000..b4e3c9fb --- /dev/null +++ b/google/cloud/dialogflowcx_v3/services/test_cases/transports/grpc_asyncio.py @@ -0,0 +1,584 @@ +# -*- 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. +# + +import warnings +from typing import Awaitable, Callable, Dict, Optional, Sequence, Tuple + +from google.api_core import gapic_v1 # type: ignore +from google.api_core import grpc_helpers_async # type: ignore +from google.api_core import operations_v1 # type: ignore +from google import auth # type: ignore +from google.auth import credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore + +import grpc # type: ignore +from grpc.experimental import aio # type: ignore + +from google.cloud.dialogflowcx_v3.types import test_case +from google.cloud.dialogflowcx_v3.types import test_case as gcdc_test_case +from google.longrunning import operations_pb2 as operations # type: ignore +from google.protobuf import empty_pb2 as empty # type: ignore + +from .base import TestCasesTransport, DEFAULT_CLIENT_INFO +from .grpc import TestCasesGrpcTransport + + +class TestCasesGrpcAsyncIOTransport(TestCasesTransport): + """gRPC AsyncIO backend transport for TestCases. + + Service for managing [Test + Cases][google.cloud.dialogflow.cx.v3.TestCase] and [Test Case + Results][google.cloud.dialogflow.cx.v3.TestCaseResult]. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends protocol buffers over the wire using gRPC (which is built on + top of HTTP/2); the ``grpcio`` package must be installed. + """ + + _grpc_channel: aio.Channel + _stubs: Dict[str, Callable] = {} + + @classmethod + def create_channel( + cls, + host: str = "dialogflow.googleapis.com", + credentials: credentials.Credentials = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, + **kwargs, + ) -> aio.Channel: + """Create and return a gRPC AsyncIO channel object. + Args: + address (Optional[str]): The host for the channel to use. + credentials (Optional[~.Credentials]): The + authorization credentials to attach to requests. These + credentials identify this application to the service. If + none are specified, the client will attempt to ascertain + the credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + kwargs (Optional[dict]): Keyword arguments, which are passed to the + channel creation. + Returns: + aio.Channel: A gRPC AsyncIO channel object. + """ + scopes = scopes or cls.AUTH_SCOPES + return grpc_helpers_async.create_channel( + host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + **kwargs, + ) + + def __init__( + self, + *, + host: str = "dialogflow.googleapis.com", + credentials: credentials.Credentials = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + channel: aio.Channel = None, + api_mtls_endpoint: str = None, + client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, + ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, + quota_project_id=None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + This argument is ignored if ``channel`` is provided. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + channel (Optional[aio.Channel]): A ``Channel`` instance through + which to make calls. + api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. + If provided, it overrides the ``host`` argument and tries to create + a mutual TLS channel with client SSL credentials from + ``client_cert_source`` or applicatin default SSL credentials. + client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): + Deprecated. A callback to provide client SSL certificate bytes and + private key bytes, both in PEM format. It is ignored if + ``api_mtls_endpoint`` is None. + ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials + for 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 + your own client library. + + Raises: + google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport + creation failed for any reason. + google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` + and ``credentials_file`` are passed. + """ + self._ssl_channel_credentials = ssl_channel_credentials + + 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. + credentials = False + + # If a channel was explicitly provided, set it. + self._grpc_channel = channel + self._ssl_channel_credentials = None + elif api_mtls_endpoint: + 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 + ) + + # 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 credentials is None: + credentials, _ = auth.default( + scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id + ) + + 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=self._ssl_channel_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), + ], + ) + + # 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 + + @property + def grpc_channel(self) -> aio.Channel: + """Create the channel designed to connect to this service. + + This property caches on the instance; repeated calls return + the same channel. + """ + # Return the channel from cache. + return self._grpc_channel + + @property + def operations_client(self) -> operations_v1.OperationsAsyncClient: + """Create the client designed to process long-running operations. + + This property caches on the instance; repeated calls return the same + client. + """ + # Sanity check: Only create a new client if we do not already have one. + if self._operations_client is None: + self._operations_client = operations_v1.OperationsAsyncClient( + self.grpc_channel + ) + + # Return the client from cache. + return self._operations_client + + @property + def list_test_cases( + self, + ) -> Callable[ + [test_case.ListTestCasesRequest], Awaitable[test_case.ListTestCasesResponse] + ]: + r"""Return a callable for the list test cases method over gRPC. + + Fetches a list of test cases for a given agent. + + Returns: + Callable[[~.ListTestCasesRequest], + Awaitable[~.ListTestCasesResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_test_cases" not in self._stubs: + self._stubs["list_test_cases"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3.TestCases/ListTestCases", + request_serializer=test_case.ListTestCasesRequest.serialize, + response_deserializer=test_case.ListTestCasesResponse.deserialize, + ) + return self._stubs["list_test_cases"] + + @property + def batch_delete_test_cases( + self, + ) -> Callable[[test_case.BatchDeleteTestCasesRequest], Awaitable[empty.Empty]]: + r"""Return a callable for the batch delete test cases method over gRPC. + + Batch deletes test cases. + + Returns: + Callable[[~.BatchDeleteTestCasesRequest], + Awaitable[~.Empty]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "batch_delete_test_cases" not in self._stubs: + self._stubs["batch_delete_test_cases"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3.TestCases/BatchDeleteTestCases", + request_serializer=test_case.BatchDeleteTestCasesRequest.serialize, + response_deserializer=empty.Empty.FromString, + ) + return self._stubs["batch_delete_test_cases"] + + @property + def get_test_case( + self, + ) -> Callable[[test_case.GetTestCaseRequest], Awaitable[test_case.TestCase]]: + r"""Return a callable for the get test case method over gRPC. + + Gets a test case. + + Returns: + Callable[[~.GetTestCaseRequest], + Awaitable[~.TestCase]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_test_case" not in self._stubs: + self._stubs["get_test_case"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3.TestCases/GetTestCase", + request_serializer=test_case.GetTestCaseRequest.serialize, + response_deserializer=test_case.TestCase.deserialize, + ) + return self._stubs["get_test_case"] + + @property + def create_test_case( + self, + ) -> Callable[ + [gcdc_test_case.CreateTestCaseRequest], Awaitable[gcdc_test_case.TestCase] + ]: + r"""Return a callable for the create test case method over gRPC. + + Creates a test case for the given agent. + + Returns: + Callable[[~.CreateTestCaseRequest], + Awaitable[~.TestCase]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "create_test_case" not in self._stubs: + self._stubs["create_test_case"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3.TestCases/CreateTestCase", + request_serializer=gcdc_test_case.CreateTestCaseRequest.serialize, + response_deserializer=gcdc_test_case.TestCase.deserialize, + ) + return self._stubs["create_test_case"] + + @property + def update_test_case( + self, + ) -> Callable[ + [gcdc_test_case.UpdateTestCaseRequest], Awaitable[gcdc_test_case.TestCase] + ]: + r"""Return a callable for the update test case method over gRPC. + + Updates the specified test case. + + Returns: + Callable[[~.UpdateTestCaseRequest], + Awaitable[~.TestCase]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "update_test_case" not in self._stubs: + self._stubs["update_test_case"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3.TestCases/UpdateTestCase", + request_serializer=gcdc_test_case.UpdateTestCaseRequest.serialize, + response_deserializer=gcdc_test_case.TestCase.deserialize, + ) + return self._stubs["update_test_case"] + + @property + def run_test_case( + self, + ) -> Callable[[test_case.RunTestCaseRequest], Awaitable[operations.Operation]]: + r"""Return a callable for the run test case method over gRPC. + + Kicks off a test case run. + + Returns: + Callable[[~.RunTestCaseRequest], + Awaitable[~.Operation]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "run_test_case" not in self._stubs: + self._stubs["run_test_case"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3.TestCases/RunTestCase", + request_serializer=test_case.RunTestCaseRequest.serialize, + response_deserializer=operations.Operation.FromString, + ) + return self._stubs["run_test_case"] + + @property + def batch_run_test_cases( + self, + ) -> Callable[ + [test_case.BatchRunTestCasesRequest], Awaitable[operations.Operation] + ]: + r"""Return a callable for the batch run test cases method over gRPC. + + Kicks off a batch run of test cases. + + Returns: + Callable[[~.BatchRunTestCasesRequest], + Awaitable[~.Operation]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "batch_run_test_cases" not in self._stubs: + self._stubs["batch_run_test_cases"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3.TestCases/BatchRunTestCases", + request_serializer=test_case.BatchRunTestCasesRequest.serialize, + response_deserializer=operations.Operation.FromString, + ) + return self._stubs["batch_run_test_cases"] + + @property + def calculate_coverage( + self, + ) -> Callable[ + [test_case.CalculateCoverageRequest], + Awaitable[test_case.CalculateCoverageResponse], + ]: + r"""Return a callable for the calculate coverage method over gRPC. + + Calculates the test coverage for an agent. + + Returns: + Callable[[~.CalculateCoverageRequest], + Awaitable[~.CalculateCoverageResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "calculate_coverage" not in self._stubs: + self._stubs["calculate_coverage"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3.TestCases/CalculateCoverage", + request_serializer=test_case.CalculateCoverageRequest.serialize, + response_deserializer=test_case.CalculateCoverageResponse.deserialize, + ) + return self._stubs["calculate_coverage"] + + @property + def import_test_cases( + self, + ) -> Callable[[test_case.ImportTestCasesRequest], Awaitable[operations.Operation]]: + r"""Return a callable for the import test cases method over gRPC. + + Imports the test cases from a Cloud Storage bucket or + a local file. It always creates new test cases and won't + overwite any existing ones. The provided ID in the + imported test case is neglected. + + Returns: + Callable[[~.ImportTestCasesRequest], + Awaitable[~.Operation]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "import_test_cases" not in self._stubs: + self._stubs["import_test_cases"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3.TestCases/ImportTestCases", + request_serializer=test_case.ImportTestCasesRequest.serialize, + response_deserializer=operations.Operation.FromString, + ) + return self._stubs["import_test_cases"] + + @property + def export_test_cases( + self, + ) -> Callable[[test_case.ExportTestCasesRequest], Awaitable[operations.Operation]]: + r"""Return a callable for the export test cases method over gRPC. + + Exports the test cases under the agent to a Cloud + Storage bucket or a local file. Filter can be applied to + export a subset of test cases. + + Returns: + Callable[[~.ExportTestCasesRequest], + Awaitable[~.Operation]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "export_test_cases" not in self._stubs: + self._stubs["export_test_cases"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3.TestCases/ExportTestCases", + request_serializer=test_case.ExportTestCasesRequest.serialize, + response_deserializer=operations.Operation.FromString, + ) + return self._stubs["export_test_cases"] + + @property + def list_test_case_results( + self, + ) -> Callable[ + [test_case.ListTestCaseResultsRequest], + Awaitable[test_case.ListTestCaseResultsResponse], + ]: + r"""Return a callable for the list test case results method over gRPC. + + Fetches a list of results for a given test case. + + Returns: + Callable[[~.ListTestCaseResultsRequest], + Awaitable[~.ListTestCaseResultsResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_test_case_results" not in self._stubs: + self._stubs["list_test_case_results"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3.TestCases/ListTestCaseResults", + request_serializer=test_case.ListTestCaseResultsRequest.serialize, + response_deserializer=test_case.ListTestCaseResultsResponse.deserialize, + ) + return self._stubs["list_test_case_results"] + + +__all__ = ("TestCasesGrpcAsyncIOTransport",) diff --git a/google/cloud/dialogflowcx_v3/services/transition_route_groups/async_client.py b/google/cloud/dialogflowcx_v3/services/transition_route_groups/async_client.py index dcd39a75..7ce59b75 100644 --- a/google/cloud/dialogflowcx_v3/services/transition_route_groups/async_client.py +++ b/google/cloud/dialogflowcx_v3/services/transition_route_groups/async_client.py @@ -97,7 +97,36 @@ class TransitionRouteGroupsAsyncClient: TransitionRouteGroupsClient.parse_common_location_path ) - from_service_account_file = TransitionRouteGroupsClient.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: + TransitionRouteGroupsAsyncClient: The constructed client. + """ + return TransitionRouteGroupsClient.from_service_account_info.__func__(TransitionRouteGroupsAsyncClient, 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: + TransitionRouteGroupsAsyncClient: The constructed client. + """ + return TransitionRouteGroupsClient.from_service_account_file.__func__(TransitionRouteGroupsAsyncClient, filename, *args, **kwargs) # type: ignore + from_service_account_json = from_service_account_file @property @@ -175,13 +204,14 @@ async def list_transition_route_groups( the specified flow. Args: - request (:class:`~.transition_route_group.ListTransitionRouteGroupsRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.ListTransitionRouteGroupsRequest`): The request object. The request message for [TransitionRouteGroups.ListTransitionRouteGroups][google.cloud.dialogflow.cx.v3.TransitionRouteGroups.ListTransitionRouteGroups]. parent (:class:`str`): Required. The flow to list all transition route groups for. Format: ``projects//locations//agents//flows/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -193,7 +223,7 @@ async def list_transition_route_groups( sent along with the request as metadata. Returns: - ~.pagers.ListTransitionRouteGroupsAsyncPager: + google.cloud.dialogflowcx_v3.services.transition_route_groups.pagers.ListTransitionRouteGroupsAsyncPager: The response message for [TransitionRouteGroups.ListTransitionRouteGroups][google.cloud.dialogflow.cx.v3.TransitionRouteGroups.ListTransitionRouteGroups]. @@ -258,7 +288,7 @@ async def get_transition_route_group( [TransitionRouteGroup][google.cloud.dialogflow.cx.v3.TransitionRouteGroup]. Args: - request (:class:`~.transition_route_group.GetTransitionRouteGroupRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.GetTransitionRouteGroupRequest`): The request object. The request message for [TransitionRouteGroups.GetTransitionRouteGroup][google.cloud.dialogflow.cx.v3.TransitionRouteGroups.GetTransitionRouteGroup]. name (:class:`str`): @@ -266,6 +296,7 @@ async def get_transition_route_group( [TransitionRouteGroup][google.cloud.dialogflow.cx.v3.TransitionRouteGroup]. Format: ``projects//locations//agents//flows//transitionRouteGroups/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -277,11 +308,11 @@ async def get_transition_route_group( sent along with the request as metadata. Returns: - ~.transition_route_group.TransitionRouteGroup: + google.cloud.dialogflowcx_v3.types.TransitionRouteGroup: An TransitionRouteGroup represents a group of - [``TransitionRoutes``][google.cloud.dialogflow.cx.v3.TransitionRoute] - to be used by a - [Page][google.cloud.dialogflow.cx.v3.Page]. + [TransitionRoutes][google.cloud.dialogflow.cx.v3.TransitionRoute] + to be used by a + [Page][google.cloud.dialogflow.cx.v3.Page]. """ # Create or coerce a protobuf request object. @@ -337,7 +368,7 @@ async def create_transition_route_group( in the specified flow. Args: - request (:class:`~.gcdc_transition_route_group.CreateTransitionRouteGroupRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.CreateTransitionRouteGroupRequest`): The request object. The request message for [TransitionRouteGroups.CreateTransitionRouteGroup][google.cloud.dialogflow.cx.v3.TransitionRouteGroups.CreateTransitionRouteGroup]. parent (:class:`str`): @@ -345,12 +376,14 @@ async def create_transition_route_group( [TransitionRouteGroup][google.cloud.dialogflow.cx.v3.TransitionRouteGroup] for. Format: ``projects//locations//agents//flows/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - transition_route_group (:class:`~.gcdc_transition_route_group.TransitionRouteGroup`): + transition_route_group (:class:`google.cloud.dialogflowcx_v3.types.TransitionRouteGroup`): Required. The transition route group to create. + This corresponds to the ``transition_route_group`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -362,11 +395,11 @@ async def create_transition_route_group( sent along with the request as metadata. Returns: - ~.gcdc_transition_route_group.TransitionRouteGroup: + google.cloud.dialogflowcx_v3.types.TransitionRouteGroup: An TransitionRouteGroup represents a group of - [``TransitionRoutes``][google.cloud.dialogflow.cx.v3.TransitionRoute] - to be used by a - [Page][google.cloud.dialogflow.cx.v3.Page]. + [TransitionRoutes][google.cloud.dialogflow.cx.v3.TransitionRoute] + to be used by a + [Page][google.cloud.dialogflow.cx.v3.Page]. """ # Create or coerce a protobuf request object. @@ -423,18 +456,20 @@ async def update_transition_route_group( [TransitionRouteGroup][google.cloud.dialogflow.cx.v3.TransitionRouteGroup]. Args: - request (:class:`~.gcdc_transition_route_group.UpdateTransitionRouteGroupRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.UpdateTransitionRouteGroupRequest`): The request object. The request message for [TransitionRouteGroups.UpdateTransitionRouteGroup][google.cloud.dialogflow.cx.v3.TransitionRouteGroups.UpdateTransitionRouteGroup]. - transition_route_group (:class:`~.gcdc_transition_route_group.TransitionRouteGroup`): + transition_route_group (:class:`google.cloud.dialogflowcx_v3.types.TransitionRouteGroup`): Required. The transition route group to update. + This corresponds to the ``transition_route_group`` 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`): The mask to control which fields get updated. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -446,11 +481,11 @@ async def update_transition_route_group( sent along with the request as metadata. Returns: - ~.gcdc_transition_route_group.TransitionRouteGroup: + google.cloud.dialogflowcx_v3.types.TransitionRouteGroup: An TransitionRouteGroup represents a group of - [``TransitionRoutes``][google.cloud.dialogflow.cx.v3.TransitionRoute] - to be used by a - [Page][google.cloud.dialogflow.cx.v3.Page]. + [TransitionRoutes][google.cloud.dialogflow.cx.v3.TransitionRoute] + to be used by a + [Page][google.cloud.dialogflow.cx.v3.Page]. """ # Create or coerce a protobuf request object. @@ -508,7 +543,7 @@ async def delete_transition_route_group( [TransitionRouteGroup][google.cloud.dialogflow.cx.v3.TransitionRouteGroup]. Args: - request (:class:`~.transition_route_group.DeleteTransitionRouteGroupRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.DeleteTransitionRouteGroupRequest`): The request object. The request message for [TransitionRouteGroups.DeleteTransitionRouteGroup][google.cloud.dialogflow.cx.v3.TransitionRouteGroups.DeleteTransitionRouteGroup]. name (:class:`str`): @@ -516,6 +551,7 @@ async def delete_transition_route_group( [TransitionRouteGroup][google.cloud.dialogflow.cx.v3.TransitionRouteGroup] to delete. Format: ``projects//locations//agents//flows//transitionRouteGroups/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. diff --git a/google/cloud/dialogflowcx_v3/services/transition_route_groups/client.py b/google/cloud/dialogflowcx_v3/services/transition_route_groups/client.py index 2b627e9f..cefa3935 100644 --- a/google/cloud/dialogflowcx_v3/services/transition_route_groups/client.py +++ b/google/cloud/dialogflowcx_v3/services/transition_route_groups/client.py @@ -119,6 +119,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: + TransitionRouteGroupsClient: 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 @@ -131,7 +147,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. + TransitionRouteGroupsClient: The constructed client. """ credentials = service_account.Credentials.from_service_account_file(filename) kwargs["credentials"] = credentials @@ -311,10 +327,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, ~.TransitionRouteGroupsTransport]): The + transport (Union[str, TransitionRouteGroupsTransport]): 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 @@ -350,21 +366,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: @@ -407,7 +419,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, ) @@ -425,13 +437,14 @@ def list_transition_route_groups( the specified flow. Args: - request (:class:`~.transition_route_group.ListTransitionRouteGroupsRequest`): + request (google.cloud.dialogflowcx_v3.types.ListTransitionRouteGroupsRequest): The request object. The request message for [TransitionRouteGroups.ListTransitionRouteGroups][google.cloud.dialogflow.cx.v3.TransitionRouteGroups.ListTransitionRouteGroups]. - parent (:class:`str`): + parent (str): Required. The flow to list all transition route groups for. Format: ``projects//locations//agents//flows/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -443,7 +456,7 @@ def list_transition_route_groups( sent along with the request as metadata. Returns: - ~.pagers.ListTransitionRouteGroupsPager: + google.cloud.dialogflowcx_v3.services.transition_route_groups.pagers.ListTransitionRouteGroupsPager: The response message for [TransitionRouteGroups.ListTransitionRouteGroups][google.cloud.dialogflow.cx.v3.TransitionRouteGroups.ListTransitionRouteGroups]. @@ -513,14 +526,15 @@ def get_transition_route_group( [TransitionRouteGroup][google.cloud.dialogflow.cx.v3.TransitionRouteGroup]. Args: - request (:class:`~.transition_route_group.GetTransitionRouteGroupRequest`): + request (google.cloud.dialogflowcx_v3.types.GetTransitionRouteGroupRequest): The request object. The request message for [TransitionRouteGroups.GetTransitionRouteGroup][google.cloud.dialogflow.cx.v3.TransitionRouteGroups.GetTransitionRouteGroup]. - name (:class:`str`): + name (str): Required. The name of the [TransitionRouteGroup][google.cloud.dialogflow.cx.v3.TransitionRouteGroup]. Format: ``projects//locations//agents//flows//transitionRouteGroups/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -532,11 +546,11 @@ def get_transition_route_group( sent along with the request as metadata. Returns: - ~.transition_route_group.TransitionRouteGroup: + google.cloud.dialogflowcx_v3.types.TransitionRouteGroup: An TransitionRouteGroup represents a group of - [``TransitionRoutes``][google.cloud.dialogflow.cx.v3.TransitionRoute] - to be used by a - [Page][google.cloud.dialogflow.cx.v3.Page]. + [TransitionRoutes][google.cloud.dialogflow.cx.v3.TransitionRoute] + to be used by a + [Page][google.cloud.dialogflow.cx.v3.Page]. """ # Create or coerce a protobuf request object. @@ -597,20 +611,22 @@ def create_transition_route_group( in the specified flow. Args: - request (:class:`~.gcdc_transition_route_group.CreateTransitionRouteGroupRequest`): + request (google.cloud.dialogflowcx_v3.types.CreateTransitionRouteGroupRequest): The request object. The request message for [TransitionRouteGroups.CreateTransitionRouteGroup][google.cloud.dialogflow.cx.v3.TransitionRouteGroups.CreateTransitionRouteGroup]. - parent (:class:`str`): + parent (str): Required. The flow to create an [TransitionRouteGroup][google.cloud.dialogflow.cx.v3.TransitionRouteGroup] for. Format: ``projects//locations//agents//flows/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - transition_route_group (:class:`~.gcdc_transition_route_group.TransitionRouteGroup`): + transition_route_group (google.cloud.dialogflowcx_v3.types.TransitionRouteGroup): Required. The transition route group to create. + This corresponds to the ``transition_route_group`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -622,11 +638,11 @@ def create_transition_route_group( sent along with the request as metadata. Returns: - ~.gcdc_transition_route_group.TransitionRouteGroup: + google.cloud.dialogflowcx_v3.types.TransitionRouteGroup: An TransitionRouteGroup represents a group of - [``TransitionRoutes``][google.cloud.dialogflow.cx.v3.TransitionRoute] - to be used by a - [Page][google.cloud.dialogflow.cx.v3.Page]. + [TransitionRoutes][google.cloud.dialogflow.cx.v3.TransitionRoute] + to be used by a + [Page][google.cloud.dialogflow.cx.v3.Page]. """ # Create or coerce a protobuf request object. @@ -690,18 +706,20 @@ def update_transition_route_group( [TransitionRouteGroup][google.cloud.dialogflow.cx.v3.TransitionRouteGroup]. Args: - request (:class:`~.gcdc_transition_route_group.UpdateTransitionRouteGroupRequest`): + request (google.cloud.dialogflowcx_v3.types.UpdateTransitionRouteGroupRequest): The request object. The request message for [TransitionRouteGroups.UpdateTransitionRouteGroup][google.cloud.dialogflow.cx.v3.TransitionRouteGroups.UpdateTransitionRouteGroup]. - transition_route_group (:class:`~.gcdc_transition_route_group.TransitionRouteGroup`): + transition_route_group (google.cloud.dialogflowcx_v3.types.TransitionRouteGroup): Required. The transition route group to update. + This corresponds to the ``transition_route_group`` 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): The mask to control which fields get updated. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -713,11 +731,11 @@ def update_transition_route_group( sent along with the request as metadata. Returns: - ~.gcdc_transition_route_group.TransitionRouteGroup: + google.cloud.dialogflowcx_v3.types.TransitionRouteGroup: An TransitionRouteGroup represents a group of - [``TransitionRoutes``][google.cloud.dialogflow.cx.v3.TransitionRoute] - to be used by a - [Page][google.cloud.dialogflow.cx.v3.Page]. + [TransitionRoutes][google.cloud.dialogflow.cx.v3.TransitionRoute] + to be used by a + [Page][google.cloud.dialogflow.cx.v3.Page]. """ # Create or coerce a protobuf request object. @@ -782,14 +800,15 @@ def delete_transition_route_group( [TransitionRouteGroup][google.cloud.dialogflow.cx.v3.TransitionRouteGroup]. Args: - request (:class:`~.transition_route_group.DeleteTransitionRouteGroupRequest`): + request (google.cloud.dialogflowcx_v3.types.DeleteTransitionRouteGroupRequest): The request object. The request message for [TransitionRouteGroups.DeleteTransitionRouteGroup][google.cloud.dialogflow.cx.v3.TransitionRouteGroups.DeleteTransitionRouteGroup]. - name (:class:`str`): + name (str): Required. The name of the [TransitionRouteGroup][google.cloud.dialogflow.cx.v3.TransitionRouteGroup] to delete. Format: ``projects//locations//agents//flows//transitionRouteGroups/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. diff --git a/google/cloud/dialogflowcx_v3/services/transition_route_groups/pagers.py b/google/cloud/dialogflowcx_v3/services/transition_route_groups/pagers.py index 0326841d..a5d2d6c6 100644 --- a/google/cloud/dialogflowcx_v3/services/transition_route_groups/pagers.py +++ b/google/cloud/dialogflowcx_v3/services/transition_route_groups/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.dialogflowcx_v3.types import transition_route_group @@ -24,7 +33,7 @@ class ListTransitionRouteGroupsPager: """A pager for iterating through ``list_transition_route_groups`` requests. This class thinly wraps an initial - :class:`~.transition_route_group.ListTransitionRouteGroupsResponse` object, and + :class:`google.cloud.dialogflowcx_v3.types.ListTransitionRouteGroupsResponse` object, and provides an ``__iter__`` method to iterate through its ``transition_route_groups`` field. @@ -33,7 +42,7 @@ class ListTransitionRouteGroupsPager: through the ``transition_route_groups`` field on the corresponding responses. - All the usual :class:`~.transition_route_group.ListTransitionRouteGroupsResponse` + All the usual :class:`google.cloud.dialogflowcx_v3.types.ListTransitionRouteGroupsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -51,9 +60,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.transition_route_group.ListTransitionRouteGroupsRequest`): + request (google.cloud.dialogflowcx_v3.types.ListTransitionRouteGroupsRequest): The initial request object. - response (:class:`~.transition_route_group.ListTransitionRouteGroupsResponse`): + response (google.cloud.dialogflowcx_v3.types.ListTransitionRouteGroupsResponse): 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 ListTransitionRouteGroupsAsyncPager: """A pager for iterating through ``list_transition_route_groups`` requests. This class thinly wraps an initial - :class:`~.transition_route_group.ListTransitionRouteGroupsResponse` object, and + :class:`google.cloud.dialogflowcx_v3.types.ListTransitionRouteGroupsResponse` object, and provides an ``__aiter__`` method to iterate through its ``transition_route_groups`` field. @@ -97,7 +106,7 @@ class ListTransitionRouteGroupsAsyncPager: through the ``transition_route_groups`` field on the corresponding responses. - All the usual :class:`~.transition_route_group.ListTransitionRouteGroupsResponse` + All the usual :class:`google.cloud.dialogflowcx_v3.types.ListTransitionRouteGroupsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -117,9 +126,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.transition_route_group.ListTransitionRouteGroupsRequest`): + request (google.cloud.dialogflowcx_v3.types.ListTransitionRouteGroupsRequest): The initial request object. - response (:class:`~.transition_route_group.ListTransitionRouteGroupsResponse`): + response (google.cloud.dialogflowcx_v3.types.ListTransitionRouteGroupsResponse): 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/dialogflowcx_v3/services/transition_route_groups/transports/grpc.py b/google/cloud/dialogflowcx_v3/services/transition_route_groups/transports/grpc.py index bed1e905..a46694ea 100644 --- a/google/cloud/dialogflowcx_v3/services/transition_route_groups/transports/grpc.py +++ b/google/cloud/dialogflowcx_v3/services/transition_route_groups/transports/grpc.py @@ -62,6 +62,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: @@ -92,6 +93,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): @@ -108,6 +113,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -117,11 +127,6 @@ def __init__( 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 @@ -165,12 +170,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ diff --git a/google/cloud/dialogflowcx_v3/services/transition_route_groups/transports/grpc_asyncio.py b/google/cloud/dialogflowcx_v3/services/transition_route_groups/transports/grpc_asyncio.py index 0a2829e3..76a4d328 100644 --- a/google/cloud/dialogflowcx_v3/services/transition_route_groups/transports/grpc_asyncio.py +++ b/google/cloud/dialogflowcx_v3/services/transition_route_groups/transports/grpc_asyncio.py @@ -106,6 +106,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: @@ -137,6 +138,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): @@ -153,6 +158,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -162,11 +172,6 @@ def __init__( 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 @@ -210,12 +215,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ diff --git a/google/cloud/dialogflowcx_v3/services/versions/async_client.py b/google/cloud/dialogflowcx_v3/services/versions/async_client.py index 410e775f..61aaec83 100644 --- a/google/cloud/dialogflowcx_v3/services/versions/async_client.py +++ b/google/cloud/dialogflowcx_v3/services/versions/async_client.py @@ -78,7 +78,36 @@ class VersionsAsyncClient: common_location_path = staticmethod(VersionsClient.common_location_path) parse_common_location_path = staticmethod(VersionsClient.parse_common_location_path) - from_service_account_file = VersionsClient.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: + VersionsAsyncClient: The constructed client. + """ + return VersionsClient.from_service_account_info.__func__(VersionsAsyncClient, 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: + VersionsAsyncClient: The constructed client. + """ + return VersionsClient.from_service_account_file.__func__(VersionsAsyncClient, filename, *args, **kwargs) # type: ignore + from_service_account_json = from_service_account_file @property @@ -155,13 +184,14 @@ async def list_versions( [Flow][google.cloud.dialogflow.cx.v3.Flow]. Args: - request (:class:`~.version.ListVersionsRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.ListVersionsRequest`): The request object. The request message for [Versions.ListVersions][google.cloud.dialogflow.cx.v3.Versions.ListVersions]. parent (:class:`str`): Required. The [Flow][google.cloud.dialogflow.cx.v3.Flow] to list all versions for. Format: ``projects//locations//agents//flows/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -173,7 +203,7 @@ async def list_versions( sent along with the request as metadata. Returns: - ~.pagers.ListVersionsAsyncPager: + google.cloud.dialogflowcx_v3.services.versions.pagers.ListVersionsAsyncPager: The response message for [Versions.ListVersions][google.cloud.dialogflow.cx.v3.Versions.ListVersions]. @@ -238,7 +268,7 @@ async def get_version( [Version][google.cloud.dialogflow.cx.v3.Version]. Args: - request (:class:`~.version.GetVersionRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.GetVersionRequest`): The request object. The request message for [Versions.GetVersion][google.cloud.dialogflow.cx.v3.Versions.GetVersion]. name (:class:`str`): @@ -246,6 +276,7 @@ async def get_version( [Version][google.cloud.dialogflow.cx.v3.Version]. Format: ``projects//locations//agents//flows//versions/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -257,7 +288,7 @@ async def get_version( sent along with the request as metadata. Returns: - ~.version.Version: + google.cloud.dialogflowcx_v3.types.Version: Represents a version of a flow. """ # Create or coerce a protobuf request object. @@ -312,7 +343,7 @@ async def create_version( the specified [Flow][google.cloud.dialogflow.cx.v3.Flow]. Args: - request (:class:`~.gcdc_version.CreateVersionRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.CreateVersionRequest`): The request object. The request message for [Versions.CreateVersion][google.cloud.dialogflow.cx.v3.Versions.CreateVersion]. parent (:class:`str`): @@ -321,10 +352,11 @@ async def create_version( [Version][google.cloud.dialogflow.cx.v3.Version] for. Format: ``projects//locations//agents//flows/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - version (:class:`~.gcdc_version.Version`): + version (:class:`google.cloud.dialogflowcx_v3.types.Version`): Required. The version to create. This corresponds to the ``version`` field on the ``request`` instance; if ``request`` is provided, this @@ -337,12 +369,12 @@ async def create_version( 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:``~.gcdc_version.Version``: Represents a version - of a flow. + :class:`google.cloud.dialogflowcx_v3.types.Version` + Represents a version of a flow. """ # Create or coerce a protobuf request object. @@ -407,18 +439,19 @@ async def update_version( [Version][google.cloud.dialogflow.cx.v3.Version]. Args: - request (:class:`~.gcdc_version.UpdateVersionRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.UpdateVersionRequest`): The request object. The request message for [Versions.UpdateVersion][google.cloud.dialogflow.cx.v3.Versions.UpdateVersion]. - version (:class:`~.gcdc_version.Version`): + version (:class:`google.cloud.dialogflowcx_v3.types.Version`): Required. The version to update. This corresponds to the ``version`` 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`): Required. The mask to control which fields get updated. Currently only ``description`` and ``display_name`` can be updated. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -430,7 +463,7 @@ async def update_version( sent along with the request as metadata. Returns: - ~.gcdc_version.Version: + google.cloud.dialogflowcx_v3.types.Version: Represents a version of a flow. """ # Create or coerce a protobuf request object. @@ -488,7 +521,7 @@ async def delete_version( [Version][google.cloud.dialogflow.cx.v3.Version]. Args: - request (:class:`~.version.DeleteVersionRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.DeleteVersionRequest`): The request object. The request message for [Versions.DeleteVersion][google.cloud.dialogflow.cx.v3.Versions.DeleteVersion]. name (:class:`str`): @@ -496,6 +529,7 @@ async def delete_version( [Version][google.cloud.dialogflow.cx.v3.Version] to delete. Format: ``projects//locations//agents//flows//versions/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -555,7 +589,7 @@ async def load_version( r"""Loads a specified version to draft version. Args: - request (:class:`~.version.LoadVersionRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.LoadVersionRequest`): The request object. The request message for [Versions.LoadVersion][google.cloud.dialogflow.cx.v3.Versions.LoadVersion]. name (:class:`str`): @@ -563,6 +597,7 @@ async def load_version( [Version][google.cloud.dialogflow.cx.v3.Version] to be loaded to draft version. Format: ``projects//locations//agents//flows//versions/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -574,24 +609,22 @@ async def load_version( 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:``~.empty.Empty``: A generic empty message that - you can re-use to avoid defining duplicated empty - messages in your APIs. A typical example is to use it as - the request or the response type of an API method. For - instance: + The result type for the operation will be :class:`google.protobuf.empty_pb2.Empty` A generic empty message that you can re-use to avoid defining duplicated + empty messages in your APIs. A typical example is to + use it as the request or the response type of an API + method. For instance: - :: + service Foo { + rpc Bar(google.protobuf.Empty) returns + (google.protobuf.Empty); - service Foo { - rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty); - } + } - The JSON representation for ``Empty`` is empty JSON - object ``{}``. + The JSON representation for Empty is empty JSON + object {}. """ # Create or coerce a protobuf request object. diff --git a/google/cloud/dialogflowcx_v3/services/versions/client.py b/google/cloud/dialogflowcx_v3/services/versions/client.py index 2cf5e748..9ede0ecb 100644 --- a/google/cloud/dialogflowcx_v3/services/versions/client.py +++ b/google/cloud/dialogflowcx_v3/services/versions/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: + VersionsClient: 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. + VersionsClient: The constructed client. """ credentials = service_account.Credentials.from_service_account_file(filename) kwargs["credentials"] = credentials @@ -240,10 +256,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, ~.VersionsTransport]): The + transport (Union[str, VersionsTransport]): 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 @@ -279,21 +295,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: @@ -336,7 +348,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, ) @@ -354,13 +366,14 @@ def list_versions( [Flow][google.cloud.dialogflow.cx.v3.Flow]. Args: - request (:class:`~.version.ListVersionsRequest`): + request (google.cloud.dialogflowcx_v3.types.ListVersionsRequest): The request object. The request message for [Versions.ListVersions][google.cloud.dialogflow.cx.v3.Versions.ListVersions]. - parent (:class:`str`): + parent (str): Required. The [Flow][google.cloud.dialogflow.cx.v3.Flow] to list all versions for. Format: ``projects//locations//agents//flows/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -372,7 +385,7 @@ def list_versions( sent along with the request as metadata. Returns: - ~.pagers.ListVersionsPager: + google.cloud.dialogflowcx_v3.services.versions.pagers.ListVersionsPager: The response message for [Versions.ListVersions][google.cloud.dialogflow.cx.v3.Versions.ListVersions]. @@ -438,14 +451,15 @@ def get_version( [Version][google.cloud.dialogflow.cx.v3.Version]. Args: - request (:class:`~.version.GetVersionRequest`): + request (google.cloud.dialogflowcx_v3.types.GetVersionRequest): The request object. The request message for [Versions.GetVersion][google.cloud.dialogflow.cx.v3.Versions.GetVersion]. - name (:class:`str`): + name (str): Required. The name of the [Version][google.cloud.dialogflow.cx.v3.Version]. Format: ``projects//locations//agents//flows//versions/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -457,7 +471,7 @@ def get_version( sent along with the request as metadata. Returns: - ~.version.Version: + google.cloud.dialogflowcx_v3.types.Version: Represents a version of a flow. """ # Create or coerce a protobuf request object. @@ -513,19 +527,20 @@ def create_version( the specified [Flow][google.cloud.dialogflow.cx.v3.Flow]. Args: - request (:class:`~.gcdc_version.CreateVersionRequest`): + request (google.cloud.dialogflowcx_v3.types.CreateVersionRequest): The request object. The request message for [Versions.CreateVersion][google.cloud.dialogflow.cx.v3.Versions.CreateVersion]. - parent (:class:`str`): + parent (str): Required. The [Flow][google.cloud.dialogflow.cx.v3.Flow] to create an [Version][google.cloud.dialogflow.cx.v3.Version] for. Format: ``projects//locations//agents//flows/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - version (:class:`~.gcdc_version.Version`): + version (google.cloud.dialogflowcx_v3.types.Version): Required. The version to create. This corresponds to the ``version`` field on the ``request`` instance; if ``request`` is provided, this @@ -538,12 +553,12 @@ def create_version( 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:``~.gcdc_version.Version``: Represents a version - of a flow. + :class:`google.cloud.dialogflowcx_v3.types.Version` + Represents a version of a flow. """ # Create or coerce a protobuf request object. @@ -609,18 +624,19 @@ def update_version( [Version][google.cloud.dialogflow.cx.v3.Version]. Args: - request (:class:`~.gcdc_version.UpdateVersionRequest`): + request (google.cloud.dialogflowcx_v3.types.UpdateVersionRequest): The request object. The request message for [Versions.UpdateVersion][google.cloud.dialogflow.cx.v3.Versions.UpdateVersion]. - version (:class:`~.gcdc_version.Version`): + version (google.cloud.dialogflowcx_v3.types.Version): Required. The version to update. This corresponds to the ``version`` 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): Required. The mask to control which fields get updated. Currently only ``description`` and ``display_name`` can be updated. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -632,7 +648,7 @@ def update_version( sent along with the request as metadata. Returns: - ~.gcdc_version.Version: + google.cloud.dialogflowcx_v3.types.Version: Represents a version of a flow. """ # Create or coerce a protobuf request object. @@ -691,14 +707,15 @@ def delete_version( [Version][google.cloud.dialogflow.cx.v3.Version]. Args: - request (:class:`~.version.DeleteVersionRequest`): + request (google.cloud.dialogflowcx_v3.types.DeleteVersionRequest): The request object. The request message for [Versions.DeleteVersion][google.cloud.dialogflow.cx.v3.Versions.DeleteVersion]. - name (:class:`str`): + name (str): Required. The name of the [Version][google.cloud.dialogflow.cx.v3.Version] to delete. Format: ``projects//locations//agents//flows//versions/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -759,14 +776,15 @@ def load_version( r"""Loads a specified version to draft version. Args: - request (:class:`~.version.LoadVersionRequest`): + request (google.cloud.dialogflowcx_v3.types.LoadVersionRequest): The request object. The request message for [Versions.LoadVersion][google.cloud.dialogflow.cx.v3.Versions.LoadVersion]. - name (:class:`str`): + name (str): Required. The [Version][google.cloud.dialogflow.cx.v3.Version] to be loaded to draft version. Format: ``projects//locations//agents//flows//versions/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -778,24 +796,22 @@ def load_version( 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:``~.empty.Empty``: A generic empty message that - you can re-use to avoid defining duplicated empty - messages in your APIs. A typical example is to use it as - the request or the response type of an API method. For - instance: + The result type for the operation will be :class:`google.protobuf.empty_pb2.Empty` A generic empty message that you can re-use to avoid defining duplicated + empty messages in your APIs. A typical example is to + use it as the request or the response type of an API + method. For instance: - :: + service Foo { + rpc Bar(google.protobuf.Empty) returns + (google.protobuf.Empty); - service Foo { - rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty); - } + } - The JSON representation for ``Empty`` is empty JSON - object ``{}``. + The JSON representation for Empty is empty JSON + object {}. """ # Create or coerce a protobuf request object. diff --git a/google/cloud/dialogflowcx_v3/services/versions/pagers.py b/google/cloud/dialogflowcx_v3/services/versions/pagers.py index decd7e0e..6c4592b9 100644 --- a/google/cloud/dialogflowcx_v3/services/versions/pagers.py +++ b/google/cloud/dialogflowcx_v3/services/versions/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.dialogflowcx_v3.types import version @@ -24,7 +33,7 @@ class ListVersionsPager: """A pager for iterating through ``list_versions`` requests. This class thinly wraps an initial - :class:`~.version.ListVersionsResponse` object, and + :class:`google.cloud.dialogflowcx_v3.types.ListVersionsResponse` object, and provides an ``__iter__`` method to iterate through its ``versions`` field. @@ -33,7 +42,7 @@ class ListVersionsPager: through the ``versions`` field on the corresponding responses. - All the usual :class:`~.version.ListVersionsResponse` + All the usual :class:`google.cloud.dialogflowcx_v3.types.ListVersionsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -51,9 +60,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.version.ListVersionsRequest`): + request (google.cloud.dialogflowcx_v3.types.ListVersionsRequest): The initial request object. - response (:class:`~.version.ListVersionsResponse`): + response (google.cloud.dialogflowcx_v3.types.ListVersionsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -86,7 +95,7 @@ class ListVersionsAsyncPager: """A pager for iterating through ``list_versions`` requests. This class thinly wraps an initial - :class:`~.version.ListVersionsResponse` object, and + :class:`google.cloud.dialogflowcx_v3.types.ListVersionsResponse` object, and provides an ``__aiter__`` method to iterate through its ``versions`` field. @@ -95,7 +104,7 @@ class ListVersionsAsyncPager: through the ``versions`` field on the corresponding responses. - All the usual :class:`~.version.ListVersionsResponse` + All the usual :class:`google.cloud.dialogflowcx_v3.types.ListVersionsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -113,9 +122,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.version.ListVersionsRequest`): + request (google.cloud.dialogflowcx_v3.types.ListVersionsRequest): The initial request object. - response (:class:`~.version.ListVersionsResponse`): + response (google.cloud.dialogflowcx_v3.types.ListVersionsResponse): 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/dialogflowcx_v3/services/versions/transports/grpc.py b/google/cloud/dialogflowcx_v3/services/versions/transports/grpc.py index 27a1b7fa..d3f5663f 100644 --- a/google/cloud/dialogflowcx_v3/services/versions/transports/grpc.py +++ b/google/cloud/dialogflowcx_v3/services/versions/transports/grpc.py @@ -62,6 +62,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: @@ -92,6 +93,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): @@ -108,6 +113,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -117,11 +127,6 @@ def __init__( 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 @@ -165,12 +170,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ diff --git a/google/cloud/dialogflowcx_v3/services/versions/transports/grpc_asyncio.py b/google/cloud/dialogflowcx_v3/services/versions/transports/grpc_asyncio.py index 52f2708a..5fe47863 100644 --- a/google/cloud/dialogflowcx_v3/services/versions/transports/grpc_asyncio.py +++ b/google/cloud/dialogflowcx_v3/services/versions/transports/grpc_asyncio.py @@ -106,6 +106,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: @@ -137,6 +138,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): @@ -153,6 +158,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -162,11 +172,6 @@ def __init__( 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 @@ -210,12 +215,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ diff --git a/google/cloud/dialogflowcx_v3/services/webhooks/async_client.py b/google/cloud/dialogflowcx_v3/services/webhooks/async_client.py index c7392227..8420ed10 100644 --- a/google/cloud/dialogflowcx_v3/services/webhooks/async_client.py +++ b/google/cloud/dialogflowcx_v3/services/webhooks/async_client.py @@ -73,7 +73,36 @@ class WebhooksAsyncClient: common_location_path = staticmethod(WebhooksClient.common_location_path) parse_common_location_path = staticmethod(WebhooksClient.parse_common_location_path) - from_service_account_file = WebhooksClient.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: + WebhooksAsyncClient: The constructed client. + """ + return WebhooksClient.from_service_account_info.__func__(WebhooksAsyncClient, 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: + WebhooksAsyncClient: The constructed client. + """ + return WebhooksClient.from_service_account_file.__func__(WebhooksAsyncClient, filename, *args, **kwargs) # type: ignore + from_service_account_json = from_service_account_file @property @@ -150,12 +179,13 @@ async def list_webhooks( agent. Args: - request (:class:`~.webhook.ListWebhooksRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.ListWebhooksRequest`): The request object. The request message for [Webhooks.ListWebhooks][google.cloud.dialogflow.cx.v3.Webhooks.ListWebhooks]. parent (:class:`str`): Required. The agent to list all webhooks for. Format: ``projects//locations//agents/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -167,7 +197,7 @@ async def list_webhooks( sent along with the request as metadata. Returns: - ~.pagers.ListWebhooksAsyncPager: + google.cloud.dialogflowcx_v3.services.webhooks.pagers.ListWebhooksAsyncPager: The response message for [Webhooks.ListWebhooks][google.cloud.dialogflow.cx.v3.Webhooks.ListWebhooks]. @@ -231,12 +261,13 @@ async def get_webhook( r"""Retrieves the specified webhook. Args: - request (:class:`~.webhook.GetWebhookRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.GetWebhookRequest`): The request object. The request message for [Webhooks.GetWebhook][google.cloud.dialogflow.cx.v3.Webhooks.GetWebhook]. name (:class:`str`): Required. The name of the webhook. Format: ``projects//locations//agents//webhooks/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -248,7 +279,7 @@ async def get_webhook( sent along with the request as metadata. Returns: - ~.webhook.Webhook: + google.cloud.dialogflowcx_v3.types.Webhook: Webhooks host the developer's business logic. During a session, webhooks allow the developer to use the @@ -309,16 +340,17 @@ async def create_webhook( r"""Creates a webhook in the specified agent. Args: - request (:class:`~.gcdc_webhook.CreateWebhookRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.CreateWebhookRequest`): The request object. The request message for [Webhooks.CreateWebhook][google.cloud.dialogflow.cx.v3.Webhooks.CreateWebhook]. parent (:class:`str`): Required. The agent to create a webhook for. Format: ``projects//locations//agents/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - webhook (:class:`~.gcdc_webhook.Webhook`): + webhook (:class:`google.cloud.dialogflowcx_v3.types.Webhook`): Required. The webhook to create. This corresponds to the ``webhook`` field on the ``request`` instance; if ``request`` is provided, this @@ -331,7 +363,7 @@ async def create_webhook( sent along with the request as metadata. Returns: - ~.gcdc_webhook.Webhook: + google.cloud.dialogflowcx_v3.types.Webhook: Webhooks host the developer's business logic. During a session, webhooks allow the developer to use the @@ -394,18 +426,19 @@ async def update_webhook( r"""Updates the specified webhook. Args: - request (:class:`~.gcdc_webhook.UpdateWebhookRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.UpdateWebhookRequest`): The request object. The request message for [Webhooks.UpdateWebhook][google.cloud.dialogflow.cx.v3.Webhooks.UpdateWebhook]. - webhook (:class:`~.gcdc_webhook.Webhook`): + webhook (:class:`google.cloud.dialogflowcx_v3.types.Webhook`): Required. The webhook to update. This corresponds to the ``webhook`` 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`): The mask to control which fields get updated. If the mask is not present, all fields will be updated. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -417,7 +450,7 @@ async def update_webhook( sent along with the request as metadata. Returns: - ~.gcdc_webhook.Webhook: + google.cloud.dialogflowcx_v3.types.Webhook: Webhooks host the developer's business logic. During a session, webhooks allow the developer to use the @@ -481,12 +514,13 @@ async def delete_webhook( r"""Deletes the specified webhook. Args: - request (:class:`~.webhook.DeleteWebhookRequest`): + request (:class:`google.cloud.dialogflowcx_v3.types.DeleteWebhookRequest`): The request object. The request message for [Webhooks.DeleteWebhook][google.cloud.dialogflow.cx.v3.Webhooks.DeleteWebhook]. name (:class:`str`): Required. The name of the webhook to delete. Format: ``projects//locations//agents//webhooks/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. diff --git a/google/cloud/dialogflowcx_v3/services/webhooks/client.py b/google/cloud/dialogflowcx_v3/services/webhooks/client.py index 8736fa0e..a1da5e3b 100644 --- a/google/cloud/dialogflowcx_v3/services/webhooks/client.py +++ b/google/cloud/dialogflowcx_v3/services/webhooks/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: + WebhooksClient: 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. + WebhooksClient: The constructed client. """ credentials = service_account.Credentials.from_service_account_file(filename) kwargs["credentials"] = credentials @@ -233,10 +249,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, ~.WebhooksTransport]): The + transport (Union[str, WebhooksTransport]): 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 @@ -272,21 +288,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: @@ -329,7 +341,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, ) @@ -347,12 +359,13 @@ def list_webhooks( agent. Args: - request (:class:`~.webhook.ListWebhooksRequest`): + request (google.cloud.dialogflowcx_v3.types.ListWebhooksRequest): The request object. The request message for [Webhooks.ListWebhooks][google.cloud.dialogflow.cx.v3.Webhooks.ListWebhooks]. - parent (:class:`str`): + parent (str): Required. The agent to list all webhooks for. Format: ``projects//locations//agents/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -364,7 +377,7 @@ def list_webhooks( sent along with the request as metadata. Returns: - ~.pagers.ListWebhooksPager: + google.cloud.dialogflowcx_v3.services.webhooks.pagers.ListWebhooksPager: The response message for [Webhooks.ListWebhooks][google.cloud.dialogflow.cx.v3.Webhooks.ListWebhooks]. @@ -429,12 +442,13 @@ def get_webhook( r"""Retrieves the specified webhook. Args: - request (:class:`~.webhook.GetWebhookRequest`): + request (google.cloud.dialogflowcx_v3.types.GetWebhookRequest): The request object. The request message for [Webhooks.GetWebhook][google.cloud.dialogflow.cx.v3.Webhooks.GetWebhook]. - name (:class:`str`): + name (str): Required. The name of the webhook. Format: ``projects//locations//agents//webhooks/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -446,7 +460,7 @@ def get_webhook( sent along with the request as metadata. Returns: - ~.webhook.Webhook: + google.cloud.dialogflowcx_v3.types.Webhook: Webhooks host the developer's business logic. During a session, webhooks allow the developer to use the @@ -508,16 +522,17 @@ def create_webhook( r"""Creates a webhook in the specified agent. Args: - request (:class:`~.gcdc_webhook.CreateWebhookRequest`): + request (google.cloud.dialogflowcx_v3.types.CreateWebhookRequest): The request object. The request message for [Webhooks.CreateWebhook][google.cloud.dialogflow.cx.v3.Webhooks.CreateWebhook]. - parent (:class:`str`): + parent (str): Required. The agent to create a webhook for. Format: ``projects//locations//agents/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - webhook (:class:`~.gcdc_webhook.Webhook`): + webhook (google.cloud.dialogflowcx_v3.types.Webhook): Required. The webhook to create. This corresponds to the ``webhook`` field on the ``request`` instance; if ``request`` is provided, this @@ -530,7 +545,7 @@ def create_webhook( sent along with the request as metadata. Returns: - ~.gcdc_webhook.Webhook: + google.cloud.dialogflowcx_v3.types.Webhook: Webhooks host the developer's business logic. During a session, webhooks allow the developer to use the @@ -594,18 +609,19 @@ def update_webhook( r"""Updates the specified webhook. Args: - request (:class:`~.gcdc_webhook.UpdateWebhookRequest`): + request (google.cloud.dialogflowcx_v3.types.UpdateWebhookRequest): The request object. The request message for [Webhooks.UpdateWebhook][google.cloud.dialogflow.cx.v3.Webhooks.UpdateWebhook]. - webhook (:class:`~.gcdc_webhook.Webhook`): + webhook (google.cloud.dialogflowcx_v3.types.Webhook): Required. The webhook to update. This corresponds to the ``webhook`` 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): The mask to control which fields get updated. If the mask is not present, all fields will be updated. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -617,7 +633,7 @@ def update_webhook( sent along with the request as metadata. Returns: - ~.gcdc_webhook.Webhook: + google.cloud.dialogflowcx_v3.types.Webhook: Webhooks host the developer's business logic. During a session, webhooks allow the developer to use the @@ -682,12 +698,13 @@ def delete_webhook( r"""Deletes the specified webhook. Args: - request (:class:`~.webhook.DeleteWebhookRequest`): + request (google.cloud.dialogflowcx_v3.types.DeleteWebhookRequest): The request object. The request message for [Webhooks.DeleteWebhook][google.cloud.dialogflow.cx.v3.Webhooks.DeleteWebhook]. - name (:class:`str`): + name (str): Required. The name of the webhook to delete. Format: ``projects//locations//agents//webhooks/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. diff --git a/google/cloud/dialogflowcx_v3/services/webhooks/pagers.py b/google/cloud/dialogflowcx_v3/services/webhooks/pagers.py index d84e8457..b1738d62 100644 --- a/google/cloud/dialogflowcx_v3/services/webhooks/pagers.py +++ b/google/cloud/dialogflowcx_v3/services/webhooks/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.dialogflowcx_v3.types import webhook @@ -24,7 +33,7 @@ class ListWebhooksPager: """A pager for iterating through ``list_webhooks`` requests. This class thinly wraps an initial - :class:`~.webhook.ListWebhooksResponse` object, and + :class:`google.cloud.dialogflowcx_v3.types.ListWebhooksResponse` object, and provides an ``__iter__`` method to iterate through its ``webhooks`` field. @@ -33,7 +42,7 @@ class ListWebhooksPager: through the ``webhooks`` field on the corresponding responses. - All the usual :class:`~.webhook.ListWebhooksResponse` + All the usual :class:`google.cloud.dialogflowcx_v3.types.ListWebhooksResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -51,9 +60,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.webhook.ListWebhooksRequest`): + request (google.cloud.dialogflowcx_v3.types.ListWebhooksRequest): The initial request object. - response (:class:`~.webhook.ListWebhooksResponse`): + response (google.cloud.dialogflowcx_v3.types.ListWebhooksResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -86,7 +95,7 @@ class ListWebhooksAsyncPager: """A pager for iterating through ``list_webhooks`` requests. This class thinly wraps an initial - :class:`~.webhook.ListWebhooksResponse` object, and + :class:`google.cloud.dialogflowcx_v3.types.ListWebhooksResponse` object, and provides an ``__aiter__`` method to iterate through its ``webhooks`` field. @@ -95,7 +104,7 @@ class ListWebhooksAsyncPager: through the ``webhooks`` field on the corresponding responses. - All the usual :class:`~.webhook.ListWebhooksResponse` + All the usual :class:`google.cloud.dialogflowcx_v3.types.ListWebhooksResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -113,9 +122,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.webhook.ListWebhooksRequest`): + request (google.cloud.dialogflowcx_v3.types.ListWebhooksRequest): The initial request object. - response (:class:`~.webhook.ListWebhooksResponse`): + response (google.cloud.dialogflowcx_v3.types.ListWebhooksResponse): 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/dialogflowcx_v3/services/webhooks/transports/grpc.py b/google/cloud/dialogflowcx_v3/services/webhooks/transports/grpc.py index 51a87ddd..31c25e97 100644 --- a/google/cloud/dialogflowcx_v3/services/webhooks/transports/grpc.py +++ b/google/cloud/dialogflowcx_v3/services/webhooks/transports/grpc.py @@ -60,6 +60,7 @@ def __init__( api_mtls_endpoint: str = None, client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, quota_project_id: Optional[str] = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: @@ -90,6 +91,10 @@ def __init__( ``api_mtls_endpoint`` is None. ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials for grpc channel. It is ignored if ``channel`` is provided. + client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]): + A callback to provide client certificate bytes and private key bytes, + both in PEM format. It is used to configure mutual TLS channel. It is + ignored if ``channel`` or ``ssl_channel_credentials`` is provided. quota_project_id (Optional[str]): An optional project to use for billing and quota. client_info (google.api_core.gapic_v1.client_info.ClientInfo): @@ -106,6 +111,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -115,11 +125,6 @@ def __init__( 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 @@ -163,12 +168,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ diff --git a/google/cloud/dialogflowcx_v3/services/webhooks/transports/grpc_asyncio.py b/google/cloud/dialogflowcx_v3/services/webhooks/transports/grpc_asyncio.py index 16fc6f12..4e556df5 100644 --- a/google/cloud/dialogflowcx_v3/services/webhooks/transports/grpc_asyncio.py +++ b/google/cloud/dialogflowcx_v3/services/webhooks/transports/grpc_asyncio.py @@ -104,6 +104,7 @@ def __init__( api_mtls_endpoint: str = None, client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, quota_project_id=None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: @@ -135,6 +136,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): @@ -151,6 +156,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -160,11 +170,6 @@ def __init__( 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 @@ -208,12 +213,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ diff --git a/google/cloud/dialogflowcx_v3/types/__init__.py b/google/cloud/dialogflowcx_v3/types/__init__.py index fc0ebbf8..7229dd1a 100644 --- a/google/cloud/dialogflowcx_v3/types/__init__.py +++ b/google/cloud/dialogflowcx_v3/types/__init__.py @@ -29,6 +29,10 @@ UpdatePageRequest, DeletePageRequest, ) +from .validation_message import ( + ValidationMessage, + ResourceName, +) from .flow import ( NluSettings, Flow, @@ -39,6 +43,9 @@ GetFlowRequest, UpdateFlowRequest, TrainFlowRequest, + ValidateFlowRequest, + GetFlowValidationResultRequest, + FlowValidationResult, ) from .agent import ( SpeechToTextSettings, @@ -52,6 +59,9 @@ ExportAgentRequest, ExportAgentResponse, RestoreAgentRequest, + ValidateAgentRequest, + GetAgentValidationResultRequest, + AgentValidationResult, ) from .audio_config import ( SpeechWordInfo, @@ -155,6 +165,41 @@ UpdateTransitionRouteGroupRequest, DeleteTransitionRouteGroupRequest, ) +from .test_case import ( + TestCase, + TestCaseResult, + TestConfig, + ConversationTurn, + TestRunDifference, + TransitionCoverage, + TransitionRouteGroupCoverage, + IntentCoverage, + CalculateCoverageRequest, + CalculateCoverageResponse, + ListTestCasesRequest, + ListTestCasesResponse, + BatchDeleteTestCasesRequest, + CreateTestCaseRequest, + UpdateTestCaseRequest, + GetTestCaseRequest, + RunTestCaseRequest, + RunTestCaseResponse, + RunTestCaseMetadata, + BatchRunTestCasesRequest, + BatchRunTestCasesResponse, + BatchRunTestCasesMetadata, + TestError, + ImportTestCasesRequest, + ImportTestCasesResponse, + ImportTestCasesMetadata, + TestCaseError, + ExportTestCasesRequest, + ExportTestCasesResponse, + ExportTestCasesMetadata, + ListTestCaseResultsRequest, + ListTestCaseResultsResponse, + TestResult, +) from .version import ( CreateVersionOperationMetadata, Version, @@ -193,6 +238,8 @@ "CreatePageRequest", "UpdatePageRequest", "DeletePageRequest", + "ValidationMessage", + "ResourceName", "NluSettings", "Flow", "CreateFlowRequest", @@ -202,6 +249,9 @@ "GetFlowRequest", "UpdateFlowRequest", "TrainFlowRequest", + "ValidateFlowRequest", + "GetFlowValidationResultRequest", + "FlowValidationResult", "SpeechToTextSettings", "Agent", "ListAgentsRequest", @@ -213,6 +263,9 @@ "ExportAgentRequest", "ExportAgentResponse", "RestoreAgentRequest", + "ValidateAgentRequest", + "GetAgentValidationResultRequest", + "AgentValidationResult", "SpeechWordInfo", "InputAudioConfig", "VoiceSelectionParams", @@ -297,6 +350,39 @@ "CreateTransitionRouteGroupRequest", "UpdateTransitionRouteGroupRequest", "DeleteTransitionRouteGroupRequest", + "TestCase", + "TestCaseResult", + "TestConfig", + "ConversationTurn", + "TestRunDifference", + "TransitionCoverage", + "TransitionRouteGroupCoverage", + "IntentCoverage", + "CalculateCoverageRequest", + "CalculateCoverageResponse", + "ListTestCasesRequest", + "ListTestCasesResponse", + "BatchDeleteTestCasesRequest", + "CreateTestCaseRequest", + "UpdateTestCaseRequest", + "GetTestCaseRequest", + "RunTestCaseRequest", + "RunTestCaseResponse", + "RunTestCaseMetadata", + "BatchRunTestCasesRequest", + "BatchRunTestCasesResponse", + "BatchRunTestCasesMetadata", + "TestError", + "ImportTestCasesRequest", + "ImportTestCasesResponse", + "ImportTestCasesMetadata", + "TestCaseError", + "ExportTestCasesRequest", + "ExportTestCasesResponse", + "ExportTestCasesMetadata", + "ListTestCaseResultsRequest", + "ListTestCaseResultsResponse", + "TestResult", "CreateVersionOperationMetadata", "Version", "ListVersionsRequest", diff --git a/google/cloud/dialogflowcx_v3/types/agent.py b/google/cloud/dialogflowcx_v3/types/agent.py index 9ba5bd47..39a49923 100644 --- a/google/cloud/dialogflowcx_v3/types/agent.py +++ b/google/cloud/dialogflowcx_v3/types/agent.py @@ -18,6 +18,7 @@ import proto # type: ignore +from google.cloud.dialogflowcx_v3.types import flow from google.protobuf import field_mask_pb2 as field_mask # type: ignore @@ -35,6 +36,9 @@ "ExportAgentRequest", "ExportAgentResponse", "RestoreAgentRequest", + "ValidateAgentRequest", + "GetAgentValidationResultRequest", + "AgentValidationResult", }, ) @@ -79,7 +83,7 @@ class Agent(proto.Message): default_language_code (str): Immutable. The default language of the agent as a language tag. See `Language - Support `__ + Support `__ for a list of the currently supported language codes. This field cannot be set by the [Agents.UpdateAgent][google.cloud.dialogflow.cx.v3.Agents.UpdateAgent] @@ -97,7 +101,7 @@ class Agent(proto.Message): the Dialogflow console and in the self-hosted `Web Demo `__ integration. - speech_to_text_settings (~.gcdc_agent.SpeechToTextSettings): + speech_to_text_settings (google.cloud.dialogflowcx_v3.types.SpeechToTextSettings): Speech recognition related settings. start_flow (str): Immutable. Name of the start flow in this agent. A start @@ -105,6 +109,11 @@ class Agent(proto.Message): created, and can only be deleted by deleting the agent. Format: ``projects//locations//agents//flows/``. + security_settings (str): + Name of the + [SecuritySettings][google.cloud.dialogflow.cx.v3.SecuritySettings] + reference for the agent. Format: + ``projects//locations//securitySettings/``. enable_stackdriver_logging (bool): Indicates if stackdriver logging is enabled for the agent. @@ -131,6 +140,8 @@ class Agent(proto.Message): start_flow = proto.Field(proto.STRING, number=16) + security_settings = proto.Field(proto.STRING, number=17) + enable_stackdriver_logging = proto.Field(proto.BOOL, number=18) enable_spell_correction = proto.Field(proto.BOOL, number=20) @@ -164,7 +175,7 @@ class ListAgentsResponse(proto.Message): [Agents.ListAgents][google.cloud.dialogflow.cx.v3.Agents.ListAgents]. Attributes: - agents (Sequence[~.gcdc_agent.Agent]): + agents (Sequence[google.cloud.dialogflowcx_v3.types.Agent]): The list of agents. There will be a maximum number of items returned based on the page_size field in the request. next_page_token (str): @@ -203,7 +214,7 @@ class CreateAgentRequest(proto.Message): parent (str): Required. The location to create a agent for. Format: ``projects//locations/``. - agent (~.gcdc_agent.Agent): + agent (google.cloud.dialogflowcx_v3.types.Agent): Required. The agent to create. """ @@ -217,9 +228,9 @@ class UpdateAgentRequest(proto.Message): [Agents.UpdateAgent][google.cloud.dialogflow.cx.v3.Agents.UpdateAgent]. Attributes: - agent (~.gcdc_agent.Agent): + agent (google.cloud.dialogflowcx_v3.types.Agent): Required. The agent to update. - update_mask (~.field_mask.FieldMask): + update_mask (google.protobuf.field_mask_pb2.FieldMask): The mask to control which fields get updated. If the mask is not present, all fields will be updated. @@ -306,4 +317,60 @@ class RestoreAgentRequest(proto.Message): agent_content = proto.Field(proto.BYTES, number=3, oneof="agent") +class ValidateAgentRequest(proto.Message): + r"""The request message for + [Agents.ValidateAgent][google.cloud.dialogflow.cx.v3.Agents.ValidateAgent]. + + Attributes: + name (str): + Required. The agent to validate. Format: + ``projects//locations//agents/``. + language_code (str): + If not specified, the agent's default + language is used. + """ + + name = proto.Field(proto.STRING, number=1) + + language_code = proto.Field(proto.STRING, number=2) + + +class GetAgentValidationResultRequest(proto.Message): + r"""The request message for + [Agents.GetAgentValidationResult][google.cloud.dialogflow.cx.v3.Agents.GetAgentValidationResult]. + + Attributes: + name (str): + Required. The agent name. Format: + ``projects//locations//agents//validationResult``. + language_code (str): + If not specified, the agent's default + language is used. + """ + + name = proto.Field(proto.STRING, number=1) + + language_code = proto.Field(proto.STRING, number=2) + + +class AgentValidationResult(proto.Message): + r"""The response message for + [Agents.GetAgentValidationResult][google.cloud.dialogflow.cx.v3.Agents.GetAgentValidationResult]. + + Attributes: + name (str): + The unique identifier of the agent validation result. + Format: + ``projects//locations//agents//validationResult``. + flow_validation_results (Sequence[google.cloud.dialogflowcx_v3.types.FlowValidationResult]): + Contains all flow validation results. + """ + + name = proto.Field(proto.STRING, number=1) + + flow_validation_results = proto.RepeatedField( + proto.MESSAGE, number=2, message=flow.FlowValidationResult, + ) + + __all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/google/cloud/dialogflowcx_v3/types/audio_config.py b/google/cloud/dialogflowcx_v3/types/audio_config.py index 4702c9b6..6b3a01d7 100644 --- a/google/cloud/dialogflowcx_v3/types/audio_config.py +++ b/google/cloud/dialogflowcx_v3/types/audio_config.py @@ -96,12 +96,12 @@ class SpeechWordInfo(proto.Message): Attributes: word (str): The word this info is for. - start_offset (~.duration.Duration): + start_offset (google.protobuf.duration_pb2.Duration): Time offset relative to the beginning of the audio that corresponds to the start of the spoken word. This is an experimental feature and the accuracy of the time offset can vary. - end_offset (~.duration.Duration): + end_offset (google.protobuf.duration_pb2.Duration): Time offset relative to the beginning of the audio that corresponds to the end of the spoken word. This is an experimental feature and the @@ -133,7 +133,7 @@ class InputAudioConfig(proto.Message): content. Attributes: - audio_encoding (~.audio_config.AudioEncoding): + audio_encoding (google.cloud.dialogflowcx_v3.types.AudioEncoding): Required. Audio encoding of the audio content to process. sample_rate_hertz (int): @@ -169,7 +169,7 @@ class InputAudioConfig(proto.Message): `Cloud Speech API documentation `__ for more details. - model_variant (~.audio_config.SpeechModelVariant): + model_variant (google.cloud.dialogflowcx_v3.types.SpeechModelVariant): Optional. Which variant of the [Speech model][google.cloud.dialogflow.cx.v3.InputAudioConfig.model] to use. @@ -208,15 +208,19 @@ class VoiceSelectionParams(proto.Message): will choose a voice based on the other parameters such as language_code and [ssml_gender][google.cloud.dialogflow.cx.v3.VoiceSelectionParams.ssml_gender]. - ssml_gender (~.audio_config.SsmlVoiceGender): + + For the list of available voices, please refer to `Supported + voices and + languages `__. + ssml_gender (google.cloud.dialogflowcx_v3.types.SsmlVoiceGender): Optional. The preferred gender of the voice. If not set, the service will choose a voice based on the other parameters such as language_code and [name][google.cloud.dialogflow.cx.v3.VoiceSelectionParams.name]. Note that this is only a preference, not requirement. If a voice of the appropriate gender is not available, the - synthesizer should substitute a voice with a different - gender rather than failing the request. + synthesizer substitutes a voice with a different gender + rather than failing the request. """ name = proto.Field(proto.STRING, number=1) @@ -255,7 +259,7 @@ class SynthesizeSpeechConfig(proto.Message): synthesized) text to speech. Effects are applied on top of each other in the order they are given. - voice (~.audio_config.VoiceSelectionParams): + voice (google.cloud.dialogflowcx_v3.types.VoiceSelectionParams): Optional. The desired voice of the synthesized audio. """ @@ -276,7 +280,7 @@ class OutputAudioConfig(proto.Message): audio content. Attributes: - audio_encoding (~.audio_config.OutputAudioEncoding): + audio_encoding (google.cloud.dialogflowcx_v3.types.OutputAudioEncoding): Required. Audio encoding of the synthesized audio content. sample_rate_hertz (int): @@ -288,7 +292,7 @@ class OutputAudioConfig(proto.Message): then the synthesizer will honor this request by converting to the desired sample rate (which might result in worse audio quality). - synthesize_speech_config (~.audio_config.SynthesizeSpeechConfig): + synthesize_speech_config (google.cloud.dialogflowcx_v3.types.SynthesizeSpeechConfig): Optional. Configuration of how speech should be synthesized. """ diff --git a/google/cloud/dialogflowcx_v3/types/entity_type.py b/google/cloud/dialogflowcx_v3/types/entity_type.py index 1322111c..a78a4ea4 100644 --- a/google/cloud/dialogflowcx_v3/types/entity_type.py +++ b/google/cloud/dialogflowcx_v3/types/entity_type.py @@ -77,15 +77,15 @@ class EntityType(proto.Message): display_name (str): Required. The human-readable name of the entity type, unique within the agent. - kind (~.gcdc_entity_type.EntityType.Kind): + kind (google.cloud.dialogflowcx_v3.types.EntityType.Kind): Required. Indicates the kind of entity type. - auto_expansion_mode (~.gcdc_entity_type.EntityType.AutoExpansionMode): + auto_expansion_mode (google.cloud.dialogflowcx_v3.types.EntityType.AutoExpansionMode): Indicates whether the entity type can be automatically expanded. - entities (Sequence[~.gcdc_entity_type.EntityType.Entity]): + entities (Sequence[google.cloud.dialogflowcx_v3.types.EntityType.Entity]): The collection of entity entries associated with the entity type. - excluded_phrases (Sequence[~.gcdc_entity_type.EntityType.ExcludedPhrase]): + excluded_phrases (Sequence[google.cloud.dialogflowcx_v3.types.EntityType.ExcludedPhrase]): Collection of exceptional words and phrases that shouldn't be matched. For example, if you have a size entity type with entry ``giant``\ (an adjective), you might consider adding @@ -95,6 +95,12 @@ class EntityType(proto.Message): enable_fuzzy_extraction (bool): Enables fuzzy entity extraction during classification. + redact (bool): + Indicates whether parameters of the entity + type should be redacted in log. If redaction is + enabled, page parameters and intent parameters + referring to the entity type will be replaced by + parameter name when logging. """ class Kind(proto.Enum): @@ -114,7 +120,7 @@ class AutoExpansionMode(proto.Enum): AUTO_EXPANSION_MODE_DEFAULT = 1 class Entity(proto.Message): - r"""An **entity entry** for an associated entity type. Next Id = 8 + r"""An **entity entry** for an associated entity type. Attributes: value (str): @@ -171,6 +177,8 @@ class ExcludedPhrase(proto.Message): enable_fuzzy_extraction = proto.Field(proto.BOOL, number=7) + redact = proto.Field(proto.BOOL, number=9) + class ListEntityTypesRequest(proto.Message): r"""The request message for @@ -190,7 +198,7 @@ class ListEntityTypesRequest(proto.Message): If not specified, the agent's default language is used. `Many - languages `__ + languages `__ are supported. Note: languages must be enabled in the agent before they can be used. page_size (int): @@ -215,7 +223,7 @@ class ListEntityTypesResponse(proto.Message): [EntityTypes.ListEntityTypes][google.cloud.dialogflow.cx.v3.EntityTypes.ListEntityTypes]. Attributes: - entity_types (Sequence[~.gcdc_entity_type.EntityType]): + entity_types (Sequence[google.cloud.dialogflowcx_v3.types.EntityType]): The list of entity types. There will be a maximum number of items returned based on the page_size field in the request. next_page_token (str): @@ -251,7 +259,7 @@ class GetEntityTypeRequest(proto.Message): If not specified, the agent's default language is used. `Many - languages `__ + languages `__ are supported. Note: languages must be enabled in the agent before they can be used. """ @@ -269,7 +277,7 @@ class CreateEntityTypeRequest(proto.Message): parent (str): Required. The agent to create a entity type for. Format: ``projects//locations//agents/``. - entity_type (~.gcdc_entity_type.EntityType): + entity_type (google.cloud.dialogflowcx_v3.types.EntityType): Required. The entity type to create. language_code (str): The language of the following fields in ``entity_type``: @@ -280,7 +288,7 @@ class CreateEntityTypeRequest(proto.Message): If not specified, the agent's default language is used. `Many - languages `__ + languages `__ are supported. Note: languages must be enabled in the agent before they can be used. """ @@ -297,7 +305,7 @@ class UpdateEntityTypeRequest(proto.Message): [EntityTypes.UpdateEntityType][google.cloud.dialogflow.cx.v3.EntityTypes.UpdateEntityType]. Attributes: - entity_type (~.gcdc_entity_type.EntityType): + entity_type (google.cloud.dialogflowcx_v3.types.EntityType): Required. The entity type to update. language_code (str): The language of the following fields in ``entity_type``: @@ -308,10 +316,10 @@ class UpdateEntityTypeRequest(proto.Message): If not specified, the agent's default language is used. `Many - languages `__ + languages `__ are supported. Note: languages must be enabled in the agent before they can be used. - update_mask (~.field_mask.FieldMask): + update_mask (google.protobuf.field_mask_pb2.FieldMask): The mask to control which fields get updated. """ diff --git a/google/cloud/dialogflowcx_v3/types/environment.py b/google/cloud/dialogflowcx_v3/types/environment.py index 7edb1112..1159996f 100644 --- a/google/cloud/dialogflowcx_v3/types/environment.py +++ b/google/cloud/dialogflowcx_v3/types/environment.py @@ -62,12 +62,12 @@ class Environment(proto.Message): environment. The maximum length is 500 characters. If exceeded, the request is rejected. - version_configs (Sequence[~.gcdc_environment.Environment.VersionConfig]): + version_configs (Sequence[google.cloud.dialogflowcx_v3.types.Environment.VersionConfig]): Required. A list of configurations for flow versions. You should include version configs for all flows that are reachable from [``Start Flow``][Agent.start_flow] in the agent. Otherwise, an error will be returned. - update_time (~.timestamp.Timestamp): + update_time (google.protobuf.timestamp_pb2.Timestamp): Output only. Update time of this environment. """ @@ -125,7 +125,7 @@ class ListEnvironmentsResponse(proto.Message): [Environments.ListEnvironments][google.cloud.dialogflow.cx.v3.Environments.ListEnvironments]. Attributes: - environments (Sequence[~.gcdc_environment.Environment]): + environments (Sequence[google.cloud.dialogflowcx_v3.types.Environment]): The list of environments. There will be a maximum number of items returned based on the page_size field in the request. The list may in some cases be empty or contain fewer entries @@ -171,7 +171,7 @@ class CreateEnvironmentRequest(proto.Message): [Environment][google.cloud.dialogflow.cx.v3.Environment] for. Format: ``projects//locations//agents/``. - environment (~.gcdc_environment.Environment): + environment (google.cloud.dialogflowcx_v3.types.Environment): Required. The environment to create. """ @@ -185,9 +185,9 @@ class UpdateEnvironmentRequest(proto.Message): [Environments.UpdateEnvironment][google.cloud.dialogflow.cx.v3.Environments.UpdateEnvironment]. Attributes: - environment (~.gcdc_environment.Environment): + environment (google.cloud.dialogflowcx_v3.types.Environment): Required. The environment to update. - update_mask (~.field_mask.FieldMask): + update_mask (google.protobuf.field_mask_pb2.FieldMask): Required. The mask to control which fields get updated. """ @@ -241,7 +241,7 @@ class LookupEnvironmentHistoryResponse(proto.Message): [Environments.LookupEnvironmentHistory][google.cloud.dialogflow.cx.v3.Environments.LookupEnvironmentHistory]. Attributes: - environments (Sequence[~.gcdc_environment.Environment]): + environments (Sequence[google.cloud.dialogflowcx_v3.types.Environment]): Represents a list of snapshots for an environment. Time of the snapshots is stored in [``update_time``][google.cloud.dialogflow.cx.v3.Environment.update_time]. diff --git a/google/cloud/dialogflowcx_v3/types/experiment.py b/google/cloud/dialogflowcx_v3/types/experiment.py index 6a4bda5d..dd64833c 100644 --- a/google/cloud/dialogflowcx_v3/types/experiment.py +++ b/google/cloud/dialogflowcx_v3/types/experiment.py @@ -43,7 +43,6 @@ class Experiment(proto.Message): r"""Represents an experiment in an environment. - Next ID: 13 Attributes: name (str): @@ -59,28 +58,28 @@ class Experiment(proto.Message): description (str): The human-readable description of the experiment. - state (~.gcdc_experiment.Experiment.State): + state (google.cloud.dialogflowcx_v3.types.Experiment.State): The current state of the experiment. Transition triggered by Expriments.StartExperiment: PENDING->RUNNING. Transition triggered by Expriments.CancelExperiment: PENDING->CANCELLED or RUNNING->CANCELLED. - definition (~.gcdc_experiment.Experiment.Definition): + definition (google.cloud.dialogflowcx_v3.types.Experiment.Definition): The definition of the experiment. - result (~.gcdc_experiment.Experiment.Result): + result (google.cloud.dialogflowcx_v3.types.Experiment.Result): Inference result of the experiment. - create_time (~.timestamp.Timestamp): + create_time (google.protobuf.timestamp_pb2.Timestamp): Creation time of this experiment. - start_time (~.timestamp.Timestamp): + start_time (google.protobuf.timestamp_pb2.Timestamp): Start time of this experiment. - end_time (~.timestamp.Timestamp): + end_time (google.protobuf.timestamp_pb2.Timestamp): End time of this experiment. - last_update_time (~.timestamp.Timestamp): + last_update_time (google.protobuf.timestamp_pb2.Timestamp): Last update time of this experiment. - experiment_length (~.duration.Duration): + experiment_length (google.protobuf.duration_pb2.Duration): Maximum number of days to run the experiment. - variants_history (Sequence[~.gcdc_experiment.VariantsHistory]): + variants_history (Sequence[google.cloud.dialogflowcx_v3.types.VariantsHistory]): The history of updates to the experiment variants. """ @@ -94,7 +93,6 @@ class State(proto.Enum): class Definition(proto.Message): r"""Definition of the experiment. - Next ID: 3 Attributes: condition (str): @@ -103,7 +101,7 @@ class Definition(proto.Message): eligible. E.g. "query_input.language_code=en" See the `conditions reference `__. - version_variants (~.gcdc_experiment.VersionVariants): + version_variants (google.cloud.dialogflowcx_v3.types.VersionVariants): The flow versions as the variants of this experiment. """ @@ -119,16 +117,16 @@ class Result(proto.Message): optimize and the confidence interval. Attributes: - version_metrics (Sequence[~.gcdc_experiment.Experiment.Result.VersionMetrics]): + version_metrics (Sequence[google.cloud.dialogflowcx_v3.types.Experiment.Result.VersionMetrics]): Version variants and metrics. - last_update_time (~.timestamp.Timestamp): + last_update_time (google.protobuf.timestamp_pb2.Timestamp): The last time the experiment's stats data was updated. Will have default value if stats have never been computed for this experiment. """ class MetricType(proto.Enum): - r"""Types of metric for Dialogflow experiment.""" + r"""Types of ratio-based metric for Dialogflow experiment.""" METRIC_UNSPECIFIED = 0 CONTAINED_SESSION_NO_CALLBACK_RATE = 1 LIVE_AGENT_HANDOFF_RATE = 2 @@ -136,6 +134,13 @@ class MetricType(proto.Enum): ABANDONED_SESSION_RATE = 4 SESSION_END_RATE = 5 + class CountType(proto.Enum): + r"""Types of count-based metric for Dialogflow experiment.""" + COUNT_TYPE_UNSPECIFIED = 0 + TOTAL_NO_MATCH_COUNT = 1 + TOTAL_TURN_COUNT = 2 + AVERAGE_TURN_COUNT = 3 + class ConfidenceInterval(proto.Message): r"""A confidence interval is a range of possible values for the experiment objective you are trying to measure. @@ -166,11 +171,17 @@ class Metric(proto.Message): r"""Metric and corresponding confidence intervals. Attributes: - type_ (~.gcdc_experiment.Experiment.Result.MetricType): - The type of the metric. + type_ (google.cloud.dialogflowcx_v3.types.Experiment.Result.MetricType): + Ratio-based metric type. Only one of type or count_type is + specified in each Metric. + count_type (google.cloud.dialogflowcx_v3.types.Experiment.Result.CountType): + Count-based metric type. Only one of type or count_type is + specified in each Metric. ratio (float): Ratio value of a metric. - confidence_interval (~.gcdc_experiment.Experiment.Result.ConfidenceInterval): + count (float): + Count value of a metric. + confidence_interval (google.cloud.dialogflowcx_v3.types.Experiment.Result.ConfidenceInterval): The probability that the treatment is better than all other treatments in the experiment """ @@ -179,8 +190,14 @@ class Metric(proto.Message): proto.ENUM, number=1, enum="Experiment.Result.MetricType", ) + count_type = proto.Field( + proto.ENUM, number=5, enum="Experiment.Result.CountType", + ) + ratio = proto.Field(proto.DOUBLE, number=2, oneof="value") + count = proto.Field(proto.DOUBLE, number=4, oneof="value") + confidence_interval = proto.Field( proto.MESSAGE, number=3, message="Experiment.Result.ConfidenceInterval", ) @@ -193,7 +210,7 @@ class VersionMetrics(proto.Message): The name of the flow [Version][google.cloud.dialogflow.cx.v3.Version]. Format: ``projects//locations//agents//flows//versions/``. - metrics (Sequence[~.gcdc_experiment.Experiment.Result.Metric]): + metrics (Sequence[google.cloud.dialogflowcx_v3.types.Experiment.Result.Metric]): The metrics and corresponding confidence intervals in the inference result. session_count (int): @@ -252,7 +269,7 @@ class VersionVariants(proto.Message): r"""A list of flow version variants. Attributes: - variants (Sequence[~.gcdc_experiment.VersionVariants.Variant]): + variants (Sequence[google.cloud.dialogflowcx_v3.types.VersionVariants.Variant]): A list of flow version variants. """ @@ -284,9 +301,9 @@ class VariantsHistory(proto.Message): r"""The history of variants update. Attributes: - version_variants (~.gcdc_experiment.VersionVariants): + version_variants (google.cloud.dialogflowcx_v3.types.VersionVariants): The flow versions as the variants. - update_time (~.timestamp.Timestamp): + update_time (google.protobuf.timestamp_pb2.Timestamp): Update time of the variants. """ @@ -327,7 +344,7 @@ class ListExperimentsResponse(proto.Message): [Experiments.ListExperiments][google.cloud.dialogflow.cx.v3.Experiments.ListExperiments]. Attributes: - experiments (Sequence[~.gcdc_experiment.Experiment]): + experiments (Sequence[google.cloud.dialogflowcx_v3.types.Experiment]): The list of experiments. There will be a maximum number of items returned based on the page_size field in the request. The list may in some cases be empty or contain fewer entries @@ -373,7 +390,7 @@ class CreateExperimentRequest(proto.Message): [Environment][google.cloud.dialogflow.cx.v3.Environment] for. Format: ``projects//locations//agents//environments/``. - experiment (~.gcdc_experiment.Experiment): + experiment (google.cloud.dialogflowcx_v3.types.Experiment): Required. The experiment to create. """ @@ -387,9 +404,9 @@ class UpdateExperimentRequest(proto.Message): [Experiments.UpdateExperiment][google.cloud.dialogflow.cx.v3.Experiments.UpdateExperiment]. Attributes: - experiment (~.gcdc_experiment.Experiment): + experiment (google.cloud.dialogflowcx_v3.types.Experiment): Required. The experiment to update. - update_mask (~.field_mask.FieldMask): + update_mask (google.protobuf.field_mask_pb2.FieldMask): Required. The mask to control which fields get updated. """ diff --git a/google/cloud/dialogflowcx_v3/types/flow.py b/google/cloud/dialogflowcx_v3/types/flow.py index a49e12d3..391ce448 100644 --- a/google/cloud/dialogflowcx_v3/types/flow.py +++ b/google/cloud/dialogflowcx_v3/types/flow.py @@ -19,7 +19,9 @@ from google.cloud.dialogflowcx_v3.types import page +from google.cloud.dialogflowcx_v3.types import validation_message from google.protobuf import field_mask_pb2 as field_mask # type: ignore +from google.protobuf import timestamp_pb2 as timestamp # type: ignore __protobuf__ = proto.module( @@ -34,6 +36,9 @@ "GetFlowRequest", "UpdateFlowRequest", "TrainFlowRequest", + "ValidateFlowRequest", + "GetFlowValidationResultRequest", + "FlowValidationResult", }, ) @@ -42,7 +47,7 @@ class NluSettings(proto.Message): r"""Settings related to NLU. Attributes: - model_type (~.gcdc_flow.NluSettings.ModelType): + model_type (google.cloud.dialogflowcx_v3.types.NluSettings.ModelType): Indicates the type of NLU model. classification_threshold (float): To filter out false positive results and @@ -54,7 +59,7 @@ class NluSettings(proto.Message): The score values range from 0.0 (completely uncertain) to 1.0 (completely certain). If set to 0.0, the default of 0.3 is used. - model_training_mode (~.gcdc_flow.NluSettings.ModelTrainingMode): + model_training_mode (google.cloud.dialogflowcx_v3.types.NluSettings.ModelTrainingMode): Indicates NLU model training mode. """ @@ -106,7 +111,7 @@ class Flow(proto.Message): The description of the flow. The maximum length is 500 characters. If exceeded, the request is rejected. - transition_routes (Sequence[~.page.TransitionRoute]): + transition_routes (Sequence[google.cloud.dialogflowcx_v3.types.TransitionRoute]): A flow's transition routes serve two purposes: - They are responsible for matching the user's first @@ -125,7 +130,7 @@ class Flow(proto.Message): TransitionRoutes with intent specified are inherited by pages in the flow. - event_handlers (Sequence[~.page.EventHandler]): + event_handlers (Sequence[google.cloud.dialogflowcx_v3.types.EventHandler]): A flow's event handlers serve two purposes: - They are responsible for handling events (e.g. no match, @@ -141,7 +146,7 @@ class Flow(proto.Message): these handlers are evaluated on a first-match basis. The first one that matches the event get executed, with the rest being ignored. - nlu_settings (~.gcdc_flow.NluSettings): + nlu_settings (google.cloud.dialogflowcx_v3.types.NluSettings): NLU related settings of the flow. """ @@ -170,7 +175,7 @@ class CreateFlowRequest(proto.Message): parent (str): Required. The agent to create a flow for. Format: ``projects//locations//agents/``. - flow (~.gcdc_flow.Flow): + flow (google.cloud.dialogflowcx_v3.types.Flow): Required. The flow to create. language_code (str): The language of the following fields in ``flow``: @@ -180,7 +185,7 @@ class CreateFlowRequest(proto.Message): If not specified, the agent's default language is used. `Many - languages `__ + languages `__ are supported. Note: languages must be enabled in the agent before they can be used. """ @@ -242,7 +247,7 @@ class ListFlowsRequest(proto.Message): If not specified, the agent's default language is used. `Many - languages `__ + languages `__ are supported. Note: languages must be enabled in the agent before they can be used. """ @@ -261,7 +266,7 @@ class ListFlowsResponse(proto.Message): [Flows.ListFlows][google.cloud.dialogflow.cx.v3.Flows.ListFlows]. Attributes: - flows (Sequence[~.gcdc_flow.Flow]): + flows (Sequence[google.cloud.dialogflowcx_v3.types.Flow]): The list of flows. There will be a maximum number of items returned based on the page_size field in the request. next_page_token (str): @@ -296,7 +301,7 @@ class GetFlowRequest(proto.Message): If not specified, the agent's default language is used. `Many - languages `__ + languages `__ are supported. Note: languages must be enabled in the agent before they can be used. """ @@ -311,9 +316,9 @@ class UpdateFlowRequest(proto.Message): [Flows.UpdateFlow][google.cloud.dialogflow.cx.v3.Flows.UpdateFlow]. Attributes: - flow (~.gcdc_flow.Flow): + flow (google.cloud.dialogflowcx_v3.types.Flow): Required. The flow to update. - update_mask (~.field_mask.FieldMask): + update_mask (google.protobuf.field_mask_pb2.FieldMask): Required. The mask to control which fields get updated. If ``update_mask`` is not specified, an error will be returned. language_code (str): @@ -324,7 +329,7 @@ class UpdateFlowRequest(proto.Message): If not specified, the agent's default language is used. `Many - languages `__ + languages `__ are supported. Note: languages must be enabled in the agent before they can be used. """ @@ -349,4 +354,63 @@ class TrainFlowRequest(proto.Message): name = proto.Field(proto.STRING, number=1) +class ValidateFlowRequest(proto.Message): + r"""The request message for + [Flows.ValidateFlow][google.cloud.dialogflow.cx.v3.Flows.ValidateFlow]. + + Attributes: + name (str): + Required. The flow to validate. Format: + ``projects//locations//agents//flows/``. + language_code (str): + If not specified, the agent's default + language is used. + """ + + name = proto.Field(proto.STRING, number=1) + + language_code = proto.Field(proto.STRING, number=2) + + +class GetFlowValidationResultRequest(proto.Message): + r"""The request message for + [Flows.GetFlowValidationResult][google.cloud.dialogflow.cx.v3.Flows.GetFlowValidationResult]. + + Attributes: + name (str): + Required. The flow name. Format: + ``projects//locations//agents//flows//validationResult``. + language_code (str): + If not specified, the agent's default + language is used. + """ + + name = proto.Field(proto.STRING, number=1) + + language_code = proto.Field(proto.STRING, number=2) + + +class FlowValidationResult(proto.Message): + r"""The response message for + [Flows.GetFlowValidationResult][google.cloud.dialogflow.cx.v3.Flows.GetFlowValidationResult]. + + Attributes: + name (str): + The unique identifier of the flow validation result. Format: + ``projects//locations//agents//flows//validationResult``. + validation_messages (Sequence[google.cloud.dialogflowcx_v3.types.ValidationMessage]): + Contains all validation messages. + update_time (google.protobuf.timestamp_pb2.Timestamp): + Last time the flow was validated. + """ + + name = proto.Field(proto.STRING, number=1) + + validation_messages = proto.RepeatedField( + proto.MESSAGE, number=2, message=validation_message.ValidationMessage, + ) + + update_time = proto.Field(proto.MESSAGE, number=3, message=timestamp.Timestamp,) + + __all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/google/cloud/dialogflowcx_v3/types/fulfillment.py b/google/cloud/dialogflowcx_v3/types/fulfillment.py index 288dab10..c0a3267e 100644 --- a/google/cloud/dialogflowcx_v3/types/fulfillment.py +++ b/google/cloud/dialogflowcx_v3/types/fulfillment.py @@ -49,7 +49,7 @@ class Fulfillment(proto.Message): or both. Attributes: - messages (Sequence[~.response_message.ResponseMessage]): + messages (Sequence[google.cloud.dialogflowcx_v3.types.ResponseMessage]): The list of rich message responses to present to the user. webhook (str): @@ -59,10 +59,10 @@ class Fulfillment(proto.Message): The tag used by the webhook to identify which fulfillment is being called. This field is required if ``webhook`` is specified. - set_parameter_actions (Sequence[~.fulfillment.Fulfillment.SetParameterAction]): + set_parameter_actions (Sequence[google.cloud.dialogflowcx_v3.types.Fulfillment.SetParameterAction]): Set parameter values before executing the webhook. - conditional_cases (Sequence[~.fulfillment.Fulfillment.ConditionalCases]): + conditional_cases (Sequence[google.cloud.dialogflowcx_v3.types.Fulfillment.ConditionalCases]): Conditional cases for this fulfillment. """ @@ -72,7 +72,7 @@ class SetParameterAction(proto.Message): Attributes: parameter (str): Display name of the parameter. - value (~.struct.Value): + value (google.protobuf.struct_pb2.Value): The new value of the parameter. A null value clears the parameter. """ @@ -87,7 +87,7 @@ class ConditionalCases(proto.Message): all the rest ignored. Attributes: - cases (Sequence[~.fulfillment.Fulfillment.ConditionalCases.Case]): + cases (Sequence[google.cloud.dialogflowcx_v3.types.Fulfillment.ConditionalCases.Case]): A list of cascading if-else conditions. """ @@ -105,7 +105,7 @@ class Case(proto.Message): See the `conditions reference `__. - case_content (Sequence[~.fulfillment.Fulfillment.ConditionalCases.Case.CaseContent]): + case_content (Sequence[google.cloud.dialogflowcx_v3.types.Fulfillment.ConditionalCases.Case.CaseContent]): A list of case content. """ @@ -114,9 +114,9 @@ class CaseContent(proto.Message): this case. Attributes: - message (~.response_message.ResponseMessage): + message (google.cloud.dialogflowcx_v3.types.ResponseMessage): Returned message. - additional_cases (~.fulfillment.Fulfillment.ConditionalCases): + additional_cases (google.cloud.dialogflowcx_v3.types.Fulfillment.ConditionalCases): Additional cases to be evaluated. """ diff --git a/google/cloud/dialogflowcx_v3/types/intent.py b/google/cloud/dialogflowcx_v3/types/intent.py index 446cbb1b..204013f7 100644 --- a/google/cloud/dialogflowcx_v3/types/intent.py +++ b/google/cloud/dialogflowcx_v3/types/intent.py @@ -65,10 +65,10 @@ class Intent(proto.Message): display_name (str): Required. The human-readable name of the intent, unique within the agent. - training_phrases (Sequence[~.gcdc_intent.Intent.TrainingPhrase]): + training_phrases (Sequence[google.cloud.dialogflowcx_v3.types.Intent.TrainingPhrase]): The collection of training phrases the agent is trained on to identify the intent. - parameters (Sequence[~.gcdc_intent.Intent.Parameter]): + parameters (Sequence[google.cloud.dialogflowcx_v3.types.Intent.Parameter]): The collection of parameters associated with the intent. priority (int): @@ -90,7 +90,7 @@ class Intent(proto.Message): mistakenly matched, since training phrases assigned to fallback intents act as negative examples that triggers no-match event. - labels (Sequence[~.gcdc_intent.Intent.LabelsEntry]): + labels (Sequence[google.cloud.dialogflowcx_v3.types.Intent.LabelsEntry]): Optional. The key/value metadata to label an intent. Labels can contain lowercase letters, digits and the symbols '-' and '_'. International characters are allowed, including @@ -120,7 +120,7 @@ class TrainingPhrase(proto.Message): id (str): Output only. The unique identifier of the training phrase. - parts (Sequence[~.gcdc_intent.Intent.TrainingPhrase.Part]): + parts (Sequence[google.cloud.dialogflowcx_v3.types.Intent.TrainingPhrase.Part]): Required. The ordered list of training phrase parts. The parts are concatenated in order to form the training phrase. @@ -197,11 +197,13 @@ class Parameter(proto.Message): Indicates whether the parameter represents a list of values. redact (bool): - Indicates whether the parameter content is - logged in text and audio. If it is set to true, - the parameter content will be replaced to - parameter id in both request and response. The - default value is false. + Indicates whether the parameter content should be redacted + in log. If redaction is enabled, the parameter content will + be replaced by parameter name during logging. Note: the + parameter content is subject to redaction if either + parameter level redaction or [entity type level + redaction][google.cloud.dialogflow.cx.v3.EntityType.redact] + is enabled. """ id = proto.Field(proto.STRING, number=1) @@ -247,10 +249,10 @@ class ListIntentsRequest(proto.Message): If not specified, the agent's default language is used. `Many - languages `__ + languages `__ are supported. Note: languages must be enabled in the agent before they can be used. - intent_view (~.gcdc_intent.IntentView): + intent_view (google.cloud.dialogflowcx_v3.types.IntentView): The resource view to apply to the returned intent. page_size (int): @@ -277,7 +279,7 @@ class ListIntentsResponse(proto.Message): [Intents.ListIntents][google.cloud.dialogflow.cx.v3.Intents.ListIntents]. Attributes: - intents (Sequence[~.gcdc_intent.Intent]): + intents (Sequence[google.cloud.dialogflowcx_v3.types.Intent]): The list of intents. There will be a maximum number of items returned based on the page_size field in the request. next_page_token (str): @@ -311,7 +313,7 @@ class GetIntentRequest(proto.Message): If not specified, the agent's default language is used. `Many - languages `__ + languages `__ are supported. Note: languages must be enabled in the agent before they can be used. """ @@ -329,7 +331,7 @@ class CreateIntentRequest(proto.Message): parent (str): Required. The agent to create an intent for. Format: ``projects//locations//agents/``. - intent (~.gcdc_intent.Intent): + intent (google.cloud.dialogflowcx_v3.types.Intent): Required. The intent to create. language_code (str): The language of the following fields in ``intent``: @@ -338,7 +340,7 @@ class CreateIntentRequest(proto.Message): If not specified, the agent's default language is used. `Many - languages `__ + languages `__ are supported. Note: languages must be enabled in the agent before they can be used. """ @@ -355,7 +357,7 @@ class UpdateIntentRequest(proto.Message): [Intents.UpdateIntent][google.cloud.dialogflow.cx.v3.Intents.UpdateIntent]. Attributes: - intent (~.gcdc_intent.Intent): + intent (google.cloud.dialogflowcx_v3.types.Intent): Required. The intent to update. language_code (str): The language of the following fields in ``intent``: @@ -364,10 +366,10 @@ class UpdateIntentRequest(proto.Message): If not specified, the agent's default language is used. `Many - languages `__ + languages `__ are supported. Note: languages must be enabled in the agent before they can be used. - update_mask (~.field_mask.FieldMask): + update_mask (google.protobuf.field_mask_pb2.FieldMask): The mask to control which fields get updated. If the mask is not present, all fields will be updated. diff --git a/google/cloud/dialogflowcx_v3/types/page.py b/google/cloud/dialogflowcx_v3/types/page.py index a80b950e..64440566 100644 --- a/google/cloud/dialogflowcx_v3/types/page.py +++ b/google/cloud/dialogflowcx_v3/types/page.py @@ -72,10 +72,10 @@ class Page(proto.Message): display_name (str): Required. The human-readable name of the page, unique within the agent. - entry_fulfillment (~.fulfillment.Fulfillment): + entry_fulfillment (google.cloud.dialogflowcx_v3.types.Fulfillment): The fulfillment to call when the session is entering the page. - form (~.gcdc_page.Form): + form (google.cloud.dialogflowcx_v3.types.Form): The form associated with the page, used for collecting parameters relevant to the page. transition_route_groups (Sequence[str]): @@ -94,7 +94,7 @@ class Page(proto.Message): takes precedence. Format:\ ``projects//locations//agents//flows//transitionRouteGroups/``. - transition_routes (Sequence[~.gcdc_page.TransitionRoute]): + transition_routes (Sequence[google.cloud.dialogflowcx_v3.types.TransitionRoute]): A list of transitions for the transition rules of this page. They route the conversation to another page in the same flow, or another flow. @@ -105,11 +105,18 @@ class Page(proto.Message): - TransitionRoutes defined in the page with intent specified. - TransitionRoutes defined in the [transition route - groups][google.cloud.dialogflow.cx.v3.Page.transition_route_groups]. + groups][google.cloud.dialogflow.cx.v3.Page.transition_route_groups] + with intent specified. - TransitionRoutes defined in flow with intent specified. + - TransitionRoutes defined in the [transition route + groups][google.cloud.dialogflow.cx.v3.Flow.transition_route_groups] + with intent specified. - TransitionRoutes defined in the page with only condition specified. - event_handlers (Sequence[~.gcdc_page.EventHandler]): + - TransitionRoutes defined in the [transition route + groups][google.cloud.dialogflow.cx.v3.Page.transition_route_groups] + with only condition specified. + event_handlers (Sequence[google.cloud.dialogflowcx_v3.types.EventHandler]): Handlers associated with the page to handle events such as webhook errors, no match or no input. @@ -146,7 +153,7 @@ class Form(proto.Message): [session][google.cloud.dialogflow.cx.v3.SessionInfo.parameters]. Attributes: - parameters (Sequence[~.gcdc_page.Form.Parameter]): + parameters (Sequence[google.cloud.dialogflowcx_v3.types.Form.Parameter]): Parameters to collect from the user. """ @@ -174,19 +181,21 @@ class Parameter(proto.Message): is_list (bool): Indicates whether the parameter represents a list of values. - fill_behavior (~.gcdc_page.Form.Parameter.FillBehavior): + fill_behavior (google.cloud.dialogflowcx_v3.types.Form.Parameter.FillBehavior): Required. Defines fill behavior for the parameter. - default_value (~.struct.Value): + default_value (google.protobuf.struct_pb2.Value): The default value of an optional parameter. If the parameter is required, the default value will be ignored. redact (bool): - Indicates whether the parameter content is - logged in text and audio. If it is set to true, - the parameter content will be replaced to - parameter name in both request and response. The - default value is false. + Indicates whether the parameter content should be redacted + in log. If redaction is enabled, the parameter content will + be replaced by parameter name during logging. Note: the + parameter content is subject to redaction if either + parameter level redaction or [entity type level + redaction][google.cloud.dialogflow.cx.v3.EntityType.redact] + is enabled. """ class FillBehavior(proto.Message): @@ -194,11 +203,11 @@ class FillBehavior(proto.Message): handled. Attributes: - initial_prompt_fulfillment (~.fulfillment.Fulfillment): + initial_prompt_fulfillment (google.cloud.dialogflowcx_v3.types.Fulfillment): Required. The fulfillment to provide the initial prompt that the agent can present to the user in order to fill the parameter. - reprompt_event_handlers (Sequence[~.gcdc_page.EventHandler]): + reprompt_event_handlers (Sequence[google.cloud.dialogflowcx_v3.types.EventHandler]): The handlers for parameter-level events, used to provide reprompt for the parameter or transition to a different page/flow. The supported events are: @@ -289,7 +298,7 @@ class EventHandler(proto.Message): event handler. event (str): Required. The name of the event to handle. - trigger_fulfillment (~.fulfillment.Fulfillment): + trigger_fulfillment (google.cloud.dialogflowcx_v3.types.Fulfillment): The fulfillment to call when the event occurs. Handling webhook errors with a fulfillment enabled with webhook could cause @@ -360,7 +369,7 @@ class TransitionRoute(proto.Message): specified. When both ``intent`` and ``condition`` are specified, the transition can only happen when both are fulfilled. - trigger_fulfillment (~.fulfillment.Fulfillment): + trigger_fulfillment (google.cloud.dialogflowcx_v3.types.Fulfillment): The fulfillment to call when the condition is satisfied. At least one of ``trigger_fulfillment`` and ``target`` must be specified. When both are defined, ``trigger_fulfillment`` is @@ -410,7 +419,7 @@ class ListPagesRequest(proto.Message): If not specified, the agent's default language is used. `Many - languages `__ + languages `__ are supported. Note: languages must be enabled in the agent before they can be used. page_size (int): @@ -435,7 +444,7 @@ class ListPagesResponse(proto.Message): [Pages.ListPages][google.cloud.dialogflow.cx.v3.Pages.ListPages]. Attributes: - pages (Sequence[~.gcdc_page.Page]): + pages (Sequence[google.cloud.dialogflowcx_v3.types.Page]): The list of pages. There will be a maximum number of items returned based on the page_size field in the request. next_page_token (str): @@ -475,7 +484,7 @@ class GetPageRequest(proto.Message): If not specified, the agent's default language is used. `Many - languages `__ + languages `__ are supported. Note: languages must be enabled in the agent before they can be used. """ @@ -493,7 +502,7 @@ class CreatePageRequest(proto.Message): parent (str): Required. The flow to create a page for. Format: ``projects//locations//agents//flows/``. - page (~.gcdc_page.Page): + page (google.cloud.dialogflowcx_v3.types.Page): Required. The page to create. language_code (str): The language of the following fields in ``page``: @@ -508,7 +517,7 @@ class CreatePageRequest(proto.Message): If not specified, the agent's default language is used. `Many - languages `__ + languages `__ are supported. Note: languages must be enabled in the agent before they can be used. """ @@ -525,7 +534,7 @@ class UpdatePageRequest(proto.Message): [Pages.UpdatePage][google.cloud.dialogflow.cx.v3.Pages.UpdatePage]. Attributes: - page (~.gcdc_page.Page): + page (google.cloud.dialogflowcx_v3.types.Page): Required. The page to update. language_code (str): The language of the following fields in ``page``: @@ -540,10 +549,10 @@ class UpdatePageRequest(proto.Message): If not specified, the agent's default language is used. `Many - languages `__ + languages `__ are supported. Note: languages must be enabled in the agent before they can be used. - update_mask (~.field_mask.FieldMask): + update_mask (google.protobuf.field_mask_pb2.FieldMask): The mask to control which fields get updated. If the mask is not present, all fields will be updated. diff --git a/google/cloud/dialogflowcx_v3/types/response_message.py b/google/cloud/dialogflowcx_v3/types/response_message.py index 837621e0..9b346bd2 100644 --- a/google/cloud/dialogflowcx_v3/types/response_message.py +++ b/google/cloud/dialogflowcx_v3/types/response_message.py @@ -49,34 +49,36 @@ class ResponseMessage(proto.Message): is heard. Attributes: - text (~.response_message.ResponseMessage.Text): + text (google.cloud.dialogflowcx_v3.types.ResponseMessage.Text): Returns a text response. - payload (~.struct.Struct): + payload (google.protobuf.struct_pb2.Struct): Returns a response containing a custom, platform-specific payload. - conversation_success (~.response_message.ResponseMessage.ConversationSuccess): + conversation_success (google.cloud.dialogflowcx_v3.types.ResponseMessage.ConversationSuccess): Indicates that the conversation succeeded. - output_audio_text (~.response_message.ResponseMessage.OutputAudioText): + output_audio_text (google.cloud.dialogflowcx_v3.types.ResponseMessage.OutputAudioText): A text or ssml response that is preferentially used for TTS output audio synthesis, as described in the comment on the ResponseMessage message. - live_agent_handoff (~.response_message.ResponseMessage.LiveAgentHandoff): + live_agent_handoff (google.cloud.dialogflowcx_v3.types.ResponseMessage.LiveAgentHandoff): Hands off conversation to a human agent. - end_interaction (~.response_message.ResponseMessage.EndInteraction): + end_interaction (google.cloud.dialogflowcx_v3.types.ResponseMessage.EndInteraction): Output only. A signal that indicates the interaction with the Dialogflow agent has ended. This message is generated by Dialogflow only when the conversation reaches - ``END_SESSION`` or ``END_PAGE`` page. It is not supposed to - be defined by the user. It's guaranteed that there is at - most one such message in each response. - play_audio (~.response_message.ResponseMessage.PlayAudio): + ``END_SESSION`` page. It is not supposed to be defined by + the user. + + It's guaranteed that there is at most one such message in + each response. + play_audio (google.cloud.dialogflowcx_v3.types.ResponseMessage.PlayAudio): Signal that the client should play an audio clip hosted at a client-specific URI. Dialogflow uses this to construct [mixed_audio][google.cloud.dialogflow.cx.v3.ResponseMessage.mixed_audio]. However, Dialogflow itself does not try to read or process the URI in any way. - mixed_audio (~.response_message.ResponseMessage.MixedAudio): + mixed_audio (google.cloud.dialogflowcx_v3.types.ResponseMessage.MixedAudio): Output only. An audio response message composed of both the synthesized Dialogflow agent responses and responses defined via @@ -121,7 +123,7 @@ class LiveAgentHandoff(proto.Message): can only be handled by a human. Attributes: - metadata (~.struct.Struct): + metadata (google.protobuf.struct_pb2.Struct): Custom metadata for your handoff procedure. Dialogflow doesn't impose any structure on this. """ @@ -149,7 +151,7 @@ class ConversationSuccess(proto.Message): customer issue. Attributes: - metadata (~.struct.Struct): + metadata (google.protobuf.struct_pb2.Struct): Custom metadata. Dialogflow doesn't impose any structure on this. """ @@ -216,7 +218,7 @@ class MixedAudio(proto.Message): defined by the user. Attributes: - segments (Sequence[~.response_message.ResponseMessage.MixedAudio.Segment]): + segments (Sequence[google.cloud.dialogflowcx_v3.types.ResponseMessage.MixedAudio.Segment]): Segments this audio response is composed of. """ diff --git a/google/cloud/dialogflowcx_v3/types/security_settings.py b/google/cloud/dialogflowcx_v3/types/security_settings.py index 8645b0ed..a029b2f6 100644 --- a/google/cloud/dialogflowcx_v3/types/security_settings.py +++ b/google/cloud/dialogflowcx_v3/types/security_settings.py @@ -53,10 +53,10 @@ class UpdateSecuritySettingsRequest(proto.Message): [SecuritySettingsService.UpdateSecuritySettings][google.cloud.dialogflow.cx.v3.SecuritySettingsService.UpdateSecuritySettings]. Attributes: - security_settings (~.gcdc_security_settings.SecuritySettings): + security_settings (google.cloud.dialogflowcx_v3.types.SecuritySettings): Required. [SecuritySettings] object that contains values for each of the fields to update. - update_mask (~.field_mask.FieldMask): + update_mask (google.protobuf.field_mask_pb2.FieldMask): Required. The mask to control which fields get updated. If the mask is not present, all fields will be updated. @@ -95,7 +95,7 @@ class ListSecuritySettingsResponse(proto.Message): r"""The response message for [SecuritySettings.ListSecuritySettings][]. Attributes: - security_settings (Sequence[~.gcdc_security_settings.SecuritySettings]): + security_settings (Sequence[google.cloud.dialogflowcx_v3.types.SecuritySettings]): The list of security settings. next_page_token (str): Token to retrieve the next page of results, @@ -123,7 +123,7 @@ class CreateSecuritySettingsRequest(proto.Message): [SecuritySettings][google.cloud.dialogflow.cx.v3.SecuritySettings] for. Format: ``projects//locations/``. - security_settings (~.gcdc_security_settings.SecuritySettings): + security_settings (google.cloud.dialogflowcx_v3.types.SecuritySettings): Required. The security settings to create. """ @@ -161,9 +161,9 @@ class SecuritySettings(proto.Message): display_name (str): Required. The human-readable name of the security settings, unique within the location. - redaction_strategy (~.gcdc_security_settings.SecuritySettings.RedactionStrategy): + redaction_strategy (google.cloud.dialogflowcx_v3.types.SecuritySettings.RedactionStrategy): Strategy that defines how we do redaction. - redaction_scope (~.gcdc_security_settings.SecuritySettings.RedactionScope): + redaction_scope (google.cloud.dialogflowcx_v3.types.SecuritySettings.RedactionScope): Defines on what data we apply redaction. Note that we don't redact data to which we don't have access, e.g., Stackdriver logs. @@ -183,7 +183,7 @@ class SecuritySettings(proto.Message): higher than that has no effect. A missing value or setting to 0 also means we use Dialogflow's default TTL. - purge_data_types (Sequence[~.gcdc_security_settings.SecuritySettings.PurgeDataType]): + purge_data_types (Sequence[google.cloud.dialogflowcx_v3.types.SecuritySettings.PurgeDataType]): List of types of data to remove when retention settings triggers purge. """ diff --git a/google/cloud/dialogflowcx_v3/types/session.py b/google/cloud/dialogflowcx_v3/types/session.py index b0876d07..e452a707 100644 --- a/google/cloud/dialogflowcx_v3/types/session.py +++ b/google/cloud/dialogflowcx_v3/types/session.py @@ -77,11 +77,11 @@ class DetectIntentRequest(proto.Message): Note: Always use agent versions for production traffic. See `Versions and environments `__. - query_params (~.gcdc_session.QueryParameters): + query_params (google.cloud.dialogflowcx_v3.types.QueryParameters): The parameters of this query. - query_input (~.gcdc_session.QueryInput): + query_input (google.cloud.dialogflowcx_v3.types.QueryInput): Required. The input specification. - output_audio_config (~.audio_config.OutputAudioConfig): + output_audio_config (google.cloud.dialogflowcx_v3.types.OutputAudioConfig): Instructs the speech synthesizer how to generate the output audio. """ @@ -106,7 +106,7 @@ class DetectIntentResponse(proto.Message): response. It can be used to locate a response in the training example set or for reporting issues. - query_result (~.gcdc_session.QueryResult): + query_result (google.cloud.dialogflowcx_v3.types.QueryResult): The result of the conversational query. output_audio (bytes): The audio data bytes encoded as specified in the request. @@ -121,7 +121,7 @@ class DetectIntentResponse(proto.Message): In some scenarios, multiple output audio fields may be present in the response structure. In these cases, only the top-most-level audio output has content. - output_audio_config (~.audio_config.OutputAudioConfig): + output_audio_config (google.cloud.dialogflowcx_v3.types.OutputAudioConfig): The config used by the speech synthesizer to generate the output audio. """ @@ -193,11 +193,11 @@ class StreamingDetectIntentRequest(proto.Message): Note: Always use agent versions for production traffic. See `Versions and environments `__. - query_params (~.gcdc_session.QueryParameters): + query_params (google.cloud.dialogflowcx_v3.types.QueryParameters): The parameters of this query. - query_input (~.gcdc_session.QueryInput): + query_input (google.cloud.dialogflowcx_v3.types.QueryInput): Required. The input specification. - output_audio_config (~.audio_config.OutputAudioConfig): + output_audio_config (google.cloud.dialogflowcx_v3.types.OutputAudioConfig): Instructs the speech synthesizer how to generate the output audio. """ @@ -228,9 +228,9 @@ class StreamingDetectIntentResponse(proto.Message): 2. The last message contains ``detect_intent_response``. Attributes: - recognition_result (~.gcdc_session.StreamingRecognitionResult): + recognition_result (google.cloud.dialogflowcx_v3.types.StreamingRecognitionResult): The result of speech recognition. - detect_intent_response (~.gcdc_session.DetectIntentResponse): + detect_intent_response (google.cloud.dialogflowcx_v3.types.DetectIntentResponse): The response from detect intent. """ @@ -277,7 +277,7 @@ class StreamingRecognitionResult(proto.Message): - for ``END_OF_SINGLE_UTTERANCE``: only ``message_type``. Attributes: - message_type (~.gcdc_session.StreamingRecognitionResult.MessageType): + message_type (google.cloud.dialogflowcx_v3.types.StreamingRecognitionResult.MessageType): Type of the result message. transcript (str): Transcript text representing the words that the user spoke. @@ -309,13 +309,13 @@ class StreamingRecognitionResult(proto.Message): ``is_final = false``. - Otherwise, the value is in (0.0, 1.0] where 0.0 means completely unstable and 1.0 means completely stable. - speech_word_info (Sequence[~.audio_config.SpeechWordInfo]): + speech_word_info (Sequence[google.cloud.dialogflowcx_v3.types.SpeechWordInfo]): Word-specific information for the words recognized by Speech in [transcript][google.cloud.dialogflow.cx.v3.StreamingRecognitionResult.transcript]. Populated if and only if ``message_type`` = ``TRANSCRIPT`` and [InputAudioConfig.enable_word_info] is set. - speech_end_offset (~.duration.Duration): + speech_end_offset (google.protobuf.duration_pb2.Duration): Time offset of the end of this Speech recognition result relative to the beginning of the audio. Only populated for ``message_type`` = ``TRANSCRIPT``. @@ -353,19 +353,19 @@ class QueryParameters(proto.Message): zone database `__, e.g., America/New_York, Europe/Paris. If not provided, the time zone specified in the agent is used. - geo_location (~.latlng.LatLng): + geo_location (google.type.latlng_pb2.LatLng): The geo location of this conversational query. - session_entity_types (Sequence[~.session_entity_type.SessionEntityType]): + session_entity_types (Sequence[google.cloud.dialogflowcx_v3.types.SessionEntityType]): Additional session entity types to replace or extend developer entity types with. The entity synonyms apply to all languages and persist for the session of this query. - payload (~.struct.Struct): + payload (google.protobuf.struct_pb2.Struct): This field can be used to pass custom data into the webhook associated with the agent. Arbitrary JSON objects are supported. - parameters (~.struct.Struct): + parameters (google.protobuf.struct_pb2.Struct): Additional parameters to be put into [session parameters][SessionInfo.parameters]. To remove a parameter from the session, clients should explicitly set the @@ -390,11 +390,14 @@ class QueryParameters(proto.Message): from composite entity property names to property values - Else: parameter value + disable_webhook (bool): + Whether to disable webhook calls for this + request. analyze_query_text_sentiment (bool): Configures whether sentiment analysis should be performed. If not provided, sentiment analysis is not performed. - webhook_headers (Sequence[~.gcdc_session.QueryParameters.WebhookHeadersEntry]): + webhook_headers (Sequence[google.cloud.dialogflowcx_v3.types.QueryParameters.WebhookHeadersEntry]): This field can be used to pass HTTP headers for a webhook call. These headers will be sent to webhook along with the headers that have been @@ -421,6 +424,8 @@ class QueryParameters(proto.Message): parameters = proto.Field(proto.MESSAGE, number=5, message=struct.Struct,) + disable_webhook = proto.Field(proto.BOOL, number=7) + analyze_query_text_sentiment = proto.Field(proto.BOOL, number=8) webhook_headers = proto.MapField(proto.STRING, proto.STRING, number=10) @@ -436,20 +441,20 @@ class QueryInput(proto.Message): 4. An event to be triggered. Attributes: - text (~.gcdc_session.TextInput): + text (google.cloud.dialogflowcx_v3.types.TextInput): The natural language text to be processed. - intent (~.gcdc_session.IntentInput): + intent (google.cloud.dialogflowcx_v3.types.IntentInput): The intent to be triggered. - audio (~.gcdc_session.AudioInput): + audio (google.cloud.dialogflowcx_v3.types.AudioInput): The natural language speech audio to be processed. - event (~.gcdc_session.EventInput): + event (google.cloud.dialogflowcx_v3.types.EventInput): The event to be triggered. - dtmf (~.gcdc_session.DtmfInput): + dtmf (google.cloud.dialogflowcx_v3.types.DtmfInput): The DTMF event to be handled. language_code (str): Required. The language of the input. See `Language - Support `__ + Support `__ for a list of the currently supported language codes. Note that queries in the same session do not necessarily need to specify the same language. @@ -492,9 +497,9 @@ class QueryResult(proto.Message): language_code (str): The language that was triggered during intent detection. See `Language - Support `__ + Support `__ for a list of the currently supported language codes. - parameters (~.struct.Struct): + parameters (google.protobuf.struct_pb2.Struct): The collected [session parameters][google.cloud.dialogflow.cx.v3.SessionInfo.parameters]. @@ -517,25 +522,25 @@ class QueryResult(proto.Message): from composite entity property names to property values - Else: parameter value - response_messages (Sequence[~.response_message.ResponseMessage]): + response_messages (Sequence[google.cloud.dialogflowcx_v3.types.ResponseMessage]): The list of rich messages returned to the client. Responses vary from simple text messages to more sophisticated, structured payloads used to drive complex logic. - webhook_statuses (Sequence[~.status.Status]): + webhook_statuses (Sequence[google.rpc.status_pb2.Status]): The list of webhook call status in the order of call sequence. - webhook_payloads (Sequence[~.struct.Struct]): + webhook_payloads (Sequence[google.protobuf.struct_pb2.Struct]): The list of webhook payload in [WebhookResponse.payload][google.cloud.dialogflow.cx.v3.WebhookResponse.payload], in the order of call sequence. If some webhook call fails or doesn't return any payload, an empty ``Struct`` would be used instead. - current_page (~.page.Page): + current_page (google.cloud.dialogflowcx_v3.types.Page): The current [Page][google.cloud.dialogflow.cx.v3.Page]. Some, not all fields are filled in this message, including but not limited to ``name`` and ``display_name``. - intent (~.gcdc_intent.Intent): + intent (google.cloud.dialogflowcx_v3.types.Intent): The [Intent][google.cloud.dialogflow.cx.v3.Intent] that matched the conversational query. Some, not all fields are filled in this message, including but not limited to: @@ -553,15 +558,15 @@ class QueryResult(proto.Message): in implementation. This field is deprecated, please use [QueryResult.match][google.cloud.dialogflow.cx.v3.QueryResult.match] instead. - match (~.gcdc_session.Match): + match (google.cloud.dialogflowcx_v3.types.Match): Intent match result, could be an intent or an event. - diagnostic_info (~.struct.Struct): + diagnostic_info (google.protobuf.struct_pb2.Struct): The free-form diagnostic info. For example, this field could contain webhook call latency. The string keys of the Struct's fields map can change without notice. - sentiment_analysis_result (~.gcdc_session.SentimentAnalysisResult): + sentiment_analysis_result (google.cloud.dialogflowcx_v3.types.SentimentAnalysisResult): The sentiment analyss result, which depends on [``analyze_query_text_sentiment``] [google.cloud.dialogflow.cx.v3.QueryParameters.analyze_query_text_sentiment], @@ -637,7 +642,7 @@ class AudioInput(proto.Message): r"""Represents the natural speech audio to be processed. Attributes: - config (~.audio_config.InputAudioConfig): + config (google.cloud.dialogflowcx_v3.types.InputAudioConfig): Required. Instructs the speech recognizer how to process the speech audio. audio (bytes): @@ -690,7 +695,7 @@ class Match(proto.Message): r"""Represents one match result of [MatchIntent][]. Attributes: - intent (~.gcdc_intent.Intent): + intent (google.cloud.dialogflowcx_v3.types.Intent): The [Intent][google.cloud.dialogflow.cx.v3.Intent] that matched the query. Some, not all fields are filled in this message, including but not limited to: ``name`` and @@ -701,7 +706,7 @@ class Match(proto.Message): The event that matched the query. Only filled for [``EVENT``][google.cloud.dialogflow.cx.v3.Match.MatchType] match type. - parameters (~.struct.Struct): + parameters (google.protobuf.struct_pb2.Struct): The collection of parameters extracted from the query. Depending on your protocol or client library @@ -726,7 +731,7 @@ class Match(proto.Message): MatchIntent. This value can be different from original input sent in request because of spelling correction or other processing. - match_type (~.gcdc_session.Match.MatchType): + match_type (google.cloud.dialogflowcx_v3.types.Match.MatchType): Type of this [Match][google.cloud.dialogflow.cx.v3.Match]. confidence (float): The confidence of this match. Values range @@ -781,9 +786,9 @@ class MatchIntentRequest(proto.Message): For more information, see the `sessions guide `__. - query_params (~.gcdc_session.QueryParameters): + query_params (google.cloud.dialogflowcx_v3.types.QueryParameters): The parameters of this query. - query_input (~.gcdc_session.QueryInput): + query_input (google.cloud.dialogflowcx_v3.types.QueryInput): Required. The input specification. """ @@ -815,11 +820,11 @@ class MatchIntentResponse(proto.Message): If an [event][google.cloud.dialogflow.cx.v3.EventInput] was provided as input, this field will contain a copy of the event name. - matches (Sequence[~.gcdc_session.Match]): + matches (Sequence[google.cloud.dialogflowcx_v3.types.Match]): Match results, if more than one, ordered descendingly by the confidence we have that the particular intent matches the query. - current_page (~.page.Page): + current_page (google.cloud.dialogflowcx_v3.types.Page): The current [Page][google.cloud.dialogflow.cx.v3.Page]. Some, not all fields are filled in this message, including but not limited to ``name`` and ``display_name``. @@ -842,12 +847,12 @@ class FulfillIntentRequest(proto.Message): r"""Request of [FulfillIntent][] Attributes: - match_intent_request (~.gcdc_session.MatchIntentRequest): + match_intent_request (google.cloud.dialogflowcx_v3.types.MatchIntentRequest): Must be same as the corresponding MatchIntent request, otherwise the behavior is undefined. - match (~.gcdc_session.Match): + match (google.cloud.dialogflowcx_v3.types.Match): The matched intent/event to fulfill. - output_audio_config (~.audio_config.OutputAudioConfig): + output_audio_config (google.cloud.dialogflowcx_v3.types.OutputAudioConfig): Instructs the speech synthesizer how to generate output audio. """ @@ -872,7 +877,7 @@ class FulfillIntentResponse(proto.Message): response. It can be used to locate a response in the training example set or for reporting issues. - query_result (~.gcdc_session.QueryResult): + query_result (google.cloud.dialogflowcx_v3.types.QueryResult): The result of the conversational query. output_audio (bytes): The audio data bytes encoded as specified in the request. @@ -887,7 +892,7 @@ class FulfillIntentResponse(proto.Message): In some scenarios, multiple output audio fields may be present in the response structure. In these cases, only the top-most-level audio output has content. - output_audio_config (~.audio_config.OutputAudioConfig): + output_audio_config (google.cloud.dialogflowcx_v3.types.OutputAudioConfig): The config used by the speech synthesizer to generate the output audio. """ diff --git a/google/cloud/dialogflowcx_v3/types/session_entity_type.py b/google/cloud/dialogflowcx_v3/types/session_entity_type.py index b3a45290..ebdb3598 100644 --- a/google/cloud/dialogflowcx_v3/types/session_entity_type.py +++ b/google/cloud/dialogflowcx_v3/types/session_entity_type.py @@ -62,11 +62,11 @@ class SessionEntityType(proto.Message): ``projects//locations//agents//environments//sessions//entityTypes/``. If ``Environment ID`` is not specified, we assume default 'draft' environment. - entity_override_mode (~.gcdc_session_entity_type.SessionEntityType.EntityOverrideMode): + entity_override_mode (google.cloud.dialogflowcx_v3.types.SessionEntityType.EntityOverrideMode): Required. Indicates whether the additional data should override or supplement the custom entity type definition. - entities (Sequence[~.entity_type.EntityType.Entity]): + entities (Sequence[google.cloud.dialogflowcx_v3.types.EntityType.Entity]): Required. The collection of entities to override or supplement the custom entity type. """ @@ -119,7 +119,7 @@ class ListSessionEntityTypesResponse(proto.Message): [SessionEntityTypes.ListSessionEntityTypes][google.cloud.dialogflow.cx.v3.SessionEntityTypes.ListSessionEntityTypes]. Attributes: - session_entity_types (Sequence[~.gcdc_session_entity_type.SessionEntityType]): + session_entity_types (Sequence[google.cloud.dialogflowcx_v3.types.SessionEntityType]): The list of session entity types. There will be a maximum number of items returned based on the page_size field in the request. @@ -170,7 +170,7 @@ class CreateSessionEntityTypeRequest(proto.Message): ``projects//locations//agents//environments//sessions/``. If ``Environment ID`` is not specified, we assume default 'draft' environment. - session_entity_type (~.gcdc_session_entity_type.SessionEntityType): + session_entity_type (google.cloud.dialogflowcx_v3.types.SessionEntityType): Required. The session entity type to create. """ @@ -186,14 +186,14 @@ class UpdateSessionEntityTypeRequest(proto.Message): [SessionEntityTypes.UpdateSessionEntityType][google.cloud.dialogflow.cx.v3.SessionEntityTypes.UpdateSessionEntityType]. Attributes: - session_entity_type (~.gcdc_session_entity_type.SessionEntityType): + session_entity_type (google.cloud.dialogflowcx_v3.types.SessionEntityType): Required. The session entity type to update. Format: ``projects//locations//agents//sessions//entityTypes/`` or ``projects//locations//agents//environments//sessions//entityTypes/``. If ``Environment ID`` is not specified, we assume default 'draft' environment. - update_mask (~.field_mask.FieldMask): + update_mask (google.protobuf.field_mask_pb2.FieldMask): The mask to control which fields get updated. """ diff --git a/google/cloud/dialogflowcx_v3/types/test_case.py b/google/cloud/dialogflowcx_v3/types/test_case.py new file mode 100644 index 00000000..459c5fb1 --- /dev/null +++ b/google/cloud/dialogflowcx_v3/types/test_case.py @@ -0,0 +1,1001 @@ +# -*- 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. +# + +import proto # type: ignore + + +from google.cloud.dialogflowcx_v3.types import flow as gcdc_flow +from google.cloud.dialogflowcx_v3.types import intent as gcdc_intent +from google.cloud.dialogflowcx_v3.types import page as gcdc_page +from google.cloud.dialogflowcx_v3.types import response_message +from google.cloud.dialogflowcx_v3.types import session +from google.cloud.dialogflowcx_v3.types import transition_route_group +from google.protobuf import field_mask_pb2 as field_mask # type: ignore +from google.protobuf import struct_pb2 as struct # type: ignore +from google.protobuf import timestamp_pb2 as timestamp # type: ignore +from google.rpc import status_pb2 as gr_status # type: ignore + + +__protobuf__ = proto.module( + package="google.cloud.dialogflow.cx.v3", + manifest={ + "TestResult", + "TestCase", + "TestCaseResult", + "TestConfig", + "ConversationTurn", + "TestRunDifference", + "TransitionCoverage", + "TransitionRouteGroupCoverage", + "IntentCoverage", + "CalculateCoverageRequest", + "CalculateCoverageResponse", + "ListTestCasesRequest", + "ListTestCasesResponse", + "BatchDeleteTestCasesRequest", + "CreateTestCaseRequest", + "UpdateTestCaseRequest", + "GetTestCaseRequest", + "RunTestCaseRequest", + "RunTestCaseResponse", + "RunTestCaseMetadata", + "BatchRunTestCasesRequest", + "BatchRunTestCasesResponse", + "BatchRunTestCasesMetadata", + "TestError", + "ImportTestCasesRequest", + "ImportTestCasesResponse", + "ImportTestCasesMetadata", + "TestCaseError", + "ExportTestCasesRequest", + "ExportTestCasesResponse", + "ExportTestCasesMetadata", + "ListTestCaseResultsRequest", + "ListTestCaseResultsResponse", + }, +) + + +class TestResult(proto.Enum): + r"""The test result for a test case and an agent environment.""" + TEST_RESULT_UNSPECIFIED = 0 + PASSED = 1 + FAILED = 2 + + +class TestCase(proto.Message): + r"""Represents a test case. + + Attributes: + name (str): + The unique identifier of the test case. + [TestCases.CreateTestCase][google.cloud.dialogflow.cx.v3.TestCases.CreateTestCase] + will populate the name automatically. Otherwise use format: + ``projects//locations//agents/ /testCases/``. + tags (Sequence[str]): + Tags are short descriptions that users may + apply to test cases for organizational and + filtering purposes. Each tag should start with + "#" and has a limit of 30 characters. + display_name (str): + Required. The human-readable name of the test + case, unique within the agent. Limit of 200 + characters. + notes (str): + Additional freeform notes about the test + case. Limit of 400 characters. + test_config (google.cloud.dialogflowcx_v3.types.TestConfig): + Config for the test case. + test_case_conversation_turns (Sequence[google.cloud.dialogflowcx_v3.types.ConversationTurn]): + The conversation turns uttered when the test + case was created, in chronological order. These + include the canonical set of agent utterances + that should occur when the agent is working + properly. + creation_time (google.protobuf.timestamp_pb2.Timestamp): + Output only. When the test was created. + last_test_result (google.cloud.dialogflowcx_v3.types.TestCaseResult): + The latest test result. + """ + + name = proto.Field(proto.STRING, number=1) + + tags = proto.RepeatedField(proto.STRING, number=2) + + display_name = proto.Field(proto.STRING, number=3) + + notes = proto.Field(proto.STRING, number=4) + + test_config = proto.Field(proto.MESSAGE, number=13, message="TestConfig",) + + test_case_conversation_turns = proto.RepeatedField( + proto.MESSAGE, number=5, message="ConversationTurn", + ) + + creation_time = proto.Field(proto.MESSAGE, number=10, message=timestamp.Timestamp,) + + last_test_result = proto.Field(proto.MESSAGE, number=12, message="TestCaseResult",) + + +class TestCaseResult(proto.Message): + r"""Represents a result from running a test case in an agent + environment. + + Attributes: + name (str): + The resource name for the test case result. Format: + ``projects//locations//agents//testCases/ /results/``. + environment (str): + Environment where the test was run. If not + set, it indicates the draft environment. + conversation_turns (Sequence[google.cloud.dialogflowcx_v3.types.ConversationTurn]): + The conversation turns uttered during the + test case replay in chronological order. + test_result (google.cloud.dialogflowcx_v3.types.TestResult): + Whether the test case passed in the agent + environment. + test_time (google.protobuf.timestamp_pb2.Timestamp): + The time that the test was run. + """ + + name = proto.Field(proto.STRING, number=1) + + environment = proto.Field(proto.STRING, number=2) + + conversation_turns = proto.RepeatedField( + proto.MESSAGE, number=3, message="ConversationTurn", + ) + + test_result = proto.Field(proto.ENUM, number=4, enum="TestResult",) + + test_time = proto.Field(proto.MESSAGE, number=5, message=timestamp.Timestamp,) + + +class TestConfig(proto.Message): + r"""Represents configurations for a test case. + + Attributes: + tracking_parameters (Sequence[str]): + Session parameters to be compared when + calculating differences. + flow (str): + Flow name. If not set, default start flow is assumed. + Format: + ``projects//locations//agents//flows/``. + """ + + tracking_parameters = proto.RepeatedField(proto.STRING, number=1) + + flow = proto.Field(proto.STRING, number=2) + + +class ConversationTurn(proto.Message): + r"""One interaction between a human and virtual agent. The human + provides some input and the virtual agent provides a response. + + Attributes: + user_input (google.cloud.dialogflowcx_v3.types.ConversationTurn.UserInput): + The user input. + virtual_agent_output (google.cloud.dialogflowcx_v3.types.ConversationTurn.VirtualAgentOutput): + The virtual agent output. + """ + + class UserInput(proto.Message): + r"""The input from the human user. + + Attributes: + input_ (google.cloud.dialogflowcx_v3.types.QueryInput): + Supports [text + input][google.cloud.dialogflow.cx.v3.QueryInput.text], + [event + input][google.cloud.dialogflow.cx.v3.QueryInput.event], + [dtmf input][google.cloud.dialogflow.cx.v3.QueryInput.dtmf] + in the test case. + injected_parameters (google.protobuf.struct_pb2.Struct): + Parameters that need to be injected into the + conversation during intent detection. + is_webhook_enabled (bool): + If webhooks should be allowed to trigger in + response to the user utterance. Often if + parameters are injected, webhooks should not be + enabled. + """ + + input_ = proto.Field(proto.MESSAGE, number=5, message=session.QueryInput,) + + injected_parameters = proto.Field( + proto.MESSAGE, number=2, message=struct.Struct, + ) + + is_webhook_enabled = proto.Field(proto.BOOL, number=3) + + class VirtualAgentOutput(proto.Message): + r"""The output from the virtual agent. + + Attributes: + session_parameters (google.protobuf.struct_pb2.Struct): + The session parameters available to the bot + at this point. + differences (Sequence[google.cloud.dialogflowcx_v3.types.TestRunDifference]): + Output only. If this is part of a [result conversation + turn][TestCaseResult.conversation_turns], the list of + differences between the original run and the replay for this + output, if any. + diagnostic_info (google.protobuf.struct_pb2.Struct): + Required. Input only. The diagnostic + [info][Session.DetectIntentResponse.QueryResult.diagnostic_info] + output for the turn. + triggered_intent (google.cloud.dialogflowcx_v3.types.Intent): + The [Intent][google.cloud.dialogflow.cx.v3.Intent] that + triggered the response. Only name and displayName will be + set. + current_page (google.cloud.dialogflowcx_v3.types.Page): + The [Page][google.cloud.dialogflow.cx.v3.Page] on which the + utterance was spoken. Only name and displayName will be set. + text_responses (Sequence[google.cloud.dialogflowcx_v3.types.ResponseMessage.Text]): + The + [text][google.cloud.dialogflow.cx.v3.ResponseMessage.Text] + responses from the agent for the turn. + status (google.rpc.status_pb2.Status): + Response error from the agent in the test + result. If set, other output is empty. + """ + + session_parameters = proto.Field( + proto.MESSAGE, number=4, message=struct.Struct, + ) + + differences = proto.RepeatedField( + proto.MESSAGE, number=5, message="TestRunDifference", + ) + + diagnostic_info = proto.Field(proto.MESSAGE, number=6, message=struct.Struct,) + + triggered_intent = proto.Field( + proto.MESSAGE, number=7, message=gcdc_intent.Intent, + ) + + current_page = proto.Field(proto.MESSAGE, number=8, message=gcdc_page.Page,) + + text_responses = proto.RepeatedField( + proto.MESSAGE, number=9, message=response_message.ResponseMessage.Text, + ) + + status = proto.Field(proto.MESSAGE, number=10, message=gr_status.Status,) + + user_input = proto.Field(proto.MESSAGE, number=1, message=UserInput,) + + virtual_agent_output = proto.Field( + proto.MESSAGE, number=2, message=VirtualAgentOutput, + ) + + +class TestRunDifference(proto.Message): + r"""The description of differences between original and replayed + agent output. + + Attributes: + type_ (google.cloud.dialogflowcx_v3.types.TestRunDifference.DiffType): + The type of diff. + description (str): + A description of the diff, showing the actual + output vs expected output. + """ + + class DiffType(proto.Enum): + r"""What part of the message replay differs from the test case.""" + DIFF_TYPE_UNSPECIFIED = 0 + INTENT = 1 + PAGE = 2 + PARAMETERS = 3 + UTTERANCE = 4 + + type_ = proto.Field(proto.ENUM, number=1, enum=DiffType,) + + description = proto.Field(proto.STRING, number=2) + + +class TransitionCoverage(proto.Message): + r"""Transition coverage represents the percentage of all possible + page transitions (page-level transition routes and event + handlers, excluding transition route groups) present within any + of a parent's test cases. + + Attributes: + transitions (Sequence[google.cloud.dialogflowcx_v3.types.TransitionCoverage.Transition]): + The list of Transitions present in the agent. + coverage_score (float): + The percent of transitions in the agent that + are covered. + """ + + class TransitionNode(proto.Message): + r"""The source or target of a transition. + + Attributes: + page (google.cloud.dialogflowcx_v3.types.Page): + Indicates a transition to a + [Page][google.cloud.dialogflow.cx.v3.Page]. Only some fields + such as name and displayname will be set. + flow (google.cloud.dialogflowcx_v3.types.Flow): + Indicates a transition to a + [Flow][google.cloud.dialogflow.cx.v3.Flow]. Only some fields + such as name and displayname will be set. + """ + + page = proto.Field( + proto.MESSAGE, number=1, oneof="kind", message=gcdc_page.Page, + ) + + flow = proto.Field( + proto.MESSAGE, number=2, oneof="kind", message=gcdc_flow.Flow, + ) + + class Transition(proto.Message): + r"""A transition in a page. + + Attributes: + source (google.cloud.dialogflowcx_v3.types.TransitionCoverage.TransitionNode): + The start node of a transition. + index (int): + The index of a transition in the transition + list. Starting from 0. + target (google.cloud.dialogflowcx_v3.types.TransitionCoverage.TransitionNode): + The end node of a transition. + covered (bool): + Whether or not the transition is covered by + at least one of the agent's test cases. + transition_route (google.cloud.dialogflowcx_v3.types.TransitionRoute): + Intent route or condition route. + event_handler (google.cloud.dialogflowcx_v3.types.EventHandler): + Event handler. + """ + + source = proto.Field( + proto.MESSAGE, number=1, message="TransitionCoverage.TransitionNode", + ) + + index = proto.Field(proto.INT32, number=4) + + target = proto.Field( + proto.MESSAGE, number=2, message="TransitionCoverage.TransitionNode", + ) + + covered = proto.Field(proto.BOOL, number=3) + + transition_route = proto.Field( + proto.MESSAGE, number=5, oneof="detail", message=gcdc_page.TransitionRoute, + ) + + event_handler = proto.Field( + proto.MESSAGE, number=6, oneof="detail", message=gcdc_page.EventHandler, + ) + + transitions = proto.RepeatedField(proto.MESSAGE, number=1, message=Transition,) + + coverage_score = proto.Field(proto.FLOAT, number=2) + + +class TransitionRouteGroupCoverage(proto.Message): + r"""Transition route group coverage represents the percentage of + all possible transition routes present within any of a parent's + test cases. The results are grouped by the transition route + group. + + Attributes: + coverages (Sequence[google.cloud.dialogflowcx_v3.types.TransitionRouteGroupCoverage.Coverage]): + Transition route group coverages. + coverage_score (float): + The percent of transition routes in all the + transition route groups that are covered. + """ + + class Coverage(proto.Message): + r"""Coverage result message for one transition route group. + + Attributes: + route_group (google.cloud.dialogflowcx_v3.types.TransitionRouteGroup): + Transition route group metadata. Only name + and displayName will be set. + transitions (Sequence[google.cloud.dialogflowcx_v3.types.TransitionRouteGroupCoverage.Coverage.Transition]): + The list of transition routes and coverage in + the transition route group. + coverage_score (float): + The percent of transition routes in the + transition route group that are covered. + """ + + class Transition(proto.Message): + r"""A transition coverage in a transition route group. + + Attributes: + transition_route (google.cloud.dialogflowcx_v3.types.TransitionRoute): + Intent route or condition route. + covered (bool): + Whether or not the transition route is + covered by at least one of the agent's test + cases. + """ + + transition_route = proto.Field( + proto.MESSAGE, number=1, message=gcdc_page.TransitionRoute, + ) + + covered = proto.Field(proto.BOOL, number=2) + + route_group = proto.Field( + proto.MESSAGE, + number=1, + message=transition_route_group.TransitionRouteGroup, + ) + + transitions = proto.RepeatedField( + proto.MESSAGE, + number=2, + message="TransitionRouteGroupCoverage.Coverage.Transition", + ) + + coverage_score = proto.Field(proto.FLOAT, number=3) + + coverages = proto.RepeatedField(proto.MESSAGE, number=1, message=Coverage,) + + coverage_score = proto.Field(proto.FLOAT, number=2) + + +class IntentCoverage(proto.Message): + r"""Intent coverage represents the percentage of all possible + intents in the agent that are triggered in any of a parent's + test cases. + + Attributes: + intents (Sequence[google.cloud.dialogflowcx_v3.types.IntentCoverage.Intent]): + The list of Intents present in the agent + coverage_score (float): + The percent of intents in the agent that are + covered. + """ + + class Intent(proto.Message): + r"""The agent's intent. + + Attributes: + intent (str): + The intent full resource name + covered (bool): + Whether or not the intent is covered by at + least one of the agent's test cases. + """ + + intent = proto.Field(proto.STRING, number=1) + + covered = proto.Field(proto.BOOL, number=2) + + intents = proto.RepeatedField(proto.MESSAGE, number=1, message=Intent,) + + coverage_score = proto.Field(proto.FLOAT, number=2) + + +class CalculateCoverageRequest(proto.Message): + r"""The request message for + [TestCases.CalculateCoverage][google.cloud.dialogflow.cx.v3.TestCases.CalculateCoverage]. + + Attributes: + agent (str): + Required. The agent to calculate coverage for. Format: + ``projects//locations//agents/``. + type_ (google.cloud.dialogflowcx_v3.types.CalculateCoverageRequest.CoverageType): + Required. The type of coverage requested. + """ + + class CoverageType(proto.Enum): + r"""The type of coverage score requested.""" + COVERAGE_TYPE_UNSPECIFIED = 0 + INTENT = 1 + PAGE_TRANSITION = 2 + TRANSITION_ROUTE_GROUP = 3 + + agent = proto.Field(proto.STRING, number=3) + + type_ = proto.Field(proto.ENUM, number=2, enum=CoverageType,) + + +class CalculateCoverageResponse(proto.Message): + r"""The response message for + [TestCases.CalculateCoverage][google.cloud.dialogflow.cx.v3.TestCases.CalculateCoverage]. + + Attributes: + agent (str): + The agent to calculate coverage for. Format: + ``projects//locations//agents/``. + intent_coverage (google.cloud.dialogflowcx_v3.types.IntentCoverage): + Intent coverage. + transition_coverage (google.cloud.dialogflowcx_v3.types.TransitionCoverage): + Transition (excluding transition route + groups) coverage. + route_group_coverage (google.cloud.dialogflowcx_v3.types.TransitionRouteGroupCoverage): + Transition route group coverage. + """ + + agent = proto.Field(proto.STRING, number=5) + + intent_coverage = proto.Field( + proto.MESSAGE, number=2, oneof="coverage_type", message="IntentCoverage", + ) + + transition_coverage = proto.Field( + proto.MESSAGE, number=4, oneof="coverage_type", message="TransitionCoverage", + ) + + route_group_coverage = proto.Field( + proto.MESSAGE, + number=6, + oneof="coverage_type", + message="TransitionRouteGroupCoverage", + ) + + +class ListTestCasesRequest(proto.Message): + r"""The request message for + [TestCases.ListTestCases][google.cloud.dialogflow.cx.v3.TestCases.ListTestCases]. + + Attributes: + parent (str): + Required. The agent to list all pages for. Format: + ``projects//locations//agents/``. + page_size (int): + The maximum number of items to return in a + single page. By default 20. Note that when + TestCaseView = FULL, the maximum page size + allowed is 20. When TestCaseView = BASIC, the + maximum page size allowed is 500. + page_token (str): + The next_page_token value returned from a previous list + request. + view (google.cloud.dialogflowcx_v3.types.ListTestCasesRequest.TestCaseView): + Specifies whether response should include all + fields or just the metadata. + """ + + class TestCaseView(proto.Enum): + r"""Specifies how much test case information to include in the + response. + """ + TEST_CASE_VIEW_UNSPECIFIED = 0 + BASIC = 1 + FULL = 2 + + parent = proto.Field(proto.STRING, number=1) + + page_size = proto.Field(proto.INT32, number=2) + + page_token = proto.Field(proto.STRING, number=3) + + view = proto.Field(proto.ENUM, number=4, enum=TestCaseView,) + + +class ListTestCasesResponse(proto.Message): + r"""The response message for + [TestCases.ListTestCases][google.cloud.dialogflow.cx.v3.TestCases.ListTestCases]. + + Attributes: + test_cases (Sequence[google.cloud.dialogflowcx_v3.types.TestCase]): + The list of test cases. There will be a maximum number of + items returned based on the page_size field in the request. + next_page_token (str): + Token to retrieve the next page of results, + or empty if there are no more results in the + list. + """ + + @property + def raw_page(self): + return self + + test_cases = proto.RepeatedField(proto.MESSAGE, number=1, message="TestCase",) + + next_page_token = proto.Field(proto.STRING, number=2) + + +class BatchDeleteTestCasesRequest(proto.Message): + r"""The request message for + [TestCases.BatchDeleteTestCases][google.cloud.dialogflow.cx.v3.TestCases.BatchDeleteTestCases]. + + Attributes: + parent (str): + Required. The agent to delete test cases from. Format: + ``projects//locations//agents/``. + names (Sequence[str]): + Required. Format of test case names: + ``projects//locations/ /agents//testCases/``. + """ + + parent = proto.Field(proto.STRING, number=1) + + names = proto.RepeatedField(proto.STRING, number=3) + + +class CreateTestCaseRequest(proto.Message): + r"""The request message for + [TestCases.CreateTestCase][google.cloud.dialogflow.cx.v3.TestCases.CreateTestCase]. + + Attributes: + parent (str): + Required. The agent to create the test case for. Format: + ``projects//locations//agents/``. + test_case (google.cloud.dialogflowcx_v3.types.TestCase): + Required. The test case to create. + """ + + parent = proto.Field(proto.STRING, number=1) + + test_case = proto.Field(proto.MESSAGE, number=2, message="TestCase",) + + +class UpdateTestCaseRequest(proto.Message): + r"""The request message for + [TestCases.UpdateTestCase][google.cloud.dialogflow.cx.v3.TestCases.UpdateTestCase]. + + Attributes: + test_case (google.cloud.dialogflowcx_v3.types.TestCase): + Required. The test case to update. + update_mask (google.protobuf.field_mask_pb2.FieldMask): + Required. The mask to specify which fields should be + updated. The + [``creationTime``][google.cloud.dialogflow.cx.v3.TestCase.creation_time] + and + [``lastTestResult``][google.cloud.dialogflow.cx.v3.TestCase.last_test_result] + cannot be updated. + """ + + test_case = proto.Field(proto.MESSAGE, number=1, message="TestCase",) + + update_mask = proto.Field(proto.MESSAGE, number=2, message=field_mask.FieldMask,) + + +class GetTestCaseRequest(proto.Message): + r"""The request message for + [TestCases.GetTestCase][google.cloud.dialogflow.cx.v3.TestCases.GetTestCase]. + + Attributes: + name (str): + Required. The name of the testcase. Format: + ``projects//locations//agents//testCases/``. + """ + + name = proto.Field(proto.STRING, number=1) + + +class RunTestCaseRequest(proto.Message): + r"""The request message for + [TestCases.RunTestCase][google.cloud.dialogflow.cx.v3.TestCases.RunTestCase]. + + Attributes: + name (str): + Required. Format of test case name to run: + ``projects//locations/ /agents//testCases/``. + environment (str): + Optional. Environment name. If not set, draft environment is + assumed. Format: + ``projects//locations//agents//environments/``. + """ + + name = proto.Field(proto.STRING, number=1) + + environment = proto.Field(proto.STRING, number=2) + + +class RunTestCaseResponse(proto.Message): + r"""The response message for + [TestCases.RunTestCase][google.cloud.dialogflow.cx.v3.TestCases.RunTestCase]. + + Attributes: + result (google.cloud.dialogflowcx_v3.types.TestCaseResult): + The result. + """ + + result = proto.Field(proto.MESSAGE, number=2, message="TestCaseResult",) + + +class RunTestCaseMetadata(proto.Message): + r"""Metadata returned for the + [TestCases.RunTestCase][google.cloud.dialogflow.cx.v3.TestCases.RunTestCase] + long running operation. + """ + + +class BatchRunTestCasesRequest(proto.Message): + r"""The request message for + [TestCases.BatchRunTestCases][google.cloud.dialogflow.cx.v3.TestCases.BatchRunTestCases]. + + Attributes: + parent (str): + Required. Agent name. Format: + ``projects//locations//agents/ ``. + environment (str): + Optional. If not set, draft environment is assumed. Format: + ``projects//locations//agents//environments/``. + test_cases (Sequence[str]): + Required. Format: + ``projects//locations//agents//testCases/``. + """ + + parent = proto.Field(proto.STRING, number=1) + + environment = proto.Field(proto.STRING, number=2) + + test_cases = proto.RepeatedField(proto.STRING, number=3) + + +class BatchRunTestCasesResponse(proto.Message): + r"""The response message for + [TestCases.BatchRunTestCases][google.cloud.dialogflow.cx.v3.TestCases.BatchRunTestCases]. + + Attributes: + results (Sequence[google.cloud.dialogflowcx_v3.types.TestCaseResult]): + The test case results. The detailed [conversation + turns][google.cloud.dialogflow.cx.v3.TestCaseResult.conversation_turns] + are empty in this response. + """ + + results = proto.RepeatedField(proto.MESSAGE, number=1, message="TestCaseResult",) + + +class BatchRunTestCasesMetadata(proto.Message): + r"""Metadata returned for the + [TestCases.BatchRunTestCases][google.cloud.dialogflow.cx.v3.TestCases.BatchRunTestCases] + long running operation. + + Attributes: + errors (Sequence[google.cloud.dialogflowcx_v3.types.TestError]): + The test errors. + """ + + errors = proto.RepeatedField(proto.MESSAGE, number=1, message="TestError",) + + +class TestError(proto.Message): + r"""Error info for running a test. + + Attributes: + test_case (str): + The test case resource name. + status (google.rpc.status_pb2.Status): + The status associated with the test. + test_time (google.protobuf.timestamp_pb2.Timestamp): + The timestamp when the test was completed. + """ + + test_case = proto.Field(proto.STRING, number=1) + + status = proto.Field(proto.MESSAGE, number=2, message=gr_status.Status,) + + test_time = proto.Field(proto.MESSAGE, number=3, message=timestamp.Timestamp,) + + +class ImportTestCasesRequest(proto.Message): + r"""The request message for + [TestCases.ImportTestCases][google.cloud.dialogflow.cx.v3.TestCases.ImportTestCases]. + + Attributes: + parent (str): + Required. The agent to import test cases to. Format: + ``projects//locations//agents/``. + gcs_uri (str): + The `Google Cloud + Storage `__ URI to + import test cases from. The format of this URI must be + ``gs:///``. + content (bytes): + Uncompressed raw byte content for test cases. + """ + + parent = proto.Field(proto.STRING, number=1) + + gcs_uri = proto.Field(proto.STRING, number=2, oneof="source") + + content = proto.Field(proto.BYTES, number=3, oneof="source") + + +class ImportTestCasesResponse(proto.Message): + r"""The response message for + [TestCases.ImportTestCases][google.cloud.dialogflow.cx.v3.TestCases.ImportTestCases]. + + Attributes: + names (Sequence[str]): + The unique identifiers of the new test cases. Format: + ``projects//locations//agents//testCases/``. + """ + + names = proto.RepeatedField(proto.STRING, number=1) + + +class ImportTestCasesMetadata(proto.Message): + r"""Metadata returned for the + [TestCases.ImportTestCases][google.cloud.dialogflow.cx.v3.TestCases.ImportTestCases] + long running operation. + + Attributes: + errors (Sequence[google.cloud.dialogflowcx_v3.types.TestCaseError]): + Errors for failed test cases. + """ + + errors = proto.RepeatedField(proto.MESSAGE, number=1, message="TestCaseError",) + + +class TestCaseError(proto.Message): + r"""Error info for importing a test. + + Attributes: + test_case (google.cloud.dialogflowcx_v3.types.TestCase): + The test case. + status (google.rpc.status_pb2.Status): + The status associated with the test case. + """ + + test_case = proto.Field(proto.MESSAGE, number=1, message="TestCase",) + + status = proto.Field(proto.MESSAGE, number=2, message=gr_status.Status,) + + +class ExportTestCasesRequest(proto.Message): + r"""The request message for + [TestCases.ExportTestCases][google.cloud.dialogflow.cx.v3.TestCases.ExportTestCases]. + + Attributes: + parent (str): + Required. The agent where to export test cases from. Format: + ``projects//locations//agents/``. + gcs_uri (str): + The `Google Cloud + Storage `__ URI to + export the test cases to. The format of this URI must be + ``gs:///``. If unspecified, the + serialized test cases is returned inline. + data_format (google.cloud.dialogflowcx_v3.types.ExportTestCasesRequest.DataFormat): + The data format of the exported test cases. If not + specified, ``BLOB`` is assumed. + filter (str): + The filter expression used to filter exported test cases, + see `API Filtering `__. The expression + is case insensitive and supports the following syntax: + + name = [OR name = ] ... + + For example: + + - "name = t1 OR name = t2" matches the test case with the + exact resource name "t1" or "t2". + """ + + class DataFormat(proto.Enum): + r"""Data format of the exported test cases.""" + DATA_FORMAT_UNSPECIFIED = 0 + BLOB = 1 + JSON = 2 + + parent = proto.Field(proto.STRING, number=1) + + gcs_uri = proto.Field(proto.STRING, number=2, oneof="destination") + + data_format = proto.Field(proto.ENUM, number=3, enum=DataFormat,) + + filter = proto.Field(proto.STRING, number=4) + + +class ExportTestCasesResponse(proto.Message): + r"""The response message for + [TestCases.ExportTestCases][google.cloud.dialogflow.cx.v3.TestCases.ExportTestCases]. + + Attributes: + gcs_uri (str): + The URI to a file containing the exported test cases. This + field is populated only if ``gcs_uri`` is specified in + [ExportTestCasesRequest][google.cloud.dialogflow.cx.v3.ExportTestCasesRequest]. + content (bytes): + Uncompressed raw byte content for test cases. + """ + + gcs_uri = proto.Field(proto.STRING, number=1, oneof="destination") + + content = proto.Field(proto.BYTES, number=2, oneof="destination") + + +class ExportTestCasesMetadata(proto.Message): + r"""Metadata returned for the + [TestCases.ExportTestCases][google.cloud.dialogflow.cx.v3.TestCases.ExportTestCases] + long running operation. + """ + + +class ListTestCaseResultsRequest(proto.Message): + r"""The request message for + [TestCases.ListTestCaseResults][google.cloud.dialogflow.cx.v3.TestCases.ListTestCaseResults]. + + Attributes: + parent (str): + Required. The test case to list results for. Format: + ``projects//locations//agents// testCases/``. + Specify a ``-`` as a wildcard for TestCase ID to list + results across multiple test cases. + page_size (int): + The maximum number of items to return in a + single page. By default 100 and at most 1000. + page_token (str): + The next_page_token value returned from a previous list + request. + filter (str): + The filter expression used to filter test case results. See + `API Filtering `__. + + The expression is case insensitive. Only 'AND' is supported + for logical operators. The supported syntax is listed below + in detail: + + [AND ] ... [AND latest] + + The supported fields and operators are: field operator + ``environment`` ``=``, ``IN`` (Use value ``draft`` for draft + environment) ``test_time`` ``>``, ``<`` + + ``latest`` only returns the latest test result in all + results for each test case. + + Examples: + + - "environment=draft AND latest" matches the latest test + result for each test case in the draft environment. + - "environment IN (e1,e2)" matches any test case results + with an environment resource name of either "e1" or "e2". + - "test_time > 1602540713" matches any test case results + with test time later than a unix timestamp in seconds + 1602540713. + """ + + parent = proto.Field(proto.STRING, number=1) + + page_size = proto.Field(proto.INT32, number=2) + + page_token = proto.Field(proto.STRING, number=3) + + filter = proto.Field(proto.STRING, number=4) + + +class ListTestCaseResultsResponse(proto.Message): + r"""The response message for + [TestCases.ListTestCaseResults][google.cloud.dialogflow.cx.v3.TestCases.ListTestCaseResults]. + + Attributes: + test_case_results (Sequence[google.cloud.dialogflowcx_v3.types.TestCaseResult]): + The list of test case results. + next_page_token (str): + Token to retrieve the next page of results, + or empty if there are no more results in the + list. + """ + + @property + def raw_page(self): + return self + + test_case_results = proto.RepeatedField( + proto.MESSAGE, number=1, message="TestCaseResult", + ) + + next_page_token = proto.Field(proto.STRING, number=2) + + +__all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/google/cloud/dialogflowcx_v3/types/transition_route_group.py b/google/cloud/dialogflowcx_v3/types/transition_route_group.py index a6a838a3..bf59b515 100644 --- a/google/cloud/dialogflowcx_v3/types/transition_route_group.py +++ b/google/cloud/dialogflowcx_v3/types/transition_route_group.py @@ -52,16 +52,9 @@ class TransitionRouteGroup(proto.Message): group, unique within the [Agent][google.cloud.dialogflow.cx.v3.Agent]. The display name can be no longer than 30 characters. - transition_routes (Sequence[~.page.TransitionRoute]): + transition_routes (Sequence[google.cloud.dialogflowcx_v3.types.TransitionRoute]): Transition routes associated with the [TransitionRouteGroup][google.cloud.dialogflow.cx.v3.TransitionRouteGroup]. - Duplicate transition routes (i.e. using the same - [``intent``][google.cloud.dialogflow.cx.v3.TransitionRoute.intent]) - are not allowed. - - Note that the - [``name``][google.cloud.dialogflow.cx.v3.TransitionRoute.name] - field is not used in the transition route group scope. """ name = proto.Field(proto.STRING, number=1) @@ -97,7 +90,7 @@ class ListTransitionRouteGroupsRequest(proto.Message): If not specified, the agent's default language is used. `Many - languages `__ + languages `__ are supported. Note: languages must be enabled in the agent before they can be used. """ @@ -116,7 +109,7 @@ class ListTransitionRouteGroupsResponse(proto.Message): [TransitionRouteGroups.ListTransitionRouteGroups][google.cloud.dialogflow.cx.v3.TransitionRouteGroups.ListTransitionRouteGroups]. Attributes: - transition_route_groups (Sequence[~.gcdc_transition_route_group.TransitionRouteGroup]): + transition_route_groups (Sequence[google.cloud.dialogflowcx_v3.types.TransitionRouteGroup]): The list of transition route groups. There will be a maximum number of items returned based on the page_size field in the request. The list may in some cases be empty or contain @@ -158,7 +151,7 @@ class GetTransitionRouteGroupRequest(proto.Message): If not specified, the agent's default language is used. `Many - languages `__ + languages `__ are supported. Note: languages must be enabled in the agent before they can be used. """ @@ -178,7 +171,7 @@ class CreateTransitionRouteGroupRequest(proto.Message): [TransitionRouteGroup][google.cloud.dialogflow.cx.v3.TransitionRouteGroup] for. Format: ``projects//locations//agents//flows/``. - transition_route_group (~.gcdc_transition_route_group.TransitionRouteGroup): + transition_route_group (google.cloud.dialogflowcx_v3.types.TransitionRouteGroup): Required. The transition route group to create. language_code (str): @@ -190,7 +183,7 @@ class CreateTransitionRouteGroupRequest(proto.Message): If not specified, the agent's default language is used. `Many - languages `__ + languages `__ are supported. Note: languages must be enabled in the agent before they can be used. """ @@ -209,10 +202,10 @@ class UpdateTransitionRouteGroupRequest(proto.Message): [TransitionRouteGroups.UpdateTransitionRouteGroup][google.cloud.dialogflow.cx.v3.TransitionRouteGroups.UpdateTransitionRouteGroup]. Attributes: - transition_route_group (~.gcdc_transition_route_group.TransitionRouteGroup): + transition_route_group (google.cloud.dialogflowcx_v3.types.TransitionRouteGroup): Required. The transition route group to update. - update_mask (~.field_mask.FieldMask): + update_mask (google.protobuf.field_mask_pb2.FieldMask): The mask to control which fields get updated. language_code (str): The language to list transition route groups for. The field @@ -223,7 +216,7 @@ class UpdateTransitionRouteGroupRequest(proto.Message): If not specified, the agent's default language is used. `Many - languages `__ + languages `__ are supported. Note: languages must be enabled in the agent before they can be used. """ diff --git a/google/cloud/dialogflowcx_v3/types/validation_message.py b/google/cloud/dialogflowcx_v3/types/validation_message.py new file mode 100644 index 00000000..1355c2d9 --- /dev/null +++ b/google/cloud/dialogflowcx_v3/types/validation_message.py @@ -0,0 +1,98 @@ +# -*- 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. +# + +import proto # type: ignore + + +__protobuf__ = proto.module( + package="google.cloud.dialogflow.cx.v3", + manifest={"ValidationMessage", "ResourceName",}, +) + + +class ValidationMessage(proto.Message): + r"""Agent/flow validation message. + + Attributes: + resource_type (google.cloud.dialogflowcx_v3.types.ValidationMessage.ResourceType): + The type of the resources where the message + is found. + resources (Sequence[str]): + The names of the resources where the message + is found. + resource_names (Sequence[google.cloud.dialogflowcx_v3.types.ResourceName]): + The resource names of the resources where the + message is found. + severity (google.cloud.dialogflowcx_v3.types.ValidationMessage.Severity): + Indicates the severity of the message. + detail (str): + The message detail. + """ + + class ResourceType(proto.Enum): + r"""Resource types.""" + RESOURCE_TYPE_UNSPECIFIED = 0 + AGENT = 1 + INTENT = 2 + INTENT_TRAINING_PHRASE = 8 + INTENT_PARAMETER = 9 + INTENTS = 10 + INTENT_TRAINING_PHRASES = 11 + ENTITY_TYPE = 3 + ENTITY_TYPES = 12 + WEBHOOK = 4 + FLOW = 5 + PAGE = 6 + PAGES = 13 + TRANSITION_ROUTE_GROUP = 7 + + class Severity(proto.Enum): + r"""Severity level.""" + SEVERITY_UNSPECIFIED = 0 + INFO = 1 + WARNING = 2 + ERROR = 3 + + resource_type = proto.Field(proto.ENUM, number=1, enum=ResourceType,) + + resources = proto.RepeatedField(proto.STRING, number=2) + + resource_names = proto.RepeatedField( + proto.MESSAGE, number=6, message="ResourceName", + ) + + severity = proto.Field(proto.ENUM, number=3, enum=Severity,) + + detail = proto.Field(proto.STRING, number=4) + + +class ResourceName(proto.Message): + r"""Resource name and display name. + + Attributes: + name (str): + Name. + display_name (str): + Display name. + """ + + name = proto.Field(proto.STRING, number=1) + + display_name = proto.Field(proto.STRING, number=2) + + +__all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/google/cloud/dialogflowcx_v3/types/version.py b/google/cloud/dialogflowcx_v3/types/version.py index ebf6d440..b5351155 100644 --- a/google/cloud/dialogflowcx_v3/types/version.py +++ b/google/cloud/dialogflowcx_v3/types/version.py @@ -69,12 +69,12 @@ class Version(proto.Message): The description of the version. The maximum length is 500 characters. If exceeded, the request is rejected. - nlu_settings (~.flow.NluSettings): + nlu_settings (google.cloud.dialogflowcx_v3.types.NluSettings): Output only. The NLU settings of the flow at version creation. - create_time (~.timestamp.Timestamp): + create_time (google.protobuf.timestamp_pb2.Timestamp): Output only. Create time of the version. - state (~.gcdc_version.Version.State): + state (google.cloud.dialogflowcx_v3.types.Version.State): Output only. The state of this version. This field is read-only and cannot be set by create and update methods. @@ -129,7 +129,7 @@ class ListVersionsResponse(proto.Message): [Versions.ListVersions][google.cloud.dialogflow.cx.v3.Versions.ListVersions]. Attributes: - versions (Sequence[~.gcdc_version.Version]): + versions (Sequence[google.cloud.dialogflowcx_v3.types.Version]): A list of versions. There will be a maximum number of items returned based on the page_size field in the request. The list may in some cases be empty or contain fewer entries @@ -173,7 +173,7 @@ class CreateVersionRequest(proto.Message): create an [Version][google.cloud.dialogflow.cx.v3.Version] for. Format: ``projects//locations//agents//flows/``. - version (~.gcdc_version.Version): + version (google.cloud.dialogflowcx_v3.types.Version): Required. The version to create. """ @@ -187,9 +187,9 @@ class UpdateVersionRequest(proto.Message): [Versions.UpdateVersion][google.cloud.dialogflow.cx.v3.Versions.UpdateVersion]. Attributes: - version (~.gcdc_version.Version): + version (google.cloud.dialogflowcx_v3.types.Version): Required. The version to update. - update_mask (~.field_mask.FieldMask): + update_mask (google.protobuf.field_mask_pb2.FieldMask): Required. The mask to control which fields get updated. Currently only ``description`` and ``display_name`` can be updated. diff --git a/google/cloud/dialogflowcx_v3/types/webhook.py b/google/cloud/dialogflowcx_v3/types/webhook.py index e59ccca6..870977ee 100644 --- a/google/cloud/dialogflowcx_v3/types/webhook.py +++ b/google/cloud/dialogflowcx_v3/types/webhook.py @@ -60,9 +60,9 @@ class Webhook(proto.Message): display_name (str): Required. The human-readable name of the webhook, unique within the agent. - generic_web_service (~.gcdc_webhook.Webhook.GenericWebService): + generic_web_service (google.cloud.dialogflowcx_v3.types.Webhook.GenericWebService): Configuration for a generic web service. - timeout (~.duration.Duration): + timeout (google.protobuf.duration_pb2.Duration): Webhook execution timeout. Execution is considered failed if Dialogflow doesn't receive a response from webhook at the end of the @@ -83,7 +83,7 @@ class GenericWebService(proto.Message): The user name for HTTP Basic authentication. password (str): The password for HTTP Basic authentication. - request_headers (Sequence[~.gcdc_webhook.Webhook.GenericWebService.RequestHeadersEntry]): + request_headers (Sequence[google.cloud.dialogflowcx_v3.types.Webhook.GenericWebService.RequestHeadersEntry]): The HTTP request headers to send together with webhook requests. """ @@ -137,7 +137,7 @@ class ListWebhooksResponse(proto.Message): [Webhooks.ListWebhooks][google.cloud.dialogflow.cx.v3.Webhooks.ListWebhooks]. Attributes: - webhooks (Sequence[~.gcdc_webhook.Webhook]): + webhooks (Sequence[google.cloud.dialogflowcx_v3.types.Webhook]): The list of webhooks. There will be a maximum number of items returned based on the page_size field in the request. next_page_token (str): @@ -176,7 +176,7 @@ class CreateWebhookRequest(proto.Message): parent (str): Required. The agent to create a webhook for. Format: ``projects//locations//agents/``. - webhook (~.gcdc_webhook.Webhook): + webhook (google.cloud.dialogflowcx_v3.types.Webhook): Required. The webhook to create. """ @@ -190,9 +190,9 @@ class UpdateWebhookRequest(proto.Message): [Webhooks.UpdateWebhook][google.cloud.dialogflow.cx.v3.Webhooks.UpdateWebhook]. Attributes: - webhook (~.gcdc_webhook.Webhook): + webhook (google.cloud.dialogflowcx_v3.types.Webhook): Required. The webhook to update. - update_mask (~.field_mask.FieldMask): + update_mask (google.protobuf.field_mask_pb2.FieldMask): The mask to control which fields get updated. If the mask is not present, all fields will be updated. @@ -239,22 +239,27 @@ class WebhookRequest(proto.Message): Always present. The unique identifier of the [DetectIntentResponse][google.cloud.dialogflow.cx.v3.DetectIntentResponse] that will be returned to the API caller. - fulfillment_info (~.gcdc_webhook.WebhookRequest.FulfillmentInfo): + fulfillment_info (google.cloud.dialogflowcx_v3.types.WebhookRequest.FulfillmentInfo): Always present. Information about the fulfillment that triggered this webhook call. - intent_info (~.gcdc_webhook.WebhookRequest.IntentInfo): + intent_info (google.cloud.dialogflowcx_v3.types.WebhookRequest.IntentInfo): Information about the last matched intent. - page_info (~.gcdc_webhook.PageInfo): + page_info (google.cloud.dialogflowcx_v3.types.PageInfo): Information about page status. - session_info (~.gcdc_webhook.SessionInfo): + session_info (google.cloud.dialogflowcx_v3.types.SessionInfo): Information about session status. - messages (Sequence[~.response_message.ResponseMessage]): + messages (Sequence[google.cloud.dialogflowcx_v3.types.ResponseMessage]): The list of rich message responses to present to the user. Webhook can choose to append or replace this list in [WebhookResponse.fulfillment_response][google.cloud.dialogflow.cx.v3.WebhookResponse.fulfillment_response]; - payload (~.struct.Struct): + payload (google.protobuf.struct_pb2.Struct): Custom data set in [QueryParameters.payload][google.cloud.dialogflow.cx.v3.QueryParameters.payload]. + sentiment_analysis_result (google.cloud.dialogflowcx_v3.types.WebhookRequest.SentimentAnalysisResult): + The sentiment analysis result of the current + user request. The field is filled when sentiment + analysis is configured to be enabled for the + request. """ class FulfillmentInfo(proto.Message): @@ -277,13 +282,20 @@ class IntentInfo(proto.Message): Always present. The unique identifier of the last matched [intent][google.cloud.dialogflow.cx.v3.Intent]. Format: ``projects//locations//agents//intents/``. - parameters (Sequence[~.gcdc_webhook.WebhookRequest.IntentInfo.ParametersEntry]): + display_name (str): + Always present. The display name of the last matched + [intent][google.cloud.dialogflow.cx.v3.Intent]. + parameters (Sequence[google.cloud.dialogflowcx_v3.types.WebhookRequest.IntentInfo.ParametersEntry]): Parameters identified as a result of intent matching. This is a map of the name of the identified parameter to the value of the parameter identified from the user's utterance. All parameters defined in the matched intent that are identified will be surfaced here. + confidence (float): + The confidence of the matched intent. Values + range from 0.0 (completely uncertain) to 1.0 + (completely certain). """ class IntentParameterValue(proto.Message): @@ -293,7 +305,7 @@ class IntentParameterValue(proto.Message): original_value (str): Always present. Original text value extracted from user utterance. - resolved_value (~.struct.Value): + resolved_value (google.protobuf.struct_pb2.Value): Always present. Structured value for the parameter extracted from user utterance. """ @@ -304,6 +316,8 @@ class IntentParameterValue(proto.Message): last_matched_intent = proto.Field(proto.STRING, number=1) + display_name = proto.Field(proto.STRING, number=3) + parameters = proto.MapField( proto.STRING, proto.MESSAGE, @@ -311,6 +325,25 @@ class IntentParameterValue(proto.Message): message="WebhookRequest.IntentInfo.IntentParameterValue", ) + confidence = proto.Field(proto.FLOAT, number=4) + + class SentimentAnalysisResult(proto.Message): + r"""Represents the result of sentiment analysis. + + Attributes: + score (float): + Sentiment score between -1.0 (negative + sentiment) and 1.0 (positive sentiment). + magnitude (float): + A non-negative number in the [0, +inf) range, which + represents the absolute magnitude of sentiment, regardless + of score (positive or negative). + """ + + score = proto.Field(proto.FLOAT, number=1) + + magnitude = proto.Field(proto.FLOAT, number=2) + detect_intent_response_id = proto.Field(proto.STRING, number=1) fulfillment_info = proto.Field(proto.MESSAGE, number=6, message=FulfillmentInfo,) @@ -327,25 +360,29 @@ class IntentParameterValue(proto.Message): payload = proto.Field(proto.MESSAGE, number=8, message=struct.Struct,) + sentiment_analysis_result = proto.Field( + proto.MESSAGE, number=9, message=SentimentAnalysisResult, + ) + class WebhookResponse(proto.Message): r"""The response message for a webhook call. Attributes: - fulfillment_response (~.gcdc_webhook.WebhookResponse.FulfillmentResponse): + fulfillment_response (google.cloud.dialogflowcx_v3.types.WebhookResponse.FulfillmentResponse): The fulfillment response to send to the user. This field can be omitted by the webhook if it does not intend to send any response to the user. - page_info (~.gcdc_webhook.PageInfo): + page_info (google.cloud.dialogflowcx_v3.types.PageInfo): Information about page status. This field can be omitted by the webhook if it does not intend to modify page status. - session_info (~.gcdc_webhook.SessionInfo): + session_info (google.cloud.dialogflowcx_v3.types.SessionInfo): Information about session status. This field can be omitted by the webhook if it does not intend to modify session status. - payload (~.struct.Struct): + payload (google.protobuf.struct_pb2.Struct): Value to append directly to [QueryResult.webhook_payloads][google.cloud.dialogflow.cx.v3.QueryResult.webhook_payloads]. target_page (str): @@ -360,10 +397,10 @@ class FulfillmentResponse(proto.Message): r"""Represents a fulfillment response to the user. Attributes: - messages (Sequence[~.response_message.ResponseMessage]): + messages (Sequence[google.cloud.dialogflowcx_v3.types.ResponseMessage]): The list of rich message responses to present to the user. - merge_behavior (~.gcdc_webhook.WebhookResponse.FulfillmentResponse.MergeBehavior): + merge_behavior (google.cloud.dialogflowcx_v3.types.WebhookResponse.FulfillmentResponse.MergeBehavior): Merge behavior for ``messages``. """ @@ -410,7 +447,7 @@ class PageInfo(proto.Message): [WebhookResponse][google.cloud.dialogflow.cx.v3.WebhookResponse]. The unique identifier of the current page. Format: ``projects//locations//agents//flows//pages/``. - form_info (~.gcdc_webhook.PageInfo.FormInfo): + form_info (google.cloud.dialogflowcx_v3.types.PageInfo.FormInfo): Optional for both [WebhookRequest][google.cloud.dialogflow.cx.v3.WebhookRequest] and @@ -422,7 +459,7 @@ class FormInfo(proto.Message): r"""Represents form information. Attributes: - parameter_info (Sequence[~.gcdc_webhook.PageInfo.FormInfo.ParameterInfo]): + parameter_info (Sequence[google.cloud.dialogflowcx_v3.types.PageInfo.FormInfo.ParameterInfo]): Optional for both [WebhookRequest][google.cloud.dialogflow.cx.v3.WebhookRequest] and @@ -451,7 +488,7 @@ class ParameterInfo(proto.Message): parameters will not trigger prompts; however, they are filled if the user specifies them. Required parameters must be filled before form filling concludes. - state (~.gcdc_webhook.PageInfo.FormInfo.ParameterInfo.ParameterState): + state (google.cloud.dialogflowcx_v3.types.PageInfo.FormInfo.ParameterInfo.ParameterState): Always present for [WebhookRequest][google.cloud.dialogflow.cx.v3.WebhookRequest]. Required for @@ -460,7 +497,7 @@ class ParameterInfo(proto.Message): [INVALID][google.cloud.dialogflow.cx.v3.PageInfo.FormInfo.ParameterInfo.ParameterState.INVALID] by the webhook to invalidate the parameter; other values set by the webhook will be ignored. - value (~.struct.Value): + value (google.protobuf.struct_pb2.Value): Optional for both [WebhookRequest][google.cloud.dialogflow.cx.v3.WebhookRequest] and @@ -518,10 +555,13 @@ class SessionInfo(proto.Message): [WebhookResponse][google.cloud.dialogflow.cx.v3.WebhookResponse]. The unique identifier of the [session][google.cloud.dialogflow.cx.v3.DetectIntentRequest.session]. - This field can be used by the webhook to identify a user. + This field can be used by the webhook to identify a session. Format: - ``projects//locations//agents//sessions/``. - parameters (Sequence[~.gcdc_webhook.SessionInfo.ParametersEntry]): + ``projects//locations//agents//sessions/`` + or + ``projects//locations//agents//environments//sessions/`` + if environment is specified. + parameters (Sequence[google.cloud.dialogflowcx_v3.types.SessionInfo.ParametersEntry]): Optional for [WebhookRequest][google.cloud.dialogflow.cx.v3.WebhookRequest]. Optional for diff --git a/google/cloud/dialogflowcx_v3beta1/__init__.py b/google/cloud/dialogflowcx_v3beta1/__init__.py index f78a8e10..b85b6810 100644 --- a/google/cloud/dialogflowcx_v3beta1/__init__.py +++ b/google/cloud/dialogflowcx_v3beta1/__init__.py @@ -25,20 +25,24 @@ from .services.security_settings_service import SecuritySettingsServiceClient from .services.session_entity_types import SessionEntityTypesClient from .services.sessions import SessionsClient +from .services.test_cases import TestCasesClient from .services.transition_route_groups import TransitionRouteGroupsClient from .services.versions import VersionsClient from .services.webhooks import WebhooksClient from .types.agent import Agent +from .types.agent import AgentValidationResult from .types.agent import CreateAgentRequest from .types.agent import DeleteAgentRequest from .types.agent import ExportAgentRequest from .types.agent import ExportAgentResponse from .types.agent import GetAgentRequest +from .types.agent import GetAgentValidationResultRequest from .types.agent import ListAgentsRequest from .types.agent import ListAgentsResponse from .types.agent import RestoreAgentRequest from .types.agent import SpeechToTextSettings from .types.agent import UpdateAgentRequest +from .types.agent import ValidateAgentRequest from .types.audio_config import AudioEncoding from .types.audio_config import InputAudioConfig from .types.audio_config import OutputAudioConfig @@ -78,12 +82,15 @@ from .types.flow import CreateFlowRequest from .types.flow import DeleteFlowRequest from .types.flow import Flow +from .types.flow import FlowValidationResult from .types.flow import GetFlowRequest +from .types.flow import GetFlowValidationResultRequest from .types.flow import ListFlowsRequest from .types.flow import ListFlowsResponse from .types.flow import NluSettings from .types.flow import TrainFlowRequest from .types.flow import UpdateFlowRequest +from .types.flow import ValidateFlowRequest from .types.fulfillment import Fulfillment from .types.intent import CreateIntentRequest from .types.intent import DeleteIntentRequest @@ -137,6 +144,39 @@ from .types.session_entity_type import ListSessionEntityTypesResponse from .types.session_entity_type import SessionEntityType from .types.session_entity_type import UpdateSessionEntityTypeRequest +from .types.test_case import BatchDeleteTestCasesRequest +from .types.test_case import BatchRunTestCasesMetadata +from .types.test_case import BatchRunTestCasesRequest +from .types.test_case import BatchRunTestCasesResponse +from .types.test_case import CalculateCoverageRequest +from .types.test_case import CalculateCoverageResponse +from .types.test_case import ConversationTurn +from .types.test_case import CreateTestCaseRequest +from .types.test_case import ExportTestCasesMetadata +from .types.test_case import ExportTestCasesRequest +from .types.test_case import ExportTestCasesResponse +from .types.test_case import GetTestCaseRequest +from .types.test_case import ImportTestCasesMetadata +from .types.test_case import ImportTestCasesRequest +from .types.test_case import ImportTestCasesResponse +from .types.test_case import IntentCoverage +from .types.test_case import ListTestCaseResultsRequest +from .types.test_case import ListTestCaseResultsResponse +from .types.test_case import ListTestCasesRequest +from .types.test_case import ListTestCasesResponse +from .types.test_case import RunTestCaseMetadata +from .types.test_case import RunTestCaseRequest +from .types.test_case import RunTestCaseResponse +from .types.test_case import TestCase +from .types.test_case import TestCaseError +from .types.test_case import TestCaseResult +from .types.test_case import TestConfig +from .types.test_case import TestError +from .types.test_case import TestResult +from .types.test_case import TestRunDifference +from .types.test_case import TransitionCoverage +from .types.test_case import TransitionRouteGroupCoverage +from .types.test_case import UpdateTestCaseRequest from .types.transition_route_group import CreateTransitionRouteGroupRequest from .types.transition_route_group import DeleteTransitionRouteGroupRequest from .types.transition_route_group import GetTransitionRouteGroupRequest @@ -144,6 +184,8 @@ from .types.transition_route_group import ListTransitionRouteGroupsResponse from .types.transition_route_group import TransitionRouteGroup from .types.transition_route_group import UpdateTransitionRouteGroupRequest +from .types.validation_message import ResourceName +from .types.validation_message import ValidationMessage from .types.version import CreateVersionOperationMetadata from .types.version import CreateVersionRequest from .types.version import DeleteVersionRequest @@ -168,8 +210,17 @@ __all__ = ( "Agent", + "AgentValidationResult", + "AgentsClient", "AudioEncoding", "AudioInput", + "BatchDeleteTestCasesRequest", + "BatchRunTestCasesMetadata", + "BatchRunTestCasesRequest", + "BatchRunTestCasesResponse", + "CalculateCoverageRequest", + "CalculateCoverageResponse", + "ConversationTurn", "CreateAgentRequest", "CreateEntityTypeRequest", "CreateEnvironmentRequest", @@ -179,6 +230,7 @@ "CreatePageRequest", "CreateSecuritySettingsRequest", "CreateSessionEntityTypeRequest", + "CreateTestCaseRequest", "CreateTransitionRouteGroupRequest", "CreateVersionOperationMetadata", "CreateVersionRequest", @@ -199,6 +251,7 @@ "DetectIntentResponse", "DtmfInput", "EntityType", + "EntityTypesClient", "Environment", "EnvironmentsClient", "EventHandler", @@ -207,26 +260,37 @@ "ExperimentsClient", "ExportAgentRequest", "ExportAgentResponse", + "ExportTestCasesMetadata", + "ExportTestCasesRequest", + "ExportTestCasesResponse", "Flow", + "FlowValidationResult", "FlowsClient", "Form", "FulfillIntentRequest", "FulfillIntentResponse", "Fulfillment", "GetAgentRequest", + "GetAgentValidationResultRequest", "GetEntityTypeRequest", "GetEnvironmentRequest", "GetExperimentRequest", "GetFlowRequest", + "GetFlowValidationResultRequest", "GetIntentRequest", "GetPageRequest", "GetSecuritySettingsRequest", "GetSessionEntityTypeRequest", + "GetTestCaseRequest", "GetTransitionRouteGroupRequest", "GetVersionRequest", "GetWebhookRequest", + "ImportTestCasesMetadata", + "ImportTestCasesRequest", + "ImportTestCasesResponse", "InputAudioConfig", "Intent", + "IntentCoverage", "IntentInput", "IntentView", "IntentsClient", @@ -248,6 +312,10 @@ "ListSecuritySettingsResponse", "ListSessionEntityTypesRequest", "ListSessionEntityTypesResponse", + "ListTestCaseResultsRequest", + "ListTestCaseResultsResponse", + "ListTestCasesRequest", + "ListTestCasesResponse", "ListTransitionRouteGroupsRequest", "ListTransitionRouteGroupsResponse", "ListVersionsRequest", @@ -269,8 +337,12 @@ "QueryInput", "QueryParameters", "QueryResult", + "ResourceName", "ResponseMessage", "RestoreAgentRequest", + "RunTestCaseMetadata", + "RunTestCaseRequest", + "RunTestCaseResponse", "SecuritySettings", "SecuritySettingsServiceClient", "SentimentAnalysisResult", @@ -288,10 +360,20 @@ "StreamingDetectIntentResponse", "StreamingRecognitionResult", "SynthesizeSpeechConfig", + "TestCase", + "TestCaseError", + "TestCaseResult", + "TestCasesClient", + "TestConfig", + "TestError", + "TestResult", + "TestRunDifference", "TextInput", "TrainFlowRequest", + "TransitionCoverage", "TransitionRoute", "TransitionRouteGroup", + "TransitionRouteGroupCoverage", "TransitionRouteGroupsClient", "UpdateAgentRequest", "UpdateEntityTypeRequest", @@ -302,9 +384,13 @@ "UpdatePageRequest", "UpdateSecuritySettingsRequest", "UpdateSessionEntityTypeRequest", + "UpdateTestCaseRequest", "UpdateTransitionRouteGroupRequest", "UpdateVersionRequest", "UpdateWebhookRequest", + "ValidateAgentRequest", + "ValidateFlowRequest", + "ValidationMessage", "VariantsHistory", "Version", "VersionVariants", @@ -314,6 +400,4 @@ "WebhookRequest", "WebhookResponse", "WebhooksClient", - "AgentsClient", - "EntityTypesClient", ) diff --git a/google/cloud/dialogflowcx_v3beta1/services/agents/async_client.py b/google/cloud/dialogflowcx_v3beta1/services/agents/async_client.py index 30132710..7af9f303 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/agents/async_client.py +++ b/google/cloud/dialogflowcx_v3beta1/services/agents/async_client.py @@ -33,6 +33,7 @@ from google.cloud.dialogflowcx_v3beta1.services.agents import pagers from google.cloud.dialogflowcx_v3beta1.types import agent from google.cloud.dialogflowcx_v3beta1.types import agent as gcdc_agent +from google.cloud.dialogflowcx_v3beta1.types import flow from google.protobuf import empty_pb2 as empty # type: ignore from google.protobuf import field_mask_pb2 as field_mask # type: ignore from google.protobuf import struct_pb2 as struct # type: ignore @@ -54,8 +55,22 @@ class AgentsAsyncClient: agent_path = staticmethod(AgentsClient.agent_path) parse_agent_path = staticmethod(AgentsClient.parse_agent_path) + agent_validation_result_path = staticmethod( + AgentsClient.agent_validation_result_path + ) + parse_agent_validation_result_path = staticmethod( + AgentsClient.parse_agent_validation_result_path + ) flow_path = staticmethod(AgentsClient.flow_path) parse_flow_path = staticmethod(AgentsClient.parse_flow_path) + flow_validation_result_path = staticmethod(AgentsClient.flow_validation_result_path) + parse_flow_validation_result_path = staticmethod( + AgentsClient.parse_flow_validation_result_path + ) + security_settings_path = staticmethod(AgentsClient.security_settings_path) + parse_security_settings_path = staticmethod( + AgentsClient.parse_security_settings_path + ) common_billing_account_path = staticmethod(AgentsClient.common_billing_account_path) parse_common_billing_account_path = staticmethod( @@ -76,7 +91,36 @@ class AgentsAsyncClient: common_location_path = staticmethod(AgentsClient.common_location_path) parse_common_location_path = staticmethod(AgentsClient.parse_common_location_path) - from_service_account_file = AgentsClient.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: + AgentsAsyncClient: The constructed client. + """ + return AgentsClient.from_service_account_info.__func__(AgentsAsyncClient, 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: + AgentsAsyncClient: The constructed client. + """ + return AgentsClient.from_service_account_file.__func__(AgentsAsyncClient, filename, *args, **kwargs) # type: ignore + from_service_account_json = from_service_account_file @property @@ -153,12 +197,13 @@ async def list_agents( location. Args: - request (:class:`~.agent.ListAgentsRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.ListAgentsRequest`): The request object. The request message for [Agents.ListAgents][google.cloud.dialogflow.cx.v3beta1.Agents.ListAgents]. parent (:class:`str`): Required. The location to list all agents for. Format: ``projects//locations/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -170,7 +215,7 @@ async def list_agents( sent along with the request as metadata. Returns: - ~.pagers.ListAgentsAsyncPager: + google.cloud.dialogflowcx_v3beta1.services.agents.pagers.ListAgentsAsyncPager: The response message for [Agents.ListAgents][google.cloud.dialogflow.cx.v3beta1.Agents.ListAgents]. @@ -234,12 +279,13 @@ async def get_agent( r"""Retrieves the specified agent. Args: - request (:class:`~.agent.GetAgentRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.GetAgentRequest`): The request object. The request message for [Agents.GetAgent][google.cloud.dialogflow.cx.v3beta1.Agents.GetAgent]. name (:class:`str`): Required. The name of the agent. Format: ``projects//locations//agents/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -251,21 +297,21 @@ async def get_agent( sent along with the request as metadata. Returns: - ~.agent.Agent: - Agents are best described as Natural Language - Understanding (NLU) modules that transform user requests - into actionable data. You can include agents in your - app, product, or service to determine user intent and - respond to the user in a natural way. - - After you create an agent, you can add - [Intents][google.cloud.dialogflow.cx.v3beta1.Intent], - [Entity - Types][google.cloud.dialogflow.cx.v3beta1.EntityType], - [Flows][google.cloud.dialogflow.cx.v3beta1.Flow], - [Fulfillments][google.cloud.dialogflow.cx.v3beta1.Fulfillment], - [Webhooks][google.cloud.dialogflow.cx.v3beta1.Webhook], - and so on to manage the conversation flows.. + google.cloud.dialogflowcx_v3beta1.types.Agent: + Agents are best described as Natural Language Understanding (NLU) modules + that transform user requests into actionable data. + You can include agents in your app, product, or + service to determine user intent and respond to the + user in a natural way. + + After you create an agent, you can add + [Intents][google.cloud.dialogflow.cx.v3beta1.Intent], + [Entity + Types][google.cloud.dialogflow.cx.v3beta1.EntityType], + [Flows][google.cloud.dialogflow.cx.v3beta1.Flow], + [Fulfillments][google.cloud.dialogflow.cx.v3beta1.Fulfillment], + [Webhooks][google.cloud.dialogflow.cx.v3beta1.Webhook], + and so on to manage the conversation flows.. """ # Create or coerce a protobuf request object. @@ -319,16 +365,17 @@ async def create_agent( r"""Creates an agent in the specified location. Args: - request (:class:`~.gcdc_agent.CreateAgentRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.CreateAgentRequest`): The request object. The request message for [Agents.CreateAgent][google.cloud.dialogflow.cx.v3beta1.Agents.CreateAgent]. parent (:class:`str`): Required. The location to create a agent for. Format: ``projects//locations/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - agent (:class:`~.gcdc_agent.Agent`): + agent (:class:`google.cloud.dialogflowcx_v3beta1.types.Agent`): Required. The agent to create. This corresponds to the ``agent`` field on the ``request`` instance; if ``request`` is provided, this @@ -341,21 +388,21 @@ async def create_agent( sent along with the request as metadata. Returns: - ~.gcdc_agent.Agent: - Agents are best described as Natural Language - Understanding (NLU) modules that transform user requests - into actionable data. You can include agents in your - app, product, or service to determine user intent and - respond to the user in a natural way. - - After you create an agent, you can add - [Intents][google.cloud.dialogflow.cx.v3beta1.Intent], - [Entity - Types][google.cloud.dialogflow.cx.v3beta1.EntityType], - [Flows][google.cloud.dialogflow.cx.v3beta1.Flow], - [Fulfillments][google.cloud.dialogflow.cx.v3beta1.Fulfillment], - [Webhooks][google.cloud.dialogflow.cx.v3beta1.Webhook], - and so on to manage the conversation flows.. + google.cloud.dialogflowcx_v3beta1.types.Agent: + Agents are best described as Natural Language Understanding (NLU) modules + that transform user requests into actionable data. + You can include agents in your app, product, or + service to determine user intent and respond to the + user in a natural way. + + After you create an agent, you can add + [Intents][google.cloud.dialogflow.cx.v3beta1.Intent], + [Entity + Types][google.cloud.dialogflow.cx.v3beta1.EntityType], + [Flows][google.cloud.dialogflow.cx.v3beta1.Flow], + [Fulfillments][google.cloud.dialogflow.cx.v3beta1.Fulfillment], + [Webhooks][google.cloud.dialogflow.cx.v3beta1.Webhook], + and so on to manage the conversation flows.. """ # Create or coerce a protobuf request object. @@ -411,18 +458,19 @@ async def update_agent( r"""Updates the specified agent. Args: - request (:class:`~.gcdc_agent.UpdateAgentRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.UpdateAgentRequest`): The request object. The request message for [Agents.UpdateAgent][google.cloud.dialogflow.cx.v3beta1.Agents.UpdateAgent]. - agent (:class:`~.gcdc_agent.Agent`): + agent (:class:`google.cloud.dialogflowcx_v3beta1.types.Agent`): Required. The agent to update. This corresponds to the ``agent`` 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`): The mask to control which fields get updated. If the mask is not present, all fields will be updated. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -434,21 +482,21 @@ async def update_agent( sent along with the request as metadata. Returns: - ~.gcdc_agent.Agent: - Agents are best described as Natural Language - Understanding (NLU) modules that transform user requests - into actionable data. You can include agents in your - app, product, or service to determine user intent and - respond to the user in a natural way. - - After you create an agent, you can add - [Intents][google.cloud.dialogflow.cx.v3beta1.Intent], - [Entity - Types][google.cloud.dialogflow.cx.v3beta1.EntityType], - [Flows][google.cloud.dialogflow.cx.v3beta1.Flow], - [Fulfillments][google.cloud.dialogflow.cx.v3beta1.Fulfillment], - [Webhooks][google.cloud.dialogflow.cx.v3beta1.Webhook], - and so on to manage the conversation flows.. + google.cloud.dialogflowcx_v3beta1.types.Agent: + Agents are best described as Natural Language Understanding (NLU) modules + that transform user requests into actionable data. + You can include agents in your app, product, or + service to determine user intent and respond to the + user in a natural way. + + After you create an agent, you can add + [Intents][google.cloud.dialogflow.cx.v3beta1.Intent], + [Entity + Types][google.cloud.dialogflow.cx.v3beta1.EntityType], + [Flows][google.cloud.dialogflow.cx.v3beta1.Flow], + [Fulfillments][google.cloud.dialogflow.cx.v3beta1.Fulfillment], + [Webhooks][google.cloud.dialogflow.cx.v3beta1.Webhook], + and so on to manage the conversation flows.. """ # Create or coerce a protobuf request object. @@ -505,12 +553,13 @@ async def delete_agent( r"""Deletes the specified agent. Args: - request (:class:`~.agent.DeleteAgentRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.DeleteAgentRequest`): The request object. The request message for [Agents.DeleteAgent][google.cloud.dialogflow.cx.v3beta1.Agents.DeleteAgent]. name (:class:`str`): Required. The name of the agent to delete. Format: ``projects//locations//agents/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -569,7 +618,7 @@ async def export_agent( r"""Exports the specified agent to a binary file. Args: - request (:class:`~.agent.ExportAgentRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.ExportAgentRequest`): The request object. The request message for [Agents.ExportAgent][google.cloud.dialogflow.cx.v3beta1.Agents.ExportAgent]. @@ -580,12 +629,12 @@ async def export_agent( 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:``~.agent.ExportAgentResponse``: The response - message for + :class:`google.cloud.dialogflowcx_v3beta1.types.ExportAgentResponse` + The response message for [Agents.ExportAgent][google.cloud.dialogflow.cx.v3beta1.Agents.ExportAgent]. """ @@ -635,7 +684,7 @@ async def restore_agent( flows) will be removed. Args: - request (:class:`~.agent.RestoreAgentRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.RestoreAgentRequest`): The request object. The request message for [Agents.RestoreAgent][google.cloud.dialogflow.cx.v3beta1.Agents.RestoreAgent]. @@ -646,24 +695,22 @@ async def restore_agent( 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:``~.empty.Empty``: A generic empty message that - you can re-use to avoid defining duplicated empty - messages in your APIs. A typical example is to use it as - the request or the response type of an API method. For - instance: + The result type for the operation will be :class:`google.protobuf.empty_pb2.Empty` A generic empty message that you can re-use to avoid defining duplicated + empty messages in your APIs. A typical example is to + use it as the request or the response type of an API + method. For instance: - :: + service Foo { + rpc Bar(google.protobuf.Empty) returns + (google.protobuf.Empty); - service Foo { - rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty); - } + } - The JSON representation for ``Empty`` is empty JSON - object ``{}``. + The JSON representation for Empty is empty JSON + object {}. """ # Create or coerce a protobuf request object. @@ -698,6 +745,134 @@ async def restore_agent( # Done; return the response. return response + async def validate_agent( + self, + request: agent.ValidateAgentRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> agent.AgentValidationResult: + r"""Validates the specified agent and creates or updates + validation results. The agent in draft version is + validated. Please call this API after the training is + completed to get the complete validation results. + + Args: + request (:class:`google.cloud.dialogflowcx_v3beta1.types.ValidateAgentRequest`): + The request object. The request message for + [Agents.ValidateAgent][google.cloud.dialogflow.cx.v3beta1.Agents.ValidateAgent]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.dialogflowcx_v3beta1.types.AgentValidationResult: + The response message for + [Agents.GetAgentValidationResult][google.cloud.dialogflow.cx.v3beta1.Agents.GetAgentValidationResult]. + + """ + # Create or coerce a protobuf request object. + + request = agent.ValidateAgentRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.validate_agent, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = await rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + + async def get_agent_validation_result( + self, + request: agent.GetAgentValidationResultRequest = None, + *, + name: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> agent.AgentValidationResult: + r"""Gets the latest agent validation result. Agent + validation is performed when ValidateAgent is called. + + Args: + request (:class:`google.cloud.dialogflowcx_v3beta1.types.GetAgentValidationResultRequest`): + The request object. The request message for + [Agents.GetAgentValidationResult][google.cloud.dialogflow.cx.v3beta1.Agents.GetAgentValidationResult]. + name (:class:`str`): + Required. The agent name. Format: + ``projects//locations//agents//validationResult``. + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.dialogflowcx_v3beta1.types.AgentValidationResult: + The response message for + [Agents.GetAgentValidationResult][google.cloud.dialogflow.cx.v3beta1.Agents.GetAgentValidationResult]. + + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = agent.GetAgentValidationResultRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.get_agent_validation_result, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = await rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + try: DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/google/cloud/dialogflowcx_v3beta1/services/agents/client.py b/google/cloud/dialogflowcx_v3beta1/services/agents/client.py index 1a81f6a3..2460aaa4 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/agents/client.py +++ b/google/cloud/dialogflowcx_v3beta1/services/agents/client.py @@ -37,6 +37,7 @@ from google.cloud.dialogflowcx_v3beta1.services.agents import pagers from google.cloud.dialogflowcx_v3beta1.types import agent from google.cloud.dialogflowcx_v3beta1.types import agent as gcdc_agent +from google.cloud.dialogflowcx_v3beta1.types import flow from google.protobuf import empty_pb2 as empty # type: ignore from google.protobuf import field_mask_pb2 as field_mask # type: ignore from google.protobuf import struct_pb2 as struct # type: ignore @@ -116,6 +117,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: + AgentsClient: 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 +145,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. + AgentsClient: The constructed client. """ credentials = service_account.Credentials.from_service_account_file(filename) kwargs["credentials"] = credentials @@ -161,6 +178,22 @@ def parse_agent_path(path: str) -> Dict[str, str]: ) return m.groupdict() if m else {} + @staticmethod + def agent_validation_result_path(project: str, location: str, agent: str,) -> str: + """Return a fully-qualified agent_validation_result string.""" + return "projects/{project}/locations/{location}/agents/{agent}/validationResult".format( + project=project, location=location, agent=agent, + ) + + @staticmethod + def parse_agent_validation_result_path(path: str) -> Dict[str, str]: + """Parse a agent_validation_result path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/locations/(?P.+?)/agents/(?P.+?)/validationResult$", + path, + ) + return m.groupdict() if m else {} + @staticmethod def flow_path(project: str, location: str, agent: str, flow: str,) -> str: """Return a fully-qualified flow string.""" @@ -177,6 +210,42 @@ def parse_flow_path(path: str) -> Dict[str, str]: ) return m.groupdict() if m else {} + @staticmethod + def flow_validation_result_path( + project: str, location: str, agent: str, flow: str, + ) -> str: + """Return a fully-qualified flow_validation_result string.""" + return "projects/{project}/locations/{location}/agents/{agent}/flows/{flow}/validationResult".format( + project=project, location=location, agent=agent, flow=flow, + ) + + @staticmethod + def parse_flow_validation_result_path(path: str) -> Dict[str, str]: + """Parse a flow_validation_result path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/locations/(?P.+?)/agents/(?P.+?)/flows/(?P.+?)/validationResult$", + path, + ) + return m.groupdict() if m else {} + + @staticmethod + def security_settings_path( + project: str, location: str, security_settings: str, + ) -> str: + """Return a fully-qualified security_settings string.""" + return "projects/{project}/locations/{location}/securitySettings/{security_settings}".format( + project=project, location=location, security_settings=security_settings, + ) + + @staticmethod + def parse_security_settings_path(path: str) -> Dict[str, str]: + """Parse a security_settings path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/locations/(?P.+?)/securitySettings/(?P.+?)$", + path, + ) + return m.groupdict() if m else {} + @staticmethod def common_billing_account_path(billing_account: str,) -> str: """Return a fully-qualified billing_account string.""" @@ -252,10 +321,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, ~.AgentsTransport]): The + transport (Union[str, AgentsTransport]): 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 +360,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 +413,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, ) @@ -366,12 +431,13 @@ def list_agents( location. Args: - request (:class:`~.agent.ListAgentsRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.ListAgentsRequest): The request object. The request message for [Agents.ListAgents][google.cloud.dialogflow.cx.v3beta1.Agents.ListAgents]. - parent (:class:`str`): + parent (str): Required. The location to list all agents for. Format: ``projects//locations/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -383,7 +449,7 @@ def list_agents( sent along with the request as metadata. Returns: - ~.pagers.ListAgentsPager: + google.cloud.dialogflowcx_v3beta1.services.agents.pagers.ListAgentsPager: The response message for [Agents.ListAgents][google.cloud.dialogflow.cx.v3beta1.Agents.ListAgents]. @@ -448,12 +514,13 @@ def get_agent( r"""Retrieves the specified agent. Args: - request (:class:`~.agent.GetAgentRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.GetAgentRequest): The request object. The request message for [Agents.GetAgent][google.cloud.dialogflow.cx.v3beta1.Agents.GetAgent]. - name (:class:`str`): + name (str): Required. The name of the agent. Format: ``projects//locations//agents/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -465,21 +532,21 @@ def get_agent( sent along with the request as metadata. Returns: - ~.agent.Agent: - Agents are best described as Natural Language - Understanding (NLU) modules that transform user requests - into actionable data. You can include agents in your - app, product, or service to determine user intent and - respond to the user in a natural way. - - After you create an agent, you can add - [Intents][google.cloud.dialogflow.cx.v3beta1.Intent], - [Entity - Types][google.cloud.dialogflow.cx.v3beta1.EntityType], - [Flows][google.cloud.dialogflow.cx.v3beta1.Flow], - [Fulfillments][google.cloud.dialogflow.cx.v3beta1.Fulfillment], - [Webhooks][google.cloud.dialogflow.cx.v3beta1.Webhook], - and so on to manage the conversation flows.. + google.cloud.dialogflowcx_v3beta1.types.Agent: + Agents are best described as Natural Language Understanding (NLU) modules + that transform user requests into actionable data. + You can include agents in your app, product, or + service to determine user intent and respond to the + user in a natural way. + + After you create an agent, you can add + [Intents][google.cloud.dialogflow.cx.v3beta1.Intent], + [Entity + Types][google.cloud.dialogflow.cx.v3beta1.EntityType], + [Flows][google.cloud.dialogflow.cx.v3beta1.Flow], + [Fulfillments][google.cloud.dialogflow.cx.v3beta1.Fulfillment], + [Webhooks][google.cloud.dialogflow.cx.v3beta1.Webhook], + and so on to manage the conversation flows.. """ # Create or coerce a protobuf request object. @@ -534,16 +601,17 @@ def create_agent( r"""Creates an agent in the specified location. Args: - request (:class:`~.gcdc_agent.CreateAgentRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.CreateAgentRequest): The request object. The request message for [Agents.CreateAgent][google.cloud.dialogflow.cx.v3beta1.Agents.CreateAgent]. - parent (:class:`str`): + parent (str): Required. The location to create a agent for. Format: ``projects//locations/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - agent (:class:`~.gcdc_agent.Agent`): + agent (google.cloud.dialogflowcx_v3beta1.types.Agent): Required. The agent to create. This corresponds to the ``agent`` field on the ``request`` instance; if ``request`` is provided, this @@ -556,21 +624,21 @@ def create_agent( sent along with the request as metadata. Returns: - ~.gcdc_agent.Agent: - Agents are best described as Natural Language - Understanding (NLU) modules that transform user requests - into actionable data. You can include agents in your - app, product, or service to determine user intent and - respond to the user in a natural way. - - After you create an agent, you can add - [Intents][google.cloud.dialogflow.cx.v3beta1.Intent], - [Entity - Types][google.cloud.dialogflow.cx.v3beta1.EntityType], - [Flows][google.cloud.dialogflow.cx.v3beta1.Flow], - [Fulfillments][google.cloud.dialogflow.cx.v3beta1.Fulfillment], - [Webhooks][google.cloud.dialogflow.cx.v3beta1.Webhook], - and so on to manage the conversation flows.. + google.cloud.dialogflowcx_v3beta1.types.Agent: + Agents are best described as Natural Language Understanding (NLU) modules + that transform user requests into actionable data. + You can include agents in your app, product, or + service to determine user intent and respond to the + user in a natural way. + + After you create an agent, you can add + [Intents][google.cloud.dialogflow.cx.v3beta1.Intent], + [Entity + Types][google.cloud.dialogflow.cx.v3beta1.EntityType], + [Flows][google.cloud.dialogflow.cx.v3beta1.Flow], + [Fulfillments][google.cloud.dialogflow.cx.v3beta1.Fulfillment], + [Webhooks][google.cloud.dialogflow.cx.v3beta1.Webhook], + and so on to manage the conversation flows.. """ # Create or coerce a protobuf request object. @@ -627,18 +695,19 @@ def update_agent( r"""Updates the specified agent. Args: - request (:class:`~.gcdc_agent.UpdateAgentRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.UpdateAgentRequest): The request object. The request message for [Agents.UpdateAgent][google.cloud.dialogflow.cx.v3beta1.Agents.UpdateAgent]. - agent (:class:`~.gcdc_agent.Agent`): + agent (google.cloud.dialogflowcx_v3beta1.types.Agent): Required. The agent to update. This corresponds to the ``agent`` 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): The mask to control which fields get updated. If the mask is not present, all fields will be updated. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -650,21 +719,21 @@ def update_agent( sent along with the request as metadata. Returns: - ~.gcdc_agent.Agent: - Agents are best described as Natural Language - Understanding (NLU) modules that transform user requests - into actionable data. You can include agents in your - app, product, or service to determine user intent and - respond to the user in a natural way. - - After you create an agent, you can add - [Intents][google.cloud.dialogflow.cx.v3beta1.Intent], - [Entity - Types][google.cloud.dialogflow.cx.v3beta1.EntityType], - [Flows][google.cloud.dialogflow.cx.v3beta1.Flow], - [Fulfillments][google.cloud.dialogflow.cx.v3beta1.Fulfillment], - [Webhooks][google.cloud.dialogflow.cx.v3beta1.Webhook], - and so on to manage the conversation flows.. + google.cloud.dialogflowcx_v3beta1.types.Agent: + Agents are best described as Natural Language Understanding (NLU) modules + that transform user requests into actionable data. + You can include agents in your app, product, or + service to determine user intent and respond to the + user in a natural way. + + After you create an agent, you can add + [Intents][google.cloud.dialogflow.cx.v3beta1.Intent], + [Entity + Types][google.cloud.dialogflow.cx.v3beta1.EntityType], + [Flows][google.cloud.dialogflow.cx.v3beta1.Flow], + [Fulfillments][google.cloud.dialogflow.cx.v3beta1.Fulfillment], + [Webhooks][google.cloud.dialogflow.cx.v3beta1.Webhook], + and so on to manage the conversation flows.. """ # Create or coerce a protobuf request object. @@ -722,12 +791,13 @@ def delete_agent( r"""Deletes the specified agent. Args: - request (:class:`~.agent.DeleteAgentRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.DeleteAgentRequest): The request object. The request message for [Agents.DeleteAgent][google.cloud.dialogflow.cx.v3beta1.Agents.DeleteAgent]. - name (:class:`str`): + name (str): Required. The name of the agent to delete. Format: ``projects//locations//agents/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -787,7 +857,7 @@ def export_agent( r"""Exports the specified agent to a binary file. Args: - request (:class:`~.agent.ExportAgentRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.ExportAgentRequest): The request object. The request message for [Agents.ExportAgent][google.cloud.dialogflow.cx.v3beta1.Agents.ExportAgent]. @@ -798,12 +868,12 @@ def export_agent( 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:``~.agent.ExportAgentResponse``: The response - message for + :class:`google.cloud.dialogflowcx_v3beta1.types.ExportAgentResponse` + The response message for [Agents.ExportAgent][google.cloud.dialogflow.cx.v3beta1.Agents.ExportAgent]. """ @@ -854,7 +924,7 @@ def restore_agent( flows) will be removed. Args: - request (:class:`~.agent.RestoreAgentRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.RestoreAgentRequest): The request object. The request message for [Agents.RestoreAgent][google.cloud.dialogflow.cx.v3beta1.Agents.RestoreAgent]. @@ -865,24 +935,22 @@ def restore_agent( 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:``~.empty.Empty``: A generic empty message that - you can re-use to avoid defining duplicated empty - messages in your APIs. A typical example is to use it as - the request or the response type of an API method. For - instance: + The result type for the operation will be :class:`google.protobuf.empty_pb2.Empty` A generic empty message that you can re-use to avoid defining duplicated + empty messages in your APIs. A typical example is to + use it as the request or the response type of an API + method. For instance: - :: + service Foo { + rpc Bar(google.protobuf.Empty) returns + (google.protobuf.Empty); - service Foo { - rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty); - } + } - The JSON representation for ``Empty`` is empty JSON - object ``{}``. + The JSON representation for Empty is empty JSON + object {}. """ # Create or coerce a protobuf request object. @@ -918,6 +986,138 @@ def restore_agent( # Done; return the response. return response + def validate_agent( + self, + request: agent.ValidateAgentRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> agent.AgentValidationResult: + r"""Validates the specified agent and creates or updates + validation results. The agent in draft version is + validated. Please call this API after the training is + completed to get the complete validation results. + + Args: + request (google.cloud.dialogflowcx_v3beta1.types.ValidateAgentRequest): + The request object. The request message for + [Agents.ValidateAgent][google.cloud.dialogflow.cx.v3beta1.Agents.ValidateAgent]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.dialogflowcx_v3beta1.types.AgentValidationResult: + The response message for + [Agents.GetAgentValidationResult][google.cloud.dialogflow.cx.v3beta1.Agents.GetAgentValidationResult]. + + """ + # Create or coerce a protobuf request object. + + # Minor optimization to avoid making a copy if the user passes + # in a agent.ValidateAgentRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, agent.ValidateAgentRequest): + request = agent.ValidateAgentRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.validate_agent] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + + def get_agent_validation_result( + self, + request: agent.GetAgentValidationResultRequest = None, + *, + name: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> agent.AgentValidationResult: + r"""Gets the latest agent validation result. Agent + validation is performed when ValidateAgent is called. + + Args: + request (google.cloud.dialogflowcx_v3beta1.types.GetAgentValidationResultRequest): + The request object. The request message for + [Agents.GetAgentValidationResult][google.cloud.dialogflow.cx.v3beta1.Agents.GetAgentValidationResult]. + name (str): + Required. The agent name. Format: + ``projects//locations//agents//validationResult``. + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.dialogflowcx_v3beta1.types.AgentValidationResult: + The response message for + [Agents.GetAgentValidationResult][google.cloud.dialogflow.cx.v3beta1.Agents.GetAgentValidationResult]. + + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a agent.GetAgentValidationResultRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, agent.GetAgentValidationResultRequest): + request = agent.GetAgentValidationResultRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[ + self._transport.get_agent_validation_result + ] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + try: DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/google/cloud/dialogflowcx_v3beta1/services/agents/pagers.py b/google/cloud/dialogflowcx_v3beta1/services/agents/pagers.py index 6b1ee5be..2f8efd7d 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/agents/pagers.py +++ b/google/cloud/dialogflowcx_v3beta1/services/agents/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.dialogflowcx_v3beta1.types import agent @@ -24,7 +33,7 @@ class ListAgentsPager: """A pager for iterating through ``list_agents`` requests. This class thinly wraps an initial - :class:`~.agent.ListAgentsResponse` object, and + :class:`google.cloud.dialogflowcx_v3beta1.types.ListAgentsResponse` object, and provides an ``__iter__`` method to iterate through its ``agents`` field. @@ -33,7 +42,7 @@ class ListAgentsPager: through the ``agents`` field on the corresponding responses. - All the usual :class:`~.agent.ListAgentsResponse` + All the usual :class:`google.cloud.dialogflowcx_v3beta1.types.ListAgentsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -51,9 +60,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.agent.ListAgentsRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.ListAgentsRequest): The initial request object. - response (:class:`~.agent.ListAgentsResponse`): + response (google.cloud.dialogflowcx_v3beta1.types.ListAgentsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -86,7 +95,7 @@ class ListAgentsAsyncPager: """A pager for iterating through ``list_agents`` requests. This class thinly wraps an initial - :class:`~.agent.ListAgentsResponse` object, and + :class:`google.cloud.dialogflowcx_v3beta1.types.ListAgentsResponse` object, and provides an ``__aiter__`` method to iterate through its ``agents`` field. @@ -95,7 +104,7 @@ class ListAgentsAsyncPager: through the ``agents`` field on the corresponding responses. - All the usual :class:`~.agent.ListAgentsResponse` + All the usual :class:`google.cloud.dialogflowcx_v3beta1.types.ListAgentsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -113,9 +122,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.agent.ListAgentsRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.ListAgentsRequest): The initial request object. - response (:class:`~.agent.ListAgentsResponse`): + response (google.cloud.dialogflowcx_v3beta1.types.ListAgentsResponse): 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/dialogflowcx_v3beta1/services/agents/transports/base.py b/google/cloud/dialogflowcx_v3beta1/services/agents/transports/base.py index 73da1c3b..5f3804f2 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/agents/transports/base.py +++ b/google/cloud/dialogflowcx_v3beta1/services/agents/transports/base.py @@ -134,6 +134,14 @@ def _prep_wrapped_messages(self, client_info): self.restore_agent: gapic_v1.method.wrap_method( self.restore_agent, default_timeout=None, client_info=client_info, ), + self.validate_agent: gapic_v1.method.wrap_method( + self.validate_agent, default_timeout=None, client_info=client_info, + ), + self.get_agent_validation_result: gapic_v1.method.wrap_method( + self.get_agent_validation_result, + default_timeout=None, + client_info=client_info, + ), } @property @@ -206,5 +214,27 @@ def restore_agent( ]: raise NotImplementedError() + @property + def validate_agent( + self, + ) -> typing.Callable[ + [agent.ValidateAgentRequest], + typing.Union[ + agent.AgentValidationResult, typing.Awaitable[agent.AgentValidationResult] + ], + ]: + raise NotImplementedError() + + @property + def get_agent_validation_result( + self, + ) -> typing.Callable[ + [agent.GetAgentValidationResultRequest], + typing.Union[ + agent.AgentValidationResult, typing.Awaitable[agent.AgentValidationResult] + ], + ]: + raise NotImplementedError() + __all__ = ("AgentsTransport",) diff --git a/google/cloud/dialogflowcx_v3beta1/services/agents/transports/grpc.py b/google/cloud/dialogflowcx_v3beta1/services/agents/transports/grpc.py index 9a68b3ca..3b1228b6 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/agents/transports/grpc.py +++ b/google/cloud/dialogflowcx_v3beta1/services/agents/transports/grpc.py @@ -62,6 +62,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: @@ -92,6 +93,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): @@ -108,6 +113,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -117,11 +127,6 @@ def __init__( 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 @@ -165,12 +170,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ @@ -439,5 +450,61 @@ def restore_agent( ) return self._stubs["restore_agent"] + @property + def validate_agent( + self, + ) -> Callable[[agent.ValidateAgentRequest], agent.AgentValidationResult]: + r"""Return a callable for the validate agent method over gRPC. + + Validates the specified agent and creates or updates + validation results. The agent in draft version is + validated. Please call this API after the training is + completed to get the complete validation results. + + Returns: + Callable[[~.ValidateAgentRequest], + ~.AgentValidationResult]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "validate_agent" not in self._stubs: + self._stubs["validate_agent"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3beta1.Agents/ValidateAgent", + request_serializer=agent.ValidateAgentRequest.serialize, + response_deserializer=agent.AgentValidationResult.deserialize, + ) + return self._stubs["validate_agent"] + + @property + def get_agent_validation_result( + self, + ) -> Callable[[agent.GetAgentValidationResultRequest], agent.AgentValidationResult]: + r"""Return a callable for the get agent validation result method over gRPC. + + Gets the latest agent validation result. Agent + validation is performed when ValidateAgent is called. + + Returns: + Callable[[~.GetAgentValidationResultRequest], + ~.AgentValidationResult]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_agent_validation_result" not in self._stubs: + self._stubs["get_agent_validation_result"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3beta1.Agents/GetAgentValidationResult", + request_serializer=agent.GetAgentValidationResultRequest.serialize, + response_deserializer=agent.AgentValidationResult.deserialize, + ) + return self._stubs["get_agent_validation_result"] + __all__ = ("AgentsGrpcTransport",) diff --git a/google/cloud/dialogflowcx_v3beta1/services/agents/transports/grpc_asyncio.py b/google/cloud/dialogflowcx_v3beta1/services/agents/transports/grpc_asyncio.py index 62a9bca4..db904280 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/agents/transports/grpc_asyncio.py +++ b/google/cloud/dialogflowcx_v3beta1/services/agents/transports/grpc_asyncio.py @@ -106,6 +106,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: @@ -137,6 +138,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): @@ -153,6 +158,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -162,11 +172,6 @@ def __init__( 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 @@ -210,12 +215,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ @@ -447,5 +458,63 @@ def restore_agent( ) return self._stubs["restore_agent"] + @property + def validate_agent( + self, + ) -> Callable[[agent.ValidateAgentRequest], Awaitable[agent.AgentValidationResult]]: + r"""Return a callable for the validate agent method over gRPC. + + Validates the specified agent and creates or updates + validation results. The agent in draft version is + validated. Please call this API after the training is + completed to get the complete validation results. + + Returns: + Callable[[~.ValidateAgentRequest], + Awaitable[~.AgentValidationResult]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "validate_agent" not in self._stubs: + self._stubs["validate_agent"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3beta1.Agents/ValidateAgent", + request_serializer=agent.ValidateAgentRequest.serialize, + response_deserializer=agent.AgentValidationResult.deserialize, + ) + return self._stubs["validate_agent"] + + @property + def get_agent_validation_result( + self, + ) -> Callable[ + [agent.GetAgentValidationResultRequest], Awaitable[agent.AgentValidationResult] + ]: + r"""Return a callable for the get agent validation result method over gRPC. + + Gets the latest agent validation result. Agent + validation is performed when ValidateAgent is called. + + Returns: + Callable[[~.GetAgentValidationResultRequest], + Awaitable[~.AgentValidationResult]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_agent_validation_result" not in self._stubs: + self._stubs["get_agent_validation_result"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3beta1.Agents/GetAgentValidationResult", + request_serializer=agent.GetAgentValidationResultRequest.serialize, + response_deserializer=agent.AgentValidationResult.deserialize, + ) + return self._stubs["get_agent_validation_result"] + __all__ = ("AgentsGrpcAsyncIOTransport",) diff --git a/google/cloud/dialogflowcx_v3beta1/services/entity_types/async_client.py b/google/cloud/dialogflowcx_v3beta1/services/entity_types/async_client.py index 66e40946..a60e969b 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/entity_types/async_client.py +++ b/google/cloud/dialogflowcx_v3beta1/services/entity_types/async_client.py @@ -76,7 +76,36 @@ class EntityTypesAsyncClient: EntityTypesClient.parse_common_location_path ) - from_service_account_file = EntityTypesClient.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: + EntityTypesAsyncClient: The constructed client. + """ + return EntityTypesClient.from_service_account_info.__func__(EntityTypesAsyncClient, 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: + EntityTypesAsyncClient: The constructed client. + """ + return EntityTypesClient.from_service_account_file.__func__(EntityTypesAsyncClient, filename, *args, **kwargs) # type: ignore + from_service_account_json = from_service_account_file @property @@ -153,13 +182,14 @@ async def list_entity_types( agent. Args: - request (:class:`~.entity_type.ListEntityTypesRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.ListEntityTypesRequest`): The request object. The request message for [EntityTypes.ListEntityTypes][google.cloud.dialogflow.cx.v3beta1.EntityTypes.ListEntityTypes]. parent (:class:`str`): Required. The agent to list all entity types for. Format: ``projects//locations//agents/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -171,7 +201,7 @@ async def list_entity_types( sent along with the request as metadata. Returns: - ~.pagers.ListEntityTypesAsyncPager: + google.cloud.dialogflowcx_v3beta1.services.entity_types.pagers.ListEntityTypesAsyncPager: The response message for [EntityTypes.ListEntityTypes][google.cloud.dialogflow.cx.v3beta1.EntityTypes.ListEntityTypes]. @@ -235,12 +265,13 @@ async def get_entity_type( r"""Retrieves the specified entity type. Args: - request (:class:`~.entity_type.GetEntityTypeRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.GetEntityTypeRequest`): The request object. The request message for [EntityTypes.GetEntityType][google.cloud.dialogflow.cx.v3beta1.EntityTypes.GetEntityType]. name (:class:`str`): Required. The name of the entity type. Format: ``projects//locations//agents//entityTypes/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -252,42 +283,41 @@ async def get_entity_type( sent along with the request as metadata. Returns: - ~.entity_type.EntityType: - Entities are extracted from user input and represent - parameters that are meaningful to your application. For - example, a date range, a proper name such as a - geographic location or landmark, and so on. Entities - represent actionable data for your application. - - When you define an entity, you can also include synonyms - that all map to that entity. For example, "soft drink", - "soda", "pop", and so on. - - There are three types of entities: - - - **System** - entities that are defined by the - Dialogflow API for common data types such as date, - time, currency, and so on. A system entity is - represented by the ``EntityType`` type. - - - **Custom** - entities that are defined by you that - represent actionable data that is meaningful to your - application. For example, you could define a - ``pizza.sauce`` entity for red or white pizza sauce, - a ``pizza.cheese`` entity for the different types of - cheese on a pizza, a ``pizza.topping`` entity for - different toppings, and so on. A custom entity is - represented by the ``EntityType`` type. - - - **User** - entities that are built for an individual - user such as favorites, preferences, playlists, and - so on. A user entity is represented by the - [SessionEntityType][google.cloud.dialogflow.cx.v3beta1.SessionEntityType] - type. - - For more information about entity types, see the - `Dialogflow - documentation `__. + google.cloud.dialogflowcx_v3beta1.types.EntityType: + Entities are extracted from user input and represent parameters that are + meaningful to your application. For example, a date + range, a proper name such as a geographic location or + landmark, and so on. Entities represent actionable + data for your application. + + When you define an entity, you can also include + synonyms that all map to that entity. For example, + "soft drink", "soda", "pop", and so on. + + There are three types of entities: + + - **System** - entities that are defined by the + Dialogflow API for common data types such as date, + time, currency, and so on. A system entity is + represented by the EntityType type. + - **Custom** - entities that are defined by you that + represent actionable data that is meaningful to + your application. For example, you could define a + pizza.sauce entity for red or white pizza sauce, a + pizza.cheese entity for the different types of + cheese on a pizza, a pizza.topping entity for + different toppings, and so on. A custom entity is + represented by the EntityType type. + - **User** - entities that are built for an + individual user such as favorites, preferences, + playlists, and so on. A user entity is represented + by the + [SessionEntityType][google.cloud.dialogflow.cx.v3beta1.SessionEntityType] + type. + + For more information about entity types, see the + [Dialogflow + documentation](\ https://cloud.google.com/dialogflow/docs/entities-overview). """ # Create or coerce a protobuf request object. @@ -341,16 +371,17 @@ async def create_entity_type( r"""Creates an entity type in the specified agent. Args: - request (:class:`~.gcdc_entity_type.CreateEntityTypeRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.CreateEntityTypeRequest`): The request object. The request message for [EntityTypes.CreateEntityType][google.cloud.dialogflow.cx.v3beta1.EntityTypes.CreateEntityType]. parent (:class:`str`): Required. The agent to create a entity type for. Format: ``projects//locations//agents/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - entity_type (:class:`~.gcdc_entity_type.EntityType`): + entity_type (:class:`google.cloud.dialogflowcx_v3beta1.types.EntityType`): Required. The entity type to create. This corresponds to the ``entity_type`` field on the ``request`` instance; if ``request`` is provided, this @@ -363,42 +394,41 @@ async def create_entity_type( sent along with the request as metadata. Returns: - ~.gcdc_entity_type.EntityType: - Entities are extracted from user input and represent - parameters that are meaningful to your application. For - example, a date range, a proper name such as a - geographic location or landmark, and so on. Entities - represent actionable data for your application. - - When you define an entity, you can also include synonyms - that all map to that entity. For example, "soft drink", - "soda", "pop", and so on. - - There are three types of entities: - - - **System** - entities that are defined by the - Dialogflow API for common data types such as date, - time, currency, and so on. A system entity is - represented by the ``EntityType`` type. - - - **Custom** - entities that are defined by you that - represent actionable data that is meaningful to your - application. For example, you could define a - ``pizza.sauce`` entity for red or white pizza sauce, - a ``pizza.cheese`` entity for the different types of - cheese on a pizza, a ``pizza.topping`` entity for - different toppings, and so on. A custom entity is - represented by the ``EntityType`` type. - - - **User** - entities that are built for an individual - user such as favorites, preferences, playlists, and - so on. A user entity is represented by the - [SessionEntityType][google.cloud.dialogflow.cx.v3beta1.SessionEntityType] - type. - - For more information about entity types, see the - `Dialogflow - documentation `__. + google.cloud.dialogflowcx_v3beta1.types.EntityType: + Entities are extracted from user input and represent parameters that are + meaningful to your application. For example, a date + range, a proper name such as a geographic location or + landmark, and so on. Entities represent actionable + data for your application. + + When you define an entity, you can also include + synonyms that all map to that entity. For example, + "soft drink", "soda", "pop", and so on. + + There are three types of entities: + + - **System** - entities that are defined by the + Dialogflow API for common data types such as date, + time, currency, and so on. A system entity is + represented by the EntityType type. + - **Custom** - entities that are defined by you that + represent actionable data that is meaningful to + your application. For example, you could define a + pizza.sauce entity for red or white pizza sauce, a + pizza.cheese entity for the different types of + cheese on a pizza, a pizza.topping entity for + different toppings, and so on. A custom entity is + represented by the EntityType type. + - **User** - entities that are built for an + individual user such as favorites, preferences, + playlists, and so on. A user entity is represented + by the + [SessionEntityType][google.cloud.dialogflow.cx.v3beta1.SessionEntityType] + type. + + For more information about entity types, see the + [Dialogflow + documentation](\ https://cloud.google.com/dialogflow/docs/entities-overview). """ # Create or coerce a protobuf request object. @@ -454,17 +484,18 @@ async def update_entity_type( r"""Updates the specified entity type. Args: - request (:class:`~.gcdc_entity_type.UpdateEntityTypeRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.UpdateEntityTypeRequest`): The request object. The request message for [EntityTypes.UpdateEntityType][google.cloud.dialogflow.cx.v3beta1.EntityTypes.UpdateEntityType]. - entity_type (:class:`~.gcdc_entity_type.EntityType`): + entity_type (:class:`google.cloud.dialogflowcx_v3beta1.types.EntityType`): Required. The entity type to update. This corresponds to the ``entity_type`` 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`): The mask to control which fields get updated. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -476,42 +507,41 @@ async def update_entity_type( sent along with the request as metadata. Returns: - ~.gcdc_entity_type.EntityType: - Entities are extracted from user input and represent - parameters that are meaningful to your application. For - example, a date range, a proper name such as a - geographic location or landmark, and so on. Entities - represent actionable data for your application. - - When you define an entity, you can also include synonyms - that all map to that entity. For example, "soft drink", - "soda", "pop", and so on. - - There are three types of entities: - - - **System** - entities that are defined by the - Dialogflow API for common data types such as date, - time, currency, and so on. A system entity is - represented by the ``EntityType`` type. - - - **Custom** - entities that are defined by you that - represent actionable data that is meaningful to your - application. For example, you could define a - ``pizza.sauce`` entity for red or white pizza sauce, - a ``pizza.cheese`` entity for the different types of - cheese on a pizza, a ``pizza.topping`` entity for - different toppings, and so on. A custom entity is - represented by the ``EntityType`` type. - - - **User** - entities that are built for an individual - user such as favorites, preferences, playlists, and - so on. A user entity is represented by the - [SessionEntityType][google.cloud.dialogflow.cx.v3beta1.SessionEntityType] - type. - - For more information about entity types, see the - `Dialogflow - documentation `__. + google.cloud.dialogflowcx_v3beta1.types.EntityType: + Entities are extracted from user input and represent parameters that are + meaningful to your application. For example, a date + range, a proper name such as a geographic location or + landmark, and so on. Entities represent actionable + data for your application. + + When you define an entity, you can also include + synonyms that all map to that entity. For example, + "soft drink", "soda", "pop", and so on. + + There are three types of entities: + + - **System** - entities that are defined by the + Dialogflow API for common data types such as date, + time, currency, and so on. A system entity is + represented by the EntityType type. + - **Custom** - entities that are defined by you that + represent actionable data that is meaningful to + your application. For example, you could define a + pizza.sauce entity for red or white pizza sauce, a + pizza.cheese entity for the different types of + cheese on a pizza, a pizza.topping entity for + different toppings, and so on. A custom entity is + represented by the EntityType type. + - **User** - entities that are built for an + individual user such as favorites, preferences, + playlists, and so on. A user entity is represented + by the + [SessionEntityType][google.cloud.dialogflow.cx.v3beta1.SessionEntityType] + type. + + For more information about entity types, see the + [Dialogflow + documentation](\ https://cloud.google.com/dialogflow/docs/entities-overview). """ # Create or coerce a protobuf request object. @@ -568,12 +598,13 @@ async def delete_entity_type( r"""Deletes the specified entity type. Args: - request (:class:`~.entity_type.DeleteEntityTypeRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.DeleteEntityTypeRequest`): The request object. The request message for [EntityTypes.DeleteEntityType][google.cloud.dialogflow.cx.v3beta1.EntityTypes.DeleteEntityType]. name (:class:`str`): Required. The name of the entity type to delete. Format: ``projects//locations//agents//entityTypes/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. diff --git a/google/cloud/dialogflowcx_v3beta1/services/entity_types/client.py b/google/cloud/dialogflowcx_v3beta1/services/entity_types/client.py index 6956b1f5..2876ad6e 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/entity_types/client.py +++ b/google/cloud/dialogflowcx_v3beta1/services/entity_types/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: + EntityTypesClient: 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. + EntityTypesClient: The constructed client. """ credentials = service_account.Credentials.from_service_account_file(filename) kwargs["credentials"] = credentials @@ -234,10 +250,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, ~.EntityTypesTransport]): The + transport (Union[str, EntityTypesTransport]): 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 @@ -273,21 +289,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: @@ -330,7 +342,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, ) @@ -348,13 +360,14 @@ def list_entity_types( agent. Args: - request (:class:`~.entity_type.ListEntityTypesRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.ListEntityTypesRequest): The request object. The request message for [EntityTypes.ListEntityTypes][google.cloud.dialogflow.cx.v3beta1.EntityTypes.ListEntityTypes]. - parent (:class:`str`): + parent (str): Required. The agent to list all entity types for. Format: ``projects//locations//agents/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -366,7 +379,7 @@ def list_entity_types( sent along with the request as metadata. Returns: - ~.pagers.ListEntityTypesPager: + google.cloud.dialogflowcx_v3beta1.services.entity_types.pagers.ListEntityTypesPager: The response message for [EntityTypes.ListEntityTypes][google.cloud.dialogflow.cx.v3beta1.EntityTypes.ListEntityTypes]. @@ -431,12 +444,13 @@ def get_entity_type( r"""Retrieves the specified entity type. Args: - request (:class:`~.entity_type.GetEntityTypeRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.GetEntityTypeRequest): The request object. The request message for [EntityTypes.GetEntityType][google.cloud.dialogflow.cx.v3beta1.EntityTypes.GetEntityType]. - name (:class:`str`): + name (str): Required. The name of the entity type. Format: ``projects//locations//agents//entityTypes/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -448,42 +462,41 @@ def get_entity_type( sent along with the request as metadata. Returns: - ~.entity_type.EntityType: - Entities are extracted from user input and represent - parameters that are meaningful to your application. For - example, a date range, a proper name such as a - geographic location or landmark, and so on. Entities - represent actionable data for your application. - - When you define an entity, you can also include synonyms - that all map to that entity. For example, "soft drink", - "soda", "pop", and so on. - - There are three types of entities: - - - **System** - entities that are defined by the - Dialogflow API for common data types such as date, - time, currency, and so on. A system entity is - represented by the ``EntityType`` type. - - - **Custom** - entities that are defined by you that - represent actionable data that is meaningful to your - application. For example, you could define a - ``pizza.sauce`` entity for red or white pizza sauce, - a ``pizza.cheese`` entity for the different types of - cheese on a pizza, a ``pizza.topping`` entity for - different toppings, and so on. A custom entity is - represented by the ``EntityType`` type. - - - **User** - entities that are built for an individual - user such as favorites, preferences, playlists, and - so on. A user entity is represented by the - [SessionEntityType][google.cloud.dialogflow.cx.v3beta1.SessionEntityType] - type. - - For more information about entity types, see the - `Dialogflow - documentation `__. + google.cloud.dialogflowcx_v3beta1.types.EntityType: + Entities are extracted from user input and represent parameters that are + meaningful to your application. For example, a date + range, a proper name such as a geographic location or + landmark, and so on. Entities represent actionable + data for your application. + + When you define an entity, you can also include + synonyms that all map to that entity. For example, + "soft drink", "soda", "pop", and so on. + + There are three types of entities: + + - **System** - entities that are defined by the + Dialogflow API for common data types such as date, + time, currency, and so on. A system entity is + represented by the EntityType type. + - **Custom** - entities that are defined by you that + represent actionable data that is meaningful to + your application. For example, you could define a + pizza.sauce entity for red or white pizza sauce, a + pizza.cheese entity for the different types of + cheese on a pizza, a pizza.topping entity for + different toppings, and so on. A custom entity is + represented by the EntityType type. + - **User** - entities that are built for an + individual user such as favorites, preferences, + playlists, and so on. A user entity is represented + by the + [SessionEntityType][google.cloud.dialogflow.cx.v3beta1.SessionEntityType] + type. + + For more information about entity types, see the + [Dialogflow + documentation](\ https://cloud.google.com/dialogflow/docs/entities-overview). """ # Create or coerce a protobuf request object. @@ -538,16 +551,17 @@ def create_entity_type( r"""Creates an entity type in the specified agent. Args: - request (:class:`~.gcdc_entity_type.CreateEntityTypeRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.CreateEntityTypeRequest): The request object. The request message for [EntityTypes.CreateEntityType][google.cloud.dialogflow.cx.v3beta1.EntityTypes.CreateEntityType]. - parent (:class:`str`): + parent (str): Required. The agent to create a entity type for. Format: ``projects//locations//agents/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - entity_type (:class:`~.gcdc_entity_type.EntityType`): + entity_type (google.cloud.dialogflowcx_v3beta1.types.EntityType): Required. The entity type to create. This corresponds to the ``entity_type`` field on the ``request`` instance; if ``request`` is provided, this @@ -560,42 +574,41 @@ def create_entity_type( sent along with the request as metadata. Returns: - ~.gcdc_entity_type.EntityType: - Entities are extracted from user input and represent - parameters that are meaningful to your application. For - example, a date range, a proper name such as a - geographic location or landmark, and so on. Entities - represent actionable data for your application. - - When you define an entity, you can also include synonyms - that all map to that entity. For example, "soft drink", - "soda", "pop", and so on. - - There are three types of entities: - - - **System** - entities that are defined by the - Dialogflow API for common data types such as date, - time, currency, and so on. A system entity is - represented by the ``EntityType`` type. - - - **Custom** - entities that are defined by you that - represent actionable data that is meaningful to your - application. For example, you could define a - ``pizza.sauce`` entity for red or white pizza sauce, - a ``pizza.cheese`` entity for the different types of - cheese on a pizza, a ``pizza.topping`` entity for - different toppings, and so on. A custom entity is - represented by the ``EntityType`` type. - - - **User** - entities that are built for an individual - user such as favorites, preferences, playlists, and - so on. A user entity is represented by the - [SessionEntityType][google.cloud.dialogflow.cx.v3beta1.SessionEntityType] - type. - - For more information about entity types, see the - `Dialogflow - documentation `__. + google.cloud.dialogflowcx_v3beta1.types.EntityType: + Entities are extracted from user input and represent parameters that are + meaningful to your application. For example, a date + range, a proper name such as a geographic location or + landmark, and so on. Entities represent actionable + data for your application. + + When you define an entity, you can also include + synonyms that all map to that entity. For example, + "soft drink", "soda", "pop", and so on. + + There are three types of entities: + + - **System** - entities that are defined by the + Dialogflow API for common data types such as date, + time, currency, and so on. A system entity is + represented by the EntityType type. + - **Custom** - entities that are defined by you that + represent actionable data that is meaningful to + your application. For example, you could define a + pizza.sauce entity for red or white pizza sauce, a + pizza.cheese entity for the different types of + cheese on a pizza, a pizza.topping entity for + different toppings, and so on. A custom entity is + represented by the EntityType type. + - **User** - entities that are built for an + individual user such as favorites, preferences, + playlists, and so on. A user entity is represented + by the + [SessionEntityType][google.cloud.dialogflow.cx.v3beta1.SessionEntityType] + type. + + For more information about entity types, see the + [Dialogflow + documentation](\ https://cloud.google.com/dialogflow/docs/entities-overview). """ # Create or coerce a protobuf request object. @@ -652,17 +665,18 @@ def update_entity_type( r"""Updates the specified entity type. Args: - request (:class:`~.gcdc_entity_type.UpdateEntityTypeRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.UpdateEntityTypeRequest): The request object. The request message for [EntityTypes.UpdateEntityType][google.cloud.dialogflow.cx.v3beta1.EntityTypes.UpdateEntityType]. - entity_type (:class:`~.gcdc_entity_type.EntityType`): + entity_type (google.cloud.dialogflowcx_v3beta1.types.EntityType): Required. The entity type to update. This corresponds to the ``entity_type`` 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): The mask to control which fields get updated. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -674,42 +688,41 @@ def update_entity_type( sent along with the request as metadata. Returns: - ~.gcdc_entity_type.EntityType: - Entities are extracted from user input and represent - parameters that are meaningful to your application. For - example, a date range, a proper name such as a - geographic location or landmark, and so on. Entities - represent actionable data for your application. - - When you define an entity, you can also include synonyms - that all map to that entity. For example, "soft drink", - "soda", "pop", and so on. - - There are three types of entities: - - - **System** - entities that are defined by the - Dialogflow API for common data types such as date, - time, currency, and so on. A system entity is - represented by the ``EntityType`` type. - - - **Custom** - entities that are defined by you that - represent actionable data that is meaningful to your - application. For example, you could define a - ``pizza.sauce`` entity for red or white pizza sauce, - a ``pizza.cheese`` entity for the different types of - cheese on a pizza, a ``pizza.topping`` entity for - different toppings, and so on. A custom entity is - represented by the ``EntityType`` type. - - - **User** - entities that are built for an individual - user such as favorites, preferences, playlists, and - so on. A user entity is represented by the - [SessionEntityType][google.cloud.dialogflow.cx.v3beta1.SessionEntityType] - type. - - For more information about entity types, see the - `Dialogflow - documentation `__. + google.cloud.dialogflowcx_v3beta1.types.EntityType: + Entities are extracted from user input and represent parameters that are + meaningful to your application. For example, a date + range, a proper name such as a geographic location or + landmark, and so on. Entities represent actionable + data for your application. + + When you define an entity, you can also include + synonyms that all map to that entity. For example, + "soft drink", "soda", "pop", and so on. + + There are three types of entities: + + - **System** - entities that are defined by the + Dialogflow API for common data types such as date, + time, currency, and so on. A system entity is + represented by the EntityType type. + - **Custom** - entities that are defined by you that + represent actionable data that is meaningful to + your application. For example, you could define a + pizza.sauce entity for red or white pizza sauce, a + pizza.cheese entity for the different types of + cheese on a pizza, a pizza.topping entity for + different toppings, and so on. A custom entity is + represented by the EntityType type. + - **User** - entities that are built for an + individual user such as favorites, preferences, + playlists, and so on. A user entity is represented + by the + [SessionEntityType][google.cloud.dialogflow.cx.v3beta1.SessionEntityType] + type. + + For more information about entity types, see the + [Dialogflow + documentation](\ https://cloud.google.com/dialogflow/docs/entities-overview). """ # Create or coerce a protobuf request object. @@ -767,12 +780,13 @@ def delete_entity_type( r"""Deletes the specified entity type. Args: - request (:class:`~.entity_type.DeleteEntityTypeRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.DeleteEntityTypeRequest): The request object. The request message for [EntityTypes.DeleteEntityType][google.cloud.dialogflow.cx.v3beta1.EntityTypes.DeleteEntityType]. - name (:class:`str`): + name (str): Required. The name of the entity type to delete. Format: ``projects//locations//agents//entityTypes/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. diff --git a/google/cloud/dialogflowcx_v3beta1/services/entity_types/pagers.py b/google/cloud/dialogflowcx_v3beta1/services/entity_types/pagers.py index 8b2cad47..266f2f48 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/entity_types/pagers.py +++ b/google/cloud/dialogflowcx_v3beta1/services/entity_types/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.dialogflowcx_v3beta1.types import entity_type @@ -24,7 +33,7 @@ class ListEntityTypesPager: """A pager for iterating through ``list_entity_types`` requests. This class thinly wraps an initial - :class:`~.entity_type.ListEntityTypesResponse` object, and + :class:`google.cloud.dialogflowcx_v3beta1.types.ListEntityTypesResponse` object, and provides an ``__iter__`` method to iterate through its ``entity_types`` field. @@ -33,7 +42,7 @@ class ListEntityTypesPager: through the ``entity_types`` field on the corresponding responses. - All the usual :class:`~.entity_type.ListEntityTypesResponse` + All the usual :class:`google.cloud.dialogflowcx_v3beta1.types.ListEntityTypesResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -51,9 +60,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.entity_type.ListEntityTypesRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.ListEntityTypesRequest): The initial request object. - response (:class:`~.entity_type.ListEntityTypesResponse`): + response (google.cloud.dialogflowcx_v3beta1.types.ListEntityTypesResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -86,7 +95,7 @@ class ListEntityTypesAsyncPager: """A pager for iterating through ``list_entity_types`` requests. This class thinly wraps an initial - :class:`~.entity_type.ListEntityTypesResponse` object, and + :class:`google.cloud.dialogflowcx_v3beta1.types.ListEntityTypesResponse` object, and provides an ``__aiter__`` method to iterate through its ``entity_types`` field. @@ -95,7 +104,7 @@ class ListEntityTypesAsyncPager: through the ``entity_types`` field on the corresponding responses. - All the usual :class:`~.entity_type.ListEntityTypesResponse` + All the usual :class:`google.cloud.dialogflowcx_v3beta1.types.ListEntityTypesResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -113,9 +122,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.entity_type.ListEntityTypesRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.ListEntityTypesRequest): The initial request object. - response (:class:`~.entity_type.ListEntityTypesResponse`): + response (google.cloud.dialogflowcx_v3beta1.types.ListEntityTypesResponse): 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/dialogflowcx_v3beta1/services/entity_types/transports/grpc.py b/google/cloud/dialogflowcx_v3beta1/services/entity_types/transports/grpc.py index 381f4131..cfb023ce 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/entity_types/transports/grpc.py +++ b/google/cloud/dialogflowcx_v3beta1/services/entity_types/transports/grpc.py @@ -60,6 +60,7 @@ def __init__( api_mtls_endpoint: str = None, client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, quota_project_id: Optional[str] = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: @@ -90,6 +91,10 @@ def __init__( ``api_mtls_endpoint`` is None. ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials for grpc channel. It is ignored if ``channel`` is provided. + client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]): + A callback to provide client certificate bytes and private key bytes, + both in PEM format. It is used to configure mutual TLS channel. It is + ignored if ``channel`` or ``ssl_channel_credentials`` is provided. quota_project_id (Optional[str]): An optional project to use for billing and quota. client_info (google.api_core.gapic_v1.client_info.ClientInfo): @@ -106,6 +111,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -115,11 +125,6 @@ def __init__( 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 @@ -163,12 +168,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ diff --git a/google/cloud/dialogflowcx_v3beta1/services/entity_types/transports/grpc_asyncio.py b/google/cloud/dialogflowcx_v3beta1/services/entity_types/transports/grpc_asyncio.py index 90201461..7f766a58 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/entity_types/transports/grpc_asyncio.py +++ b/google/cloud/dialogflowcx_v3beta1/services/entity_types/transports/grpc_asyncio.py @@ -104,6 +104,7 @@ def __init__( api_mtls_endpoint: str = None, client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, quota_project_id=None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: @@ -135,6 +136,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): @@ -151,6 +156,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -160,11 +170,6 @@ def __init__( 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 @@ -208,12 +213,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ diff --git a/google/cloud/dialogflowcx_v3beta1/services/environments/async_client.py b/google/cloud/dialogflowcx_v3beta1/services/environments/async_client.py index 38c4a0a3..145158e6 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/environments/async_client.py +++ b/google/cloud/dialogflowcx_v3beta1/services/environments/async_client.py @@ -82,7 +82,36 @@ class EnvironmentsAsyncClient: EnvironmentsClient.parse_common_location_path ) - from_service_account_file = EnvironmentsClient.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: + EnvironmentsAsyncClient: The constructed client. + """ + return EnvironmentsClient.from_service_account_info.__func__(EnvironmentsAsyncClient, 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: + EnvironmentsAsyncClient: The constructed client. + """ + return EnvironmentsClient.from_service_account_file.__func__(EnvironmentsAsyncClient, filename, *args, **kwargs) # type: ignore + from_service_account_json = from_service_account_file @property @@ -159,7 +188,7 @@ async def list_environments( [Agent][google.cloud.dialogflow.cx.v3beta1.Agent]. Args: - request (:class:`~.environment.ListEnvironmentsRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.ListEnvironmentsRequest`): The request object. The request message for [Environments.ListEnvironments][google.cloud.dialogflow.cx.v3beta1.Environments.ListEnvironments]. parent (:class:`str`): @@ -167,6 +196,7 @@ async def list_environments( [Agent][google.cloud.dialogflow.cx.v3beta1.Agent] to list all environments for. Format: ``projects//locations//agents/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -178,7 +208,7 @@ async def list_environments( sent along with the request as metadata. Returns: - ~.pagers.ListEnvironmentsAsyncPager: + google.cloud.dialogflowcx_v3beta1.services.environments.pagers.ListEnvironmentsAsyncPager: The response message for [Environments.ListEnvironments][google.cloud.dialogflow.cx.v3beta1.Environments.ListEnvironments]. @@ -243,7 +273,7 @@ async def get_environment( [Environment][google.cloud.dialogflow.cx.v3beta1.Environment]. Args: - request (:class:`~.environment.GetEnvironmentRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.GetEnvironmentRequest`): The request object. The request message for [Environments.GetEnvironment][google.cloud.dialogflow.cx.v3beta1.Environments.GetEnvironment]. name (:class:`str`): @@ -251,6 +281,7 @@ async def get_environment( [Environment][google.cloud.dialogflow.cx.v3beta1.Environment]. Format: ``projects//locations//agents//environments/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -262,7 +293,7 @@ async def get_environment( sent along with the request as metadata. Returns: - ~.environment.Environment: + google.cloud.dialogflowcx_v3beta1.types.Environment: Represents an environment for an agent. You can create multiple versions of your agent and publish them to @@ -333,7 +364,7 @@ async def create_environment( the specified [Agent][google.cloud.dialogflow.cx.v3beta1.Agent]. Args: - request (:class:`~.gcdc_environment.CreateEnvironmentRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.CreateEnvironmentRequest`): The request object. The request message for [Environments.CreateEnvironment][google.cloud.dialogflow.cx.v3beta1.Environments.CreateEnvironment]. parent (:class:`str`): @@ -343,10 +374,11 @@ async def create_environment( [Environment][google.cloud.dialogflow.cx.v3beta1.Environment] for. Format: ``projects//locations//agents/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - environment (:class:`~.gcdc_environment.Environment`): + environment (:class:`google.cloud.dialogflowcx_v3beta1.types.Environment`): Required. The environment to create. This corresponds to the ``environment`` field on the ``request`` instance; if ``request`` is provided, this @@ -359,21 +391,20 @@ async def create_environment( 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:``~.gcdc_environment.Environment``: Represents an - environment for an agent. You can create multiple - versions of your agent and publish them to separate - environments. When you edit an agent, you are editing - the draft agent. At any point, you can save the draft - agent as an agent version, which is an immutable - snapshot of your agent. When you save the draft agent, - it is published to the default environment. When you - create agent versions, you can publish them to custom - environments. You can create a variety of custom - environments for testing, development, production, etc. + The result type for the operation will be :class:`google.cloud.dialogflowcx_v3beta1.types.Environment` Represents an environment for an agent. You can create multiple versions + of your agent and publish them to separate + environments. When you edit an agent, you are editing + the draft agent. At any point, you can save the draft + agent as an agent version, which is an immutable + snapshot of your agent. When you save the draft + agent, it is published to the default environment. + When you create agent versions, you can publish them + to custom environments. You can create a variety of + custom environments for testing, development, + production, etc. """ # Create or coerce a protobuf request object. @@ -438,17 +469,18 @@ async def update_environment( [Environment][google.cloud.dialogflow.cx.v3beta1.Environment]. Args: - request (:class:`~.gcdc_environment.UpdateEnvironmentRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.UpdateEnvironmentRequest`): The request object. The request message for [Environments.UpdateEnvironment][google.cloud.dialogflow.cx.v3beta1.Environments.UpdateEnvironment]. - environment (:class:`~.gcdc_environment.Environment`): + environment (:class:`google.cloud.dialogflowcx_v3beta1.types.Environment`): Required. The environment to update. This corresponds to the ``environment`` 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`): Required. The mask to control which fields get updated. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -460,21 +492,20 @@ async def update_environment( 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:``~.gcdc_environment.Environment``: Represents an - environment for an agent. You can create multiple - versions of your agent and publish them to separate - environments. When you edit an agent, you are editing - the draft agent. At any point, you can save the draft - agent as an agent version, which is an immutable - snapshot of your agent. When you save the draft agent, - it is published to the default environment. When you - create agent versions, you can publish them to custom - environments. You can create a variety of custom - environments for testing, development, production, etc. + The result type for the operation will be :class:`google.cloud.dialogflowcx_v3beta1.types.Environment` Represents an environment for an agent. You can create multiple versions + of your agent and publish them to separate + environments. When you edit an agent, you are editing + the draft agent. At any point, you can save the draft + agent as an agent version, which is an immutable + snapshot of your agent. When you save the draft + agent, it is published to the default environment. + When you create agent versions, you can publish them + to custom environments. You can create a variety of + custom environments for testing, development, + production, etc. """ # Create or coerce a protobuf request object. @@ -540,7 +571,7 @@ async def delete_environment( [Environment][google.cloud.dialogflow.cx.v3beta1.Environment]. Args: - request (:class:`~.environment.DeleteEnvironmentRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.DeleteEnvironmentRequest`): The request object. The request message for [Environments.DeleteEnvironment][google.cloud.dialogflow.cx.v3beta1.Environments.DeleteEnvironment]. name (:class:`str`): @@ -548,6 +579,7 @@ async def delete_environment( [Environment][google.cloud.dialogflow.cx.v3beta1.Environment] to delete. Format: ``projects//locations//agents//environments/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -608,13 +640,14 @@ async def lookup_environment_history( [Environment][google.cloud.dialogflow.cx.v3beta1.Environment]. Args: - request (:class:`~.environment.LookupEnvironmentHistoryRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.LookupEnvironmentHistoryRequest`): The request object. The request message for [Environments.LookupEnvironmentHistory][google.cloud.dialogflow.cx.v3beta1.Environments.LookupEnvironmentHistory]. name (:class:`str`): Required. Resource name of the environment to look up the history for. Format: ``projects//locations//agents//environments/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -626,7 +659,7 @@ async def lookup_environment_history( sent along with the request as metadata. Returns: - ~.pagers.LookupEnvironmentHistoryAsyncPager: + google.cloud.dialogflowcx_v3beta1.services.environments.pagers.LookupEnvironmentHistoryAsyncPager: The response message for [Environments.LookupEnvironmentHistory][google.cloud.dialogflow.cx.v3beta1.Environments.LookupEnvironmentHistory]. diff --git a/google/cloud/dialogflowcx_v3beta1/services/environments/client.py b/google/cloud/dialogflowcx_v3beta1/services/environments/client.py index 03461fed..5ca9988e 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/environments/client.py +++ b/google/cloud/dialogflowcx_v3beta1/services/environments/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: + EnvironmentsClient: 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. + EnvironmentsClient: The constructed client. """ credentials = service_account.Credentials.from_service_account_file(filename) kwargs["credentials"] = credentials @@ -256,10 +272,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, ~.EnvironmentsTransport]): The + transport (Union[str, EnvironmentsTransport]): 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 @@ -295,21 +311,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: @@ -352,7 +364,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, ) @@ -370,14 +382,15 @@ def list_environments( [Agent][google.cloud.dialogflow.cx.v3beta1.Agent]. Args: - request (:class:`~.environment.ListEnvironmentsRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.ListEnvironmentsRequest): The request object. The request message for [Environments.ListEnvironments][google.cloud.dialogflow.cx.v3beta1.Environments.ListEnvironments]. - parent (:class:`str`): + parent (str): Required. The [Agent][google.cloud.dialogflow.cx.v3beta1.Agent] to list all environments for. Format: ``projects//locations//agents/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -389,7 +402,7 @@ def list_environments( sent along with the request as metadata. Returns: - ~.pagers.ListEnvironmentsPager: + google.cloud.dialogflowcx_v3beta1.services.environments.pagers.ListEnvironmentsPager: The response message for [Environments.ListEnvironments][google.cloud.dialogflow.cx.v3beta1.Environments.ListEnvironments]. @@ -455,14 +468,15 @@ def get_environment( [Environment][google.cloud.dialogflow.cx.v3beta1.Environment]. Args: - request (:class:`~.environment.GetEnvironmentRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.GetEnvironmentRequest): The request object. The request message for [Environments.GetEnvironment][google.cloud.dialogflow.cx.v3beta1.Environments.GetEnvironment]. - name (:class:`str`): + name (str): Required. The name of the [Environment][google.cloud.dialogflow.cx.v3beta1.Environment]. Format: ``projects//locations//agents//environments/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -474,7 +488,7 @@ def get_environment( sent along with the request as metadata. Returns: - ~.environment.Environment: + google.cloud.dialogflowcx_v3beta1.types.Environment: Represents an environment for an agent. You can create multiple versions of your agent and publish them to @@ -546,20 +560,21 @@ def create_environment( the specified [Agent][google.cloud.dialogflow.cx.v3beta1.Agent]. Args: - request (:class:`~.gcdc_environment.CreateEnvironmentRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.CreateEnvironmentRequest): The request object. The request message for [Environments.CreateEnvironment][google.cloud.dialogflow.cx.v3beta1.Environments.CreateEnvironment]. - parent (:class:`str`): + parent (str): Required. The [Agent][google.cloud.dialogflow.cx.v3beta1.Agent] to create an [Environment][google.cloud.dialogflow.cx.v3beta1.Environment] for. Format: ``projects//locations//agents/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - environment (:class:`~.gcdc_environment.Environment`): + environment (google.cloud.dialogflowcx_v3beta1.types.Environment): Required. The environment to create. This corresponds to the ``environment`` field on the ``request`` instance; if ``request`` is provided, this @@ -572,21 +587,20 @@ def create_environment( 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:``~.gcdc_environment.Environment``: Represents an - environment for an agent. You can create multiple - versions of your agent and publish them to separate - environments. When you edit an agent, you are editing - the draft agent. At any point, you can save the draft - agent as an agent version, which is an immutable - snapshot of your agent. When you save the draft agent, - it is published to the default environment. When you - create agent versions, you can publish them to custom - environments. You can create a variety of custom - environments for testing, development, production, etc. + The result type for the operation will be :class:`google.cloud.dialogflowcx_v3beta1.types.Environment` Represents an environment for an agent. You can create multiple versions + of your agent and publish them to separate + environments. When you edit an agent, you are editing + the draft agent. At any point, you can save the draft + agent as an agent version, which is an immutable + snapshot of your agent. When you save the draft + agent, it is published to the default environment. + When you create agent versions, you can publish them + to custom environments. You can create a variety of + custom environments for testing, development, + production, etc. """ # Create or coerce a protobuf request object. @@ -652,17 +666,18 @@ def update_environment( [Environment][google.cloud.dialogflow.cx.v3beta1.Environment]. Args: - request (:class:`~.gcdc_environment.UpdateEnvironmentRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.UpdateEnvironmentRequest): The request object. The request message for [Environments.UpdateEnvironment][google.cloud.dialogflow.cx.v3beta1.Environments.UpdateEnvironment]. - environment (:class:`~.gcdc_environment.Environment`): + environment (google.cloud.dialogflowcx_v3beta1.types.Environment): Required. The environment to update. This corresponds to the ``environment`` 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): Required. The mask to control which fields get updated. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -674,21 +689,20 @@ def update_environment( 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:``~.gcdc_environment.Environment``: Represents an - environment for an agent. You can create multiple - versions of your agent and publish them to separate - environments. When you edit an agent, you are editing - the draft agent. At any point, you can save the draft - agent as an agent version, which is an immutable - snapshot of your agent. When you save the draft agent, - it is published to the default environment. When you - create agent versions, you can publish them to custom - environments. You can create a variety of custom - environments for testing, development, production, etc. + The result type for the operation will be :class:`google.cloud.dialogflowcx_v3beta1.types.Environment` Represents an environment for an agent. You can create multiple versions + of your agent and publish them to separate + environments. When you edit an agent, you are editing + the draft agent. At any point, you can save the draft + agent as an agent version, which is an immutable + snapshot of your agent. When you save the draft + agent, it is published to the default environment. + When you create agent versions, you can publish them + to custom environments. You can create a variety of + custom environments for testing, development, + production, etc. """ # Create or coerce a protobuf request object. @@ -755,14 +769,15 @@ def delete_environment( [Environment][google.cloud.dialogflow.cx.v3beta1.Environment]. Args: - request (:class:`~.environment.DeleteEnvironmentRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.DeleteEnvironmentRequest): The request object. The request message for [Environments.DeleteEnvironment][google.cloud.dialogflow.cx.v3beta1.Environments.DeleteEnvironment]. - name (:class:`str`): + name (str): Required. The name of the [Environment][google.cloud.dialogflow.cx.v3beta1.Environment] to delete. Format: ``projects//locations//agents//environments/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -824,13 +839,14 @@ def lookup_environment_history( [Environment][google.cloud.dialogflow.cx.v3beta1.Environment]. Args: - request (:class:`~.environment.LookupEnvironmentHistoryRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.LookupEnvironmentHistoryRequest): The request object. The request message for [Environments.LookupEnvironmentHistory][google.cloud.dialogflow.cx.v3beta1.Environments.LookupEnvironmentHistory]. - name (:class:`str`): + name (str): Required. Resource name of the environment to look up the history for. Format: ``projects//locations//agents//environments/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -842,7 +858,7 @@ def lookup_environment_history( sent along with the request as metadata. Returns: - ~.pagers.LookupEnvironmentHistoryPager: + google.cloud.dialogflowcx_v3beta1.services.environments.pagers.LookupEnvironmentHistoryPager: The response message for [Environments.LookupEnvironmentHistory][google.cloud.dialogflow.cx.v3beta1.Environments.LookupEnvironmentHistory]. diff --git a/google/cloud/dialogflowcx_v3beta1/services/environments/pagers.py b/google/cloud/dialogflowcx_v3beta1/services/environments/pagers.py index 644126cd..a2f63ff2 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/environments/pagers.py +++ b/google/cloud/dialogflowcx_v3beta1/services/environments/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.dialogflowcx_v3beta1.types import environment @@ -24,7 +33,7 @@ class ListEnvironmentsPager: """A pager for iterating through ``list_environments`` requests. This class thinly wraps an initial - :class:`~.environment.ListEnvironmentsResponse` object, and + :class:`google.cloud.dialogflowcx_v3beta1.types.ListEnvironmentsResponse` object, and provides an ``__iter__`` method to iterate through its ``environments`` field. @@ -33,7 +42,7 @@ class ListEnvironmentsPager: through the ``environments`` field on the corresponding responses. - All the usual :class:`~.environment.ListEnvironmentsResponse` + All the usual :class:`google.cloud.dialogflowcx_v3beta1.types.ListEnvironmentsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -51,9 +60,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.environment.ListEnvironmentsRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.ListEnvironmentsRequest): The initial request object. - response (:class:`~.environment.ListEnvironmentsResponse`): + response (google.cloud.dialogflowcx_v3beta1.types.ListEnvironmentsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -86,7 +95,7 @@ class ListEnvironmentsAsyncPager: """A pager for iterating through ``list_environments`` requests. This class thinly wraps an initial - :class:`~.environment.ListEnvironmentsResponse` object, and + :class:`google.cloud.dialogflowcx_v3beta1.types.ListEnvironmentsResponse` object, and provides an ``__aiter__`` method to iterate through its ``environments`` field. @@ -95,7 +104,7 @@ class ListEnvironmentsAsyncPager: through the ``environments`` field on the corresponding responses. - All the usual :class:`~.environment.ListEnvironmentsResponse` + All the usual :class:`google.cloud.dialogflowcx_v3beta1.types.ListEnvironmentsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -113,9 +122,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.environment.ListEnvironmentsRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.ListEnvironmentsRequest): The initial request object. - response (:class:`~.environment.ListEnvironmentsResponse`): + response (google.cloud.dialogflowcx_v3beta1.types.ListEnvironmentsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -152,7 +161,7 @@ class LookupEnvironmentHistoryPager: """A pager for iterating through ``lookup_environment_history`` requests. This class thinly wraps an initial - :class:`~.environment.LookupEnvironmentHistoryResponse` object, and + :class:`google.cloud.dialogflowcx_v3beta1.types.LookupEnvironmentHistoryResponse` object, and provides an ``__iter__`` method to iterate through its ``environments`` field. @@ -161,7 +170,7 @@ class LookupEnvironmentHistoryPager: through the ``environments`` field on the corresponding responses. - All the usual :class:`~.environment.LookupEnvironmentHistoryResponse` + All the usual :class:`google.cloud.dialogflowcx_v3beta1.types.LookupEnvironmentHistoryResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -179,9 +188,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.environment.LookupEnvironmentHistoryRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.LookupEnvironmentHistoryRequest): The initial request object. - response (:class:`~.environment.LookupEnvironmentHistoryResponse`): + response (google.cloud.dialogflowcx_v3beta1.types.LookupEnvironmentHistoryResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -214,7 +223,7 @@ class LookupEnvironmentHistoryAsyncPager: """A pager for iterating through ``lookup_environment_history`` requests. This class thinly wraps an initial - :class:`~.environment.LookupEnvironmentHistoryResponse` object, and + :class:`google.cloud.dialogflowcx_v3beta1.types.LookupEnvironmentHistoryResponse` object, and provides an ``__aiter__`` method to iterate through its ``environments`` field. @@ -223,7 +232,7 @@ class LookupEnvironmentHistoryAsyncPager: through the ``environments`` field on the corresponding responses. - All the usual :class:`~.environment.LookupEnvironmentHistoryResponse` + All the usual :class:`google.cloud.dialogflowcx_v3beta1.types.LookupEnvironmentHistoryResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -241,9 +250,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.environment.LookupEnvironmentHistoryRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.LookupEnvironmentHistoryRequest): The initial request object. - response (:class:`~.environment.LookupEnvironmentHistoryResponse`): + response (google.cloud.dialogflowcx_v3beta1.types.LookupEnvironmentHistoryResponse): 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/dialogflowcx_v3beta1/services/environments/transports/grpc.py b/google/cloud/dialogflowcx_v3beta1/services/environments/transports/grpc.py index 9649e5c4..ab31da64 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/environments/transports/grpc.py +++ b/google/cloud/dialogflowcx_v3beta1/services/environments/transports/grpc.py @@ -62,6 +62,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: @@ -92,6 +93,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): @@ -108,6 +113,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -117,11 +127,6 @@ def __init__( 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 @@ -165,12 +170,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ diff --git a/google/cloud/dialogflowcx_v3beta1/services/environments/transports/grpc_asyncio.py b/google/cloud/dialogflowcx_v3beta1/services/environments/transports/grpc_asyncio.py index f6c47470..44954784 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/environments/transports/grpc_asyncio.py +++ b/google/cloud/dialogflowcx_v3beta1/services/environments/transports/grpc_asyncio.py @@ -106,6 +106,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: @@ -137,6 +138,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): @@ -153,6 +158,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -162,11 +172,6 @@ def __init__( 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 @@ -210,12 +215,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ diff --git a/google/cloud/dialogflowcx_v3beta1/services/experiments/async_client.py b/google/cloud/dialogflowcx_v3beta1/services/experiments/async_client.py index 6911f807..c92fd8cd 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/experiments/async_client.py +++ b/google/cloud/dialogflowcx_v3beta1/services/experiments/async_client.py @@ -80,7 +80,36 @@ class ExperimentsAsyncClient: ExperimentsClient.parse_common_location_path ) - from_service_account_file = ExperimentsClient.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: + ExperimentsAsyncClient: The constructed client. + """ + return ExperimentsClient.from_service_account_info.__func__(ExperimentsAsyncClient, 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: + ExperimentsAsyncClient: The constructed client. + """ + return ExperimentsClient.from_service_account_file.__func__(ExperimentsAsyncClient, filename, *args, **kwargs) # type: ignore + from_service_account_json = from_service_account_file @property @@ -157,7 +186,7 @@ async def list_experiments( [Environment][google.cloud.dialogflow.cx.v3beta1.Environment]. Args: - request (:class:`~.experiment.ListExperimentsRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.ListExperimentsRequest`): The request object. The request message for [Experiments.ListExperiments][google.cloud.dialogflow.cx.v3beta1.Experiments.ListExperiments]. parent (:class:`str`): @@ -165,6 +194,7 @@ async def list_experiments( [Environment][google.cloud.dialogflow.cx.v3beta1.Environment] to list all environments for. Format: ``projects//locations//agents//environments/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -176,7 +206,7 @@ async def list_experiments( sent along with the request as metadata. Returns: - ~.pagers.ListExperimentsAsyncPager: + google.cloud.dialogflowcx_v3beta1.services.experiments.pagers.ListExperimentsAsyncPager: The response message for [Experiments.ListExperiments][google.cloud.dialogflow.cx.v3beta1.Experiments.ListExperiments]. @@ -241,7 +271,7 @@ async def get_experiment( [Experiment][google.cloud.dialogflow.cx.v3beta1.Experiment]. Args: - request (:class:`~.experiment.GetExperimentRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.GetExperimentRequest`): The request object. The request message for [Experiments.GetExperiment][google.cloud.dialogflow.cx.v3beta1.Experiments.GetExperiment]. name (:class:`str`): @@ -249,6 +279,7 @@ async def get_experiment( [Environment][google.cloud.dialogflow.cx.v3beta1.Environment]. Format: ``projects//locations//agents//environments//experiments/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -260,9 +291,9 @@ async def get_experiment( sent along with the request as metadata. Returns: - ~.experiment.Experiment: + google.cloud.dialogflowcx_v3beta1.types.Experiment: Represents an experiment in an - environment. Next ID: 13 + environment. """ # Create or coerce a protobuf request object. @@ -319,7 +350,7 @@ async def create_experiment( [Environment][google.cloud.dialogflow.cx.v3beta1.Environment]. Args: - request (:class:`~.gcdc_experiment.CreateExperimentRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.CreateExperimentRequest`): The request object. The request message for [Experiments.CreateExperiment][google.cloud.dialogflow.cx.v3beta1.Experiments.CreateExperiment]. parent (:class:`str`): @@ -329,10 +360,11 @@ async def create_experiment( [Environment][google.cloud.dialogflow.cx.v3beta1.Environment] for. Format: ``projects//locations//agents//environments/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - experiment (:class:`~.gcdc_experiment.Experiment`): + experiment (:class:`google.cloud.dialogflowcx_v3beta1.types.Experiment`): Required. The experiment to create. This corresponds to the ``experiment`` field on the ``request`` instance; if ``request`` is provided, this @@ -345,9 +377,9 @@ async def create_experiment( sent along with the request as metadata. Returns: - ~.gcdc_experiment.Experiment: + google.cloud.dialogflowcx_v3beta1.types.Experiment: Represents an experiment in an - environment. Next ID: 13 + environment. """ # Create or coerce a protobuf request object. @@ -404,17 +436,18 @@ async def update_experiment( [Experiment][google.cloud.dialogflow.cx.v3beta1.Experiment]. Args: - request (:class:`~.gcdc_experiment.UpdateExperimentRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.UpdateExperimentRequest`): The request object. The request message for [Experiments.UpdateExperiment][google.cloud.dialogflow.cx.v3beta1.Experiments.UpdateExperiment]. - experiment (:class:`~.gcdc_experiment.Experiment`): + experiment (:class:`google.cloud.dialogflowcx_v3beta1.types.Experiment`): Required. The experiment to update. This corresponds to the ``experiment`` 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`): Required. The mask to control which fields get updated. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -426,9 +459,9 @@ async def update_experiment( sent along with the request as metadata. Returns: - ~.gcdc_experiment.Experiment: + google.cloud.dialogflowcx_v3beta1.types.Experiment: Represents an experiment in an - environment. Next ID: 13 + environment. """ # Create or coerce a protobuf request object. @@ -486,7 +519,7 @@ async def delete_experiment( [Experiment][google.cloud.dialogflow.cx.v3beta1.Experiment]. Args: - request (:class:`~.experiment.DeleteExperimentRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.DeleteExperimentRequest`): The request object. The request message for [Experiments.DeleteExperiment][google.cloud.dialogflow.cx.v3beta1.Experiments.DeleteExperiment]. name (:class:`str`): @@ -494,6 +527,7 @@ async def delete_experiment( [Environment][google.cloud.dialogflow.cx.v3beta1.Environment] to delete. Format: ``projects//locations//agents//environments//experiments/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -556,13 +590,14 @@ async def start_experiment( RUNNING. Args: - request (:class:`~.experiment.StartExperimentRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.StartExperimentRequest`): The request object. The request message for [Experiments.StartExperiment][google.cloud.dialogflow.cx.v3beta1.Experiments.StartExperiment]. name (:class:`str`): Required. Resource name of the experiment to start. Format: ``projects//locations//agents//environments//experiments/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -574,9 +609,9 @@ async def start_experiment( sent along with the request as metadata. Returns: - ~.experiment.Experiment: + google.cloud.dialogflowcx_v3beta1.types.Experiment: Represents an experiment in an - environment. Next ID: 13 + environment. """ # Create or coerce a protobuf request object. @@ -632,13 +667,14 @@ async def stop_experiment( DONE. Args: - request (:class:`~.experiment.StopExperimentRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.StopExperimentRequest`): The request object. The request message for [Experiments.StopExperiment][google.cloud.dialogflow.cx.v3beta1.Experiments.StopExperiment]. name (:class:`str`): Required. Resource name of the experiment to stop. Format: ``projects//locations//agents//environments//experiments/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -650,9 +686,9 @@ async def stop_experiment( sent along with the request as metadata. Returns: - ~.experiment.Experiment: + google.cloud.dialogflowcx_v3beta1.types.Experiment: Represents an experiment in an - environment. Next ID: 13 + environment. """ # Create or coerce a protobuf request object. diff --git a/google/cloud/dialogflowcx_v3beta1/services/experiments/client.py b/google/cloud/dialogflowcx_v3beta1/services/experiments/client.py index c332dc33..84570049 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/experiments/client.py +++ b/google/cloud/dialogflowcx_v3beta1/services/experiments/client.py @@ -114,6 +114,22 @@ def _get_default_mtls_endpoint(api_endpoint): DEFAULT_ENDPOINT ) + @classmethod + def from_service_account_info(cls, info: dict, *args, **kwargs): + """Creates an instance of this client using the provided credentials info. + + Args: + info (dict): The service account private key info. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + ExperimentsClient: The constructed client. + """ + credentials = service_account.Credentials.from_service_account_info(info) + kwargs["credentials"] = credentials + return cls(*args, **kwargs) + @classmethod def from_service_account_file(cls, filename: str, *args, **kwargs): """Creates an instance of this client using the provided credentials @@ -126,7 +142,7 @@ def from_service_account_file(cls, filename: str, *args, **kwargs): kwargs: Additional arguments to pass to the constructor. Returns: - {@api.name}: The constructed client. + ExperimentsClient: The constructed client. """ credentials = service_account.Credentials.from_service_account_file(filename) kwargs["credentials"] = credentials @@ -258,10 +274,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, ~.ExperimentsTransport]): The + transport (Union[str, ExperimentsTransport]): 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 @@ -297,21 +313,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: @@ -354,7 +366,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, ) @@ -372,14 +384,15 @@ def list_experiments( [Environment][google.cloud.dialogflow.cx.v3beta1.Environment]. Args: - request (:class:`~.experiment.ListExperimentsRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.ListExperimentsRequest): The request object. The request message for [Experiments.ListExperiments][google.cloud.dialogflow.cx.v3beta1.Experiments.ListExperiments]. - parent (:class:`str`): + parent (str): Required. The [Environment][google.cloud.dialogflow.cx.v3beta1.Environment] to list all environments for. Format: ``projects//locations//agents//environments/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -391,7 +404,7 @@ def list_experiments( sent along with the request as metadata. Returns: - ~.pagers.ListExperimentsPager: + google.cloud.dialogflowcx_v3beta1.services.experiments.pagers.ListExperimentsPager: The response message for [Experiments.ListExperiments][google.cloud.dialogflow.cx.v3beta1.Experiments.ListExperiments]. @@ -457,14 +470,15 @@ def get_experiment( [Experiment][google.cloud.dialogflow.cx.v3beta1.Experiment]. Args: - request (:class:`~.experiment.GetExperimentRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.GetExperimentRequest): The request object. The request message for [Experiments.GetExperiment][google.cloud.dialogflow.cx.v3beta1.Experiments.GetExperiment]. - name (:class:`str`): + name (str): Required. The name of the [Environment][google.cloud.dialogflow.cx.v3beta1.Environment]. Format: ``projects//locations//agents//environments//experiments/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -476,9 +490,9 @@ def get_experiment( sent along with the request as metadata. Returns: - ~.experiment.Experiment: + google.cloud.dialogflowcx_v3beta1.types.Experiment: Represents an experiment in an - environment. Next ID: 13 + environment. """ # Create or coerce a protobuf request object. @@ -536,20 +550,21 @@ def create_experiment( [Environment][google.cloud.dialogflow.cx.v3beta1.Environment]. Args: - request (:class:`~.gcdc_experiment.CreateExperimentRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.CreateExperimentRequest): The request object. The request message for [Experiments.CreateExperiment][google.cloud.dialogflow.cx.v3beta1.Experiments.CreateExperiment]. - parent (:class:`str`): + parent (str): Required. The [Agent][google.cloud.dialogflow.cx.v3beta1.Agent] to create an [Environment][google.cloud.dialogflow.cx.v3beta1.Environment] for. Format: ``projects//locations//agents//environments/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - experiment (:class:`~.gcdc_experiment.Experiment`): + experiment (google.cloud.dialogflowcx_v3beta1.types.Experiment): Required. The experiment to create. This corresponds to the ``experiment`` field on the ``request`` instance; if ``request`` is provided, this @@ -562,9 +577,9 @@ def create_experiment( sent along with the request as metadata. Returns: - ~.gcdc_experiment.Experiment: + google.cloud.dialogflowcx_v3beta1.types.Experiment: Represents an experiment in an - environment. Next ID: 13 + environment. """ # Create or coerce a protobuf request object. @@ -622,17 +637,18 @@ def update_experiment( [Experiment][google.cloud.dialogflow.cx.v3beta1.Experiment]. Args: - request (:class:`~.gcdc_experiment.UpdateExperimentRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.UpdateExperimentRequest): The request object. The request message for [Experiments.UpdateExperiment][google.cloud.dialogflow.cx.v3beta1.Experiments.UpdateExperiment]. - experiment (:class:`~.gcdc_experiment.Experiment`): + experiment (google.cloud.dialogflowcx_v3beta1.types.Experiment): Required. The experiment to update. This corresponds to the ``experiment`` 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): Required. The mask to control which fields get updated. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -644,9 +660,9 @@ def update_experiment( sent along with the request as metadata. Returns: - ~.gcdc_experiment.Experiment: + google.cloud.dialogflowcx_v3beta1.types.Experiment: Represents an experiment in an - environment. Next ID: 13 + environment. """ # Create or coerce a protobuf request object. @@ -705,14 +721,15 @@ def delete_experiment( [Experiment][google.cloud.dialogflow.cx.v3beta1.Experiment]. Args: - request (:class:`~.experiment.DeleteExperimentRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.DeleteExperimentRequest): The request object. The request message for [Experiments.DeleteExperiment][google.cloud.dialogflow.cx.v3beta1.Experiments.DeleteExperiment]. - name (:class:`str`): + name (str): Required. The name of the [Environment][google.cloud.dialogflow.cx.v3beta1.Environment] to delete. Format: ``projects//locations//agents//environments//experiments/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -776,13 +793,14 @@ def start_experiment( RUNNING. Args: - request (:class:`~.experiment.StartExperimentRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.StartExperimentRequest): The request object. The request message for [Experiments.StartExperiment][google.cloud.dialogflow.cx.v3beta1.Experiments.StartExperiment]. - name (:class:`str`): + name (str): Required. Resource name of the experiment to start. Format: ``projects//locations//agents//environments//experiments/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -794,9 +812,9 @@ def start_experiment( sent along with the request as metadata. Returns: - ~.experiment.Experiment: + google.cloud.dialogflowcx_v3beta1.types.Experiment: Represents an experiment in an - environment. Next ID: 13 + environment. """ # Create or coerce a protobuf request object. @@ -853,13 +871,14 @@ def stop_experiment( DONE. Args: - request (:class:`~.experiment.StopExperimentRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.StopExperimentRequest): The request object. The request message for [Experiments.StopExperiment][google.cloud.dialogflow.cx.v3beta1.Experiments.StopExperiment]. - name (:class:`str`): + name (str): Required. Resource name of the experiment to stop. Format: ``projects//locations//agents//environments//experiments/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -871,9 +890,9 @@ def stop_experiment( sent along with the request as metadata. Returns: - ~.experiment.Experiment: + google.cloud.dialogflowcx_v3beta1.types.Experiment: Represents an experiment in an - environment. Next ID: 13 + environment. """ # Create or coerce a protobuf request object. diff --git a/google/cloud/dialogflowcx_v3beta1/services/experiments/pagers.py b/google/cloud/dialogflowcx_v3beta1/services/experiments/pagers.py index d01901a5..99ae14ea 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/experiments/pagers.py +++ b/google/cloud/dialogflowcx_v3beta1/services/experiments/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.dialogflowcx_v3beta1.types import experiment @@ -24,7 +33,7 @@ class ListExperimentsPager: """A pager for iterating through ``list_experiments`` requests. This class thinly wraps an initial - :class:`~.experiment.ListExperimentsResponse` object, and + :class:`google.cloud.dialogflowcx_v3beta1.types.ListExperimentsResponse` object, and provides an ``__iter__`` method to iterate through its ``experiments`` field. @@ -33,7 +42,7 @@ class ListExperimentsPager: through the ``experiments`` field on the corresponding responses. - All the usual :class:`~.experiment.ListExperimentsResponse` + All the usual :class:`google.cloud.dialogflowcx_v3beta1.types.ListExperimentsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -51,9 +60,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.experiment.ListExperimentsRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.ListExperimentsRequest): The initial request object. - response (:class:`~.experiment.ListExperimentsResponse`): + response (google.cloud.dialogflowcx_v3beta1.types.ListExperimentsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -86,7 +95,7 @@ class ListExperimentsAsyncPager: """A pager for iterating through ``list_experiments`` requests. This class thinly wraps an initial - :class:`~.experiment.ListExperimentsResponse` object, and + :class:`google.cloud.dialogflowcx_v3beta1.types.ListExperimentsResponse` object, and provides an ``__aiter__`` method to iterate through its ``experiments`` field. @@ -95,7 +104,7 @@ class ListExperimentsAsyncPager: through the ``experiments`` field on the corresponding responses. - All the usual :class:`~.experiment.ListExperimentsResponse` + All the usual :class:`google.cloud.dialogflowcx_v3beta1.types.ListExperimentsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -113,9 +122,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.experiment.ListExperimentsRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.ListExperimentsRequest): The initial request object. - response (:class:`~.experiment.ListExperimentsResponse`): + response (google.cloud.dialogflowcx_v3beta1.types.ListExperimentsResponse): 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/dialogflowcx_v3beta1/services/experiments/transports/grpc.py b/google/cloud/dialogflowcx_v3beta1/services/experiments/transports/grpc.py index ba506a12..0a6cc4d2 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/experiments/transports/grpc.py +++ b/google/cloud/dialogflowcx_v3beta1/services/experiments/transports/grpc.py @@ -60,6 +60,7 @@ def __init__( api_mtls_endpoint: str = None, client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, quota_project_id: Optional[str] = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: @@ -90,6 +91,10 @@ def __init__( ``api_mtls_endpoint`` is None. ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials for grpc channel. It is ignored if ``channel`` is provided. + client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]): + A callback to provide client certificate bytes and private key bytes, + both in PEM format. It is used to configure mutual TLS channel. It is + ignored if ``channel`` or ``ssl_channel_credentials`` is provided. quota_project_id (Optional[str]): An optional project to use for billing and quota. client_info (google.api_core.gapic_v1.client_info.ClientInfo): @@ -106,6 +111,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -115,11 +125,6 @@ def __init__( 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 @@ -163,12 +168,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ diff --git a/google/cloud/dialogflowcx_v3beta1/services/experiments/transports/grpc_asyncio.py b/google/cloud/dialogflowcx_v3beta1/services/experiments/transports/grpc_asyncio.py index 3950a0d0..afe0a6e2 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/experiments/transports/grpc_asyncio.py +++ b/google/cloud/dialogflowcx_v3beta1/services/experiments/transports/grpc_asyncio.py @@ -104,6 +104,7 @@ def __init__( api_mtls_endpoint: str = None, client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, quota_project_id=None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: @@ -135,6 +136,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): @@ -151,6 +156,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -160,11 +170,6 @@ def __init__( 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 @@ -208,12 +213,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ diff --git a/google/cloud/dialogflowcx_v3beta1/services/flows/async_client.py b/google/cloud/dialogflowcx_v3beta1/services/flows/async_client.py index 06951967..4c733bfa 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/flows/async_client.py +++ b/google/cloud/dialogflowcx_v3beta1/services/flows/async_client.py @@ -34,9 +34,11 @@ from google.cloud.dialogflowcx_v3beta1.types import flow from google.cloud.dialogflowcx_v3beta1.types import flow as gcdc_flow from google.cloud.dialogflowcx_v3beta1.types import page +from google.cloud.dialogflowcx_v3beta1.types import validation_message from google.protobuf import empty_pb2 as empty # type: ignore from google.protobuf import field_mask_pb2 as field_mask # type: ignore from google.protobuf import struct_pb2 as struct # type: ignore +from google.protobuf import timestamp_pb2 as timestamp # type: ignore from .transports.base import FlowsTransport, DEFAULT_CLIENT_INFO from .transports.grpc_asyncio import FlowsGrpcAsyncIOTransport @@ -55,6 +57,10 @@ class FlowsAsyncClient: flow_path = staticmethod(FlowsClient.flow_path) parse_flow_path = staticmethod(FlowsClient.parse_flow_path) + flow_validation_result_path = staticmethod(FlowsClient.flow_validation_result_path) + parse_flow_validation_result_path = staticmethod( + FlowsClient.parse_flow_validation_result_path + ) intent_path = staticmethod(FlowsClient.intent_path) parse_intent_path = staticmethod(FlowsClient.parse_intent_path) page_path = staticmethod(FlowsClient.page_path) @@ -81,7 +87,36 @@ class FlowsAsyncClient: common_location_path = staticmethod(FlowsClient.common_location_path) parse_common_location_path = staticmethod(FlowsClient.parse_common_location_path) - from_service_account_file = FlowsClient.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: + FlowsAsyncClient: The constructed client. + """ + return FlowsClient.from_service_account_info.__func__(FlowsAsyncClient, 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: + FlowsAsyncClient: The constructed client. + """ + return FlowsClient.from_service_account_file.__func__(FlowsAsyncClient, filename, *args, **kwargs) # type: ignore + from_service_account_json = from_service_account_file @property @@ -158,16 +193,17 @@ async def create_flow( r"""Creates a flow in the specified agent. Args: - request (:class:`~.gcdc_flow.CreateFlowRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.CreateFlowRequest`): The request object. The request message for [Flows.CreateFlow][google.cloud.dialogflow.cx.v3beta1.Flows.CreateFlow]. parent (:class:`str`): Required. The agent to create a flow for. Format: ``projects//locations//agents/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - flow (:class:`~.gcdc_flow.Flow`): + flow (:class:`google.cloud.dialogflowcx_v3beta1.types.Flow`): Required. The flow to create. This corresponds to the ``flow`` field on the ``request`` instance; if ``request`` is provided, this @@ -180,7 +216,7 @@ async def create_flow( sent along with the request as metadata. Returns: - ~.gcdc_flow.Flow: + google.cloud.dialogflowcx_v3beta1.types.Flow: Flows represents the conversation flows when you build your chatbot agent. A flow consists of many pages connected @@ -258,12 +294,13 @@ async def delete_flow( r"""Deletes a specified flow. Args: - request (:class:`~.flow.DeleteFlowRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.DeleteFlowRequest`): The request object. The request message for [Flows.DeleteFlow][google.cloud.dialogflow.cx.v3beta1.Flows.DeleteFlow]. name (:class:`str`): Required. The name of the flow to delete. Format: ``projects//locations//agents//flows/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -323,12 +360,13 @@ async def list_flows( r"""Returns the list of all flows in the specified agent. Args: - request (:class:`~.flow.ListFlowsRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.ListFlowsRequest`): The request object. The request message for [Flows.ListFlows][google.cloud.dialogflow.cx.v3beta1.Flows.ListFlows]. parent (:class:`str`): Required. The agent containing the flows. Format: ``projects//locations//agents/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -340,7 +378,7 @@ async def list_flows( sent along with the request as metadata. Returns: - ~.pagers.ListFlowsAsyncPager: + google.cloud.dialogflowcx_v3beta1.services.flows.pagers.ListFlowsAsyncPager: The response message for [Flows.ListFlows][google.cloud.dialogflow.cx.v3beta1.Flows.ListFlows]. @@ -404,12 +442,13 @@ async def get_flow( r"""Retrieves the specified flow. Args: - request (:class:`~.flow.GetFlowRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.GetFlowRequest`): The request object. The response message for [Flows.GetFlow][google.cloud.dialogflow.cx.v3beta1.Flows.GetFlow]. name (:class:`str`): Required. The name of the flow to get. Format: ``projects//locations//agents//flows/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -421,7 +460,7 @@ async def get_flow( sent along with the request as metadata. Returns: - ~.flow.Flow: + google.cloud.dialogflowcx_v3beta1.types.Flow: Flows represents the conversation flows when you build your chatbot agent. A flow consists of many pages connected @@ -498,18 +537,19 @@ async def update_flow( r"""Updates the specified flow. Args: - request (:class:`~.gcdc_flow.UpdateFlowRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.UpdateFlowRequest`): The request object. The request message for [Flows.UpdateFlow][google.cloud.dialogflow.cx.v3beta1.Flows.UpdateFlow]. - flow (:class:`~.gcdc_flow.Flow`): + flow (:class:`google.cloud.dialogflowcx_v3beta1.types.Flow`): Required. The flow to update. This corresponds to the ``flow`` 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`): Required. The mask to control which fields get updated. If ``update_mask`` is not specified, an error will be returned. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -521,7 +561,7 @@ async def update_flow( sent along with the request as metadata. Returns: - ~.gcdc_flow.Flow: + google.cloud.dialogflowcx_v3beta1.types.Flow: Flows represents the conversation flows when you build your chatbot agent. A flow consists of many pages connected @@ -602,12 +642,13 @@ async def train_flow( 'draft' environment is trained. Args: - request (:class:`~.flow.TrainFlowRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.TrainFlowRequest`): The request object. The request message for [Flows.TrainFlow][google.cloud.dialogflow.cx.v3beta1.Flows.TrainFlow]. name (:class:`str`): Required. The flow to train. Format: ``projects//locations//agents//flows/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -619,24 +660,22 @@ async def train_flow( 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:``~.empty.Empty``: A generic empty message that - you can re-use to avoid defining duplicated empty - messages in your APIs. A typical example is to use it as - the request or the response type of an API method. For - instance: + The result type for the operation will be :class:`google.protobuf.empty_pb2.Empty` A generic empty message that you can re-use to avoid defining duplicated + empty messages in your APIs. A typical example is to + use it as the request or the response type of an API + method. For instance: - :: + service Foo { + rpc Bar(google.protobuf.Empty) returns + (google.protobuf.Empty); - service Foo { - rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty); - } + } - The JSON representation for ``Empty`` is empty JSON - object ``{}``. + The JSON representation for Empty is empty JSON + object {}. """ # Create or coerce a protobuf request object. @@ -685,6 +724,134 @@ async def train_flow( # Done; return the response. return response + async def validate_flow( + self, + request: flow.ValidateFlowRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> flow.FlowValidationResult: + r"""Validates the specified flow and creates or updates + validation results. Please call this API after the + training is completed to get the complete validation + results. + + Args: + request (:class:`google.cloud.dialogflowcx_v3beta1.types.ValidateFlowRequest`): + The request object. The request message for + [Flows.ValidateFlow][google.cloud.dialogflow.cx.v3beta1.Flows.ValidateFlow]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.dialogflowcx_v3beta1.types.FlowValidationResult: + The response message for + [Flows.GetFlowValidationResult][google.cloud.dialogflow.cx.v3beta1.Flows.GetFlowValidationResult]. + + """ + # Create or coerce a protobuf request object. + + request = flow.ValidateFlowRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.validate_flow, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = await rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + + async def get_flow_validation_result( + self, + request: flow.GetFlowValidationResultRequest = None, + *, + name: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> flow.FlowValidationResult: + r"""Gets the latest flow validation result. Flow + validation is performed when ValidateFlow is called. + + Args: + request (:class:`google.cloud.dialogflowcx_v3beta1.types.GetFlowValidationResultRequest`): + The request object. The request message for + [Flows.GetFlowValidationResult][google.cloud.dialogflow.cx.v3beta1.Flows.GetFlowValidationResult]. + name (:class:`str`): + Required. The flow name. Format: + ``projects//locations//agents//flows//validationResult``. + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.dialogflowcx_v3beta1.types.FlowValidationResult: + The response message for + [Flows.GetFlowValidationResult][google.cloud.dialogflow.cx.v3beta1.Flows.GetFlowValidationResult]. + + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = flow.GetFlowValidationResultRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.get_flow_validation_result, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = await rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + try: DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/google/cloud/dialogflowcx_v3beta1/services/flows/client.py b/google/cloud/dialogflowcx_v3beta1/services/flows/client.py index 0cd50c1a..cc0db606 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/flows/client.py +++ b/google/cloud/dialogflowcx_v3beta1/services/flows/client.py @@ -38,9 +38,11 @@ from google.cloud.dialogflowcx_v3beta1.types import flow from google.cloud.dialogflowcx_v3beta1.types import flow as gcdc_flow from google.cloud.dialogflowcx_v3beta1.types import page +from google.cloud.dialogflowcx_v3beta1.types import validation_message from google.protobuf import empty_pb2 as empty # type: ignore from google.protobuf import field_mask_pb2 as field_mask # type: ignore from google.protobuf import struct_pb2 as struct # type: ignore +from google.protobuf import timestamp_pb2 as timestamp # type: ignore from .transports.base import FlowsTransport, DEFAULT_CLIENT_INFO from .transports.grpc import FlowsGrpcTransport @@ -117,6 +119,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: + FlowsClient: 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 @@ -129,7 +147,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. + FlowsClient: The constructed client. """ credentials = service_account.Credentials.from_service_account_file(filename) kwargs["credentials"] = credentials @@ -162,6 +180,24 @@ def parse_flow_path(path: str) -> Dict[str, str]: ) return m.groupdict() if m else {} + @staticmethod + def flow_validation_result_path( + project: str, location: str, agent: str, flow: str, + ) -> str: + """Return a fully-qualified flow_validation_result string.""" + return "projects/{project}/locations/{location}/agents/{agent}/flows/{flow}/validationResult".format( + project=project, location=location, agent=agent, flow=flow, + ) + + @staticmethod + def parse_flow_validation_result_path(path: str) -> Dict[str, str]: + """Parse a flow_validation_result path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/locations/(?P.+?)/agents/(?P.+?)/flows/(?P.+?)/validationResult$", + path, + ) + return m.groupdict() if m else {} + @staticmethod def intent_path(project: str, location: str, agent: str, intent: str,) -> str: """Return a fully-qualified intent string.""" @@ -287,10 +323,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, ~.FlowsTransport]): The + transport (Union[str, FlowsTransport]): 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 @@ -326,21 +362,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: @@ -383,7 +415,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, ) @@ -401,16 +433,17 @@ def create_flow( r"""Creates a flow in the specified agent. Args: - request (:class:`~.gcdc_flow.CreateFlowRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.CreateFlowRequest): The request object. The request message for [Flows.CreateFlow][google.cloud.dialogflow.cx.v3beta1.Flows.CreateFlow]. - parent (:class:`str`): + parent (str): Required. The agent to create a flow for. Format: ``projects//locations//agents/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - flow (:class:`~.gcdc_flow.Flow`): + flow (google.cloud.dialogflowcx_v3beta1.types.Flow): Required. The flow to create. This corresponds to the ``flow`` field on the ``request`` instance; if ``request`` is provided, this @@ -423,7 +456,7 @@ def create_flow( sent along with the request as metadata. Returns: - ~.gcdc_flow.Flow: + google.cloud.dialogflowcx_v3beta1.types.Flow: Flows represents the conversation flows when you build your chatbot agent. A flow consists of many pages connected @@ -502,12 +535,13 @@ def delete_flow( r"""Deletes a specified flow. Args: - request (:class:`~.flow.DeleteFlowRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.DeleteFlowRequest): The request object. The request message for [Flows.DeleteFlow][google.cloud.dialogflow.cx.v3beta1.Flows.DeleteFlow]. - name (:class:`str`): + name (str): Required. The name of the flow to delete. Format: ``projects//locations//agents//flows/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -568,12 +602,13 @@ def list_flows( r"""Returns the list of all flows in the specified agent. Args: - request (:class:`~.flow.ListFlowsRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.ListFlowsRequest): The request object. The request message for [Flows.ListFlows][google.cloud.dialogflow.cx.v3beta1.Flows.ListFlows]. - parent (:class:`str`): + parent (str): Required. The agent containing the flows. Format: ``projects//locations//agents/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -585,7 +620,7 @@ def list_flows( sent along with the request as metadata. Returns: - ~.pagers.ListFlowsPager: + google.cloud.dialogflowcx_v3beta1.services.flows.pagers.ListFlowsPager: The response message for [Flows.ListFlows][google.cloud.dialogflow.cx.v3beta1.Flows.ListFlows]. @@ -650,12 +685,13 @@ def get_flow( r"""Retrieves the specified flow. Args: - request (:class:`~.flow.GetFlowRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.GetFlowRequest): The request object. The response message for [Flows.GetFlow][google.cloud.dialogflow.cx.v3beta1.Flows.GetFlow]. - name (:class:`str`): + name (str): Required. The name of the flow to get. Format: ``projects//locations//agents//flows/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -667,7 +703,7 @@ def get_flow( sent along with the request as metadata. Returns: - ~.flow.Flow: + google.cloud.dialogflowcx_v3beta1.types.Flow: Flows represents the conversation flows when you build your chatbot agent. A flow consists of many pages connected @@ -745,18 +781,19 @@ def update_flow( r"""Updates the specified flow. Args: - request (:class:`~.gcdc_flow.UpdateFlowRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.UpdateFlowRequest): The request object. The request message for [Flows.UpdateFlow][google.cloud.dialogflow.cx.v3beta1.Flows.UpdateFlow]. - flow (:class:`~.gcdc_flow.Flow`): + flow (google.cloud.dialogflowcx_v3beta1.types.Flow): Required. The flow to update. This corresponds to the ``flow`` 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): Required. The mask to control which fields get updated. If ``update_mask`` is not specified, an error will be returned. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -768,7 +805,7 @@ def update_flow( sent along with the request as metadata. Returns: - ~.gcdc_flow.Flow: + google.cloud.dialogflowcx_v3beta1.types.Flow: Flows represents the conversation flows when you build your chatbot agent. A flow consists of many pages connected @@ -850,12 +887,13 @@ def train_flow( 'draft' environment is trained. Args: - request (:class:`~.flow.TrainFlowRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.TrainFlowRequest): The request object. The request message for [Flows.TrainFlow][google.cloud.dialogflow.cx.v3beta1.Flows.TrainFlow]. - name (:class:`str`): + name (str): Required. The flow to train. Format: ``projects//locations//agents//flows/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -867,24 +905,22 @@ def train_flow( 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:``~.empty.Empty``: A generic empty message that - you can re-use to avoid defining duplicated empty - messages in your APIs. A typical example is to use it as - the request or the response type of an API method. For - instance: + The result type for the operation will be :class:`google.protobuf.empty_pb2.Empty` A generic empty message that you can re-use to avoid defining duplicated + empty messages in your APIs. A typical example is to + use it as the request or the response type of an API + method. For instance: - :: + service Foo { + rpc Bar(google.protobuf.Empty) returns + (google.protobuf.Empty); - service Foo { - rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty); - } + } - The JSON representation for ``Empty`` is empty JSON - object ``{}``. + The JSON representation for Empty is empty JSON + object {}. """ # Create or coerce a protobuf request object. @@ -934,6 +970,138 @@ def train_flow( # Done; return the response. return response + def validate_flow( + self, + request: flow.ValidateFlowRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> flow.FlowValidationResult: + r"""Validates the specified flow and creates or updates + validation results. Please call this API after the + training is completed to get the complete validation + results. + + Args: + request (google.cloud.dialogflowcx_v3beta1.types.ValidateFlowRequest): + The request object. The request message for + [Flows.ValidateFlow][google.cloud.dialogflow.cx.v3beta1.Flows.ValidateFlow]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.dialogflowcx_v3beta1.types.FlowValidationResult: + The response message for + [Flows.GetFlowValidationResult][google.cloud.dialogflow.cx.v3beta1.Flows.GetFlowValidationResult]. + + """ + # Create or coerce a protobuf request object. + + # Minor optimization to avoid making a copy if the user passes + # in a flow.ValidateFlowRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, flow.ValidateFlowRequest): + request = flow.ValidateFlowRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.validate_flow] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + + def get_flow_validation_result( + self, + request: flow.GetFlowValidationResultRequest = None, + *, + name: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> flow.FlowValidationResult: + r"""Gets the latest flow validation result. Flow + validation is performed when ValidateFlow is called. + + Args: + request (google.cloud.dialogflowcx_v3beta1.types.GetFlowValidationResultRequest): + The request object. The request message for + [Flows.GetFlowValidationResult][google.cloud.dialogflow.cx.v3beta1.Flows.GetFlowValidationResult]. + name (str): + Required. The flow name. Format: + ``projects//locations//agents//flows//validationResult``. + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.dialogflowcx_v3beta1.types.FlowValidationResult: + The response message for + [Flows.GetFlowValidationResult][google.cloud.dialogflow.cx.v3beta1.Flows.GetFlowValidationResult]. + + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a flow.GetFlowValidationResultRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, flow.GetFlowValidationResultRequest): + request = flow.GetFlowValidationResultRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[ + self._transport.get_flow_validation_result + ] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + try: DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( diff --git a/google/cloud/dialogflowcx_v3beta1/services/flows/pagers.py b/google/cloud/dialogflowcx_v3beta1/services/flows/pagers.py index ee15646e..84711637 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/flows/pagers.py +++ b/google/cloud/dialogflowcx_v3beta1/services/flows/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.dialogflowcx_v3beta1.types import flow @@ -24,7 +33,7 @@ class ListFlowsPager: """A pager for iterating through ``list_flows`` requests. This class thinly wraps an initial - :class:`~.flow.ListFlowsResponse` object, and + :class:`google.cloud.dialogflowcx_v3beta1.types.ListFlowsResponse` object, and provides an ``__iter__`` method to iterate through its ``flows`` field. @@ -33,7 +42,7 @@ class ListFlowsPager: through the ``flows`` field on the corresponding responses. - All the usual :class:`~.flow.ListFlowsResponse` + All the usual :class:`google.cloud.dialogflowcx_v3beta1.types.ListFlowsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -51,9 +60,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.flow.ListFlowsRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.ListFlowsRequest): The initial request object. - response (:class:`~.flow.ListFlowsResponse`): + response (google.cloud.dialogflowcx_v3beta1.types.ListFlowsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -86,7 +95,7 @@ class ListFlowsAsyncPager: """A pager for iterating through ``list_flows`` requests. This class thinly wraps an initial - :class:`~.flow.ListFlowsResponse` object, and + :class:`google.cloud.dialogflowcx_v3beta1.types.ListFlowsResponse` object, and provides an ``__aiter__`` method to iterate through its ``flows`` field. @@ -95,7 +104,7 @@ class ListFlowsAsyncPager: through the ``flows`` field on the corresponding responses. - All the usual :class:`~.flow.ListFlowsResponse` + All the usual :class:`google.cloud.dialogflowcx_v3beta1.types.ListFlowsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -113,9 +122,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.flow.ListFlowsRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.ListFlowsRequest): The initial request object. - response (:class:`~.flow.ListFlowsResponse`): + response (google.cloud.dialogflowcx_v3beta1.types.ListFlowsResponse): 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/dialogflowcx_v3beta1/services/flows/transports/base.py b/google/cloud/dialogflowcx_v3beta1/services/flows/transports/base.py index 40a2f25d..e1b65780 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/flows/transports/base.py +++ b/google/cloud/dialogflowcx_v3beta1/services/flows/transports/base.py @@ -131,6 +131,14 @@ def _prep_wrapped_messages(self, client_info): self.train_flow: gapic_v1.method.wrap_method( self.train_flow, default_timeout=None, client_info=client_info, ), + self.validate_flow: gapic_v1.method.wrap_method( + self.validate_flow, default_timeout=None, client_info=client_info, + ), + self.get_flow_validation_result: gapic_v1.method.wrap_method( + self.get_flow_validation_result, + default_timeout=None, + client_info=client_info, + ), } @property @@ -191,5 +199,27 @@ def train_flow( ]: raise NotImplementedError() + @property + def validate_flow( + self, + ) -> typing.Callable[ + [flow.ValidateFlowRequest], + typing.Union[ + flow.FlowValidationResult, typing.Awaitable[flow.FlowValidationResult] + ], + ]: + raise NotImplementedError() + + @property + def get_flow_validation_result( + self, + ) -> typing.Callable[ + [flow.GetFlowValidationResultRequest], + typing.Union[ + flow.FlowValidationResult, typing.Awaitable[flow.FlowValidationResult] + ], + ]: + raise NotImplementedError() + __all__ = ("FlowsTransport",) diff --git a/google/cloud/dialogflowcx_v3beta1/services/flows/transports/grpc.py b/google/cloud/dialogflowcx_v3beta1/services/flows/transports/grpc.py index e277d692..cd3a4740 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/flows/transports/grpc.py +++ b/google/cloud/dialogflowcx_v3beta1/services/flows/transports/grpc.py @@ -62,6 +62,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: @@ -92,6 +93,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): @@ -108,6 +113,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -117,11 +127,6 @@ def __init__( 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 @@ -165,12 +170,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ @@ -402,5 +413,61 @@ def train_flow(self) -> Callable[[flow.TrainFlowRequest], operations.Operation]: ) return self._stubs["train_flow"] + @property + def validate_flow( + self, + ) -> Callable[[flow.ValidateFlowRequest], flow.FlowValidationResult]: + r"""Return a callable for the validate flow method over gRPC. + + Validates the specified flow and creates or updates + validation results. Please call this API after the + training is completed to get the complete validation + results. + + Returns: + Callable[[~.ValidateFlowRequest], + ~.FlowValidationResult]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "validate_flow" not in self._stubs: + self._stubs["validate_flow"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3beta1.Flows/ValidateFlow", + request_serializer=flow.ValidateFlowRequest.serialize, + response_deserializer=flow.FlowValidationResult.deserialize, + ) + return self._stubs["validate_flow"] + + @property + def get_flow_validation_result( + self, + ) -> Callable[[flow.GetFlowValidationResultRequest], flow.FlowValidationResult]: + r"""Return a callable for the get flow validation result method over gRPC. + + Gets the latest flow validation result. Flow + validation is performed when ValidateFlow is called. + + Returns: + Callable[[~.GetFlowValidationResultRequest], + ~.FlowValidationResult]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_flow_validation_result" not in self._stubs: + self._stubs["get_flow_validation_result"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3beta1.Flows/GetFlowValidationResult", + request_serializer=flow.GetFlowValidationResultRequest.serialize, + response_deserializer=flow.FlowValidationResult.deserialize, + ) + return self._stubs["get_flow_validation_result"] + __all__ = ("FlowsGrpcTransport",) diff --git a/google/cloud/dialogflowcx_v3beta1/services/flows/transports/grpc_asyncio.py b/google/cloud/dialogflowcx_v3beta1/services/flows/transports/grpc_asyncio.py index ce42b92f..96562f69 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/flows/transports/grpc_asyncio.py +++ b/google/cloud/dialogflowcx_v3beta1/services/flows/transports/grpc_asyncio.py @@ -106,6 +106,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: @@ -137,6 +138,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): @@ -153,6 +158,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -162,11 +172,6 @@ def __init__( 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 @@ -210,12 +215,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ @@ -416,5 +427,63 @@ def train_flow( ) return self._stubs["train_flow"] + @property + def validate_flow( + self, + ) -> Callable[[flow.ValidateFlowRequest], Awaitable[flow.FlowValidationResult]]: + r"""Return a callable for the validate flow method over gRPC. + + Validates the specified flow and creates or updates + validation results. Please call this API after the + training is completed to get the complete validation + results. + + Returns: + Callable[[~.ValidateFlowRequest], + Awaitable[~.FlowValidationResult]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "validate_flow" not in self._stubs: + self._stubs["validate_flow"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3beta1.Flows/ValidateFlow", + request_serializer=flow.ValidateFlowRequest.serialize, + response_deserializer=flow.FlowValidationResult.deserialize, + ) + return self._stubs["validate_flow"] + + @property + def get_flow_validation_result( + self, + ) -> Callable[ + [flow.GetFlowValidationResultRequest], Awaitable[flow.FlowValidationResult] + ]: + r"""Return a callable for the get flow validation result method over gRPC. + + Gets the latest flow validation result. Flow + validation is performed when ValidateFlow is called. + + Returns: + Callable[[~.GetFlowValidationResultRequest], + Awaitable[~.FlowValidationResult]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_flow_validation_result" not in self._stubs: + self._stubs["get_flow_validation_result"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3beta1.Flows/GetFlowValidationResult", + request_serializer=flow.GetFlowValidationResultRequest.serialize, + response_deserializer=flow.FlowValidationResult.deserialize, + ) + return self._stubs["get_flow_validation_result"] + __all__ = ("FlowsGrpcAsyncIOTransport",) diff --git a/google/cloud/dialogflowcx_v3beta1/services/intents/async_client.py b/google/cloud/dialogflowcx_v3beta1/services/intents/async_client.py index e0082d6b..dc675ff8 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/intents/async_client.py +++ b/google/cloud/dialogflowcx_v3beta1/services/intents/async_client.py @@ -74,7 +74,36 @@ class IntentsAsyncClient: common_location_path = staticmethod(IntentsClient.common_location_path) parse_common_location_path = staticmethod(IntentsClient.parse_common_location_path) - from_service_account_file = IntentsClient.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: + IntentsAsyncClient: The constructed client. + """ + return IntentsClient.from_service_account_info.__func__(IntentsAsyncClient, 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: + IntentsAsyncClient: The constructed client. + """ + return IntentsClient.from_service_account_file.__func__(IntentsAsyncClient, filename, *args, **kwargs) # type: ignore + from_service_account_json = from_service_account_file @property @@ -151,12 +180,13 @@ async def list_intents( agent. Args: - request (:class:`~.intent.ListIntentsRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.ListIntentsRequest`): The request object. The request message for [Intents.ListIntents][google.cloud.dialogflow.cx.v3beta1.Intents.ListIntents]. parent (:class:`str`): Required. The agent to list all intents for. Format: ``projects//locations//agents/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -168,7 +198,7 @@ async def list_intents( sent along with the request as metadata. Returns: - ~.pagers.ListIntentsAsyncPager: + google.cloud.dialogflowcx_v3beta1.services.intents.pagers.ListIntentsAsyncPager: The response message for [Intents.ListIntents][google.cloud.dialogflow.cx.v3beta1.Intents.ListIntents]. @@ -232,12 +262,13 @@ async def get_intent( r"""Retrieves the specified intent. Args: - request (:class:`~.intent.GetIntentRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.GetIntentRequest`): The request object. The request message for [Intents.GetIntent][google.cloud.dialogflow.cx.v3beta1.Intents.GetIntent]. name (:class:`str`): Required. The name of the intent. Format: ``projects//locations//agents//intents/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -249,7 +280,7 @@ async def get_intent( sent along with the request as metadata. Returns: - ~.intent.Intent: + google.cloud.dialogflowcx_v3beta1.types.Intent: An intent represents a user's intent to interact with a conversational agent. You can provide information for the @@ -310,16 +341,17 @@ async def create_intent( r"""Creates an intent in the specified agent. Args: - request (:class:`~.gcdc_intent.CreateIntentRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.CreateIntentRequest`): The request object. The request message for [Intents.CreateIntent][google.cloud.dialogflow.cx.v3beta1.Intents.CreateIntent]. parent (:class:`str`): Required. The agent to create an intent for. Format: ``projects//locations//agents/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - intent (:class:`~.gcdc_intent.Intent`): + intent (:class:`google.cloud.dialogflowcx_v3beta1.types.Intent`): Required. The intent to create. This corresponds to the ``intent`` field on the ``request`` instance; if ``request`` is provided, this @@ -332,7 +364,7 @@ async def create_intent( sent along with the request as metadata. Returns: - ~.gcdc_intent.Intent: + google.cloud.dialogflowcx_v3beta1.types.Intent: An intent represents a user's intent to interact with a conversational agent. You can provide information for the @@ -395,18 +427,19 @@ async def update_intent( r"""Updates the specified intent. Args: - request (:class:`~.gcdc_intent.UpdateIntentRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.UpdateIntentRequest`): The request object. The request message for [Intents.UpdateIntent][google.cloud.dialogflow.cx.v3beta1.Intents.UpdateIntent]. - intent (:class:`~.gcdc_intent.Intent`): + intent (:class:`google.cloud.dialogflowcx_v3beta1.types.Intent`): Required. The intent to update. This corresponds to the ``intent`` 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`): The mask to control which fields get updated. If the mask is not present, all fields will be updated. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -418,7 +451,7 @@ async def update_intent( sent along with the request as metadata. Returns: - ~.gcdc_intent.Intent: + google.cloud.dialogflowcx_v3beta1.types.Intent: An intent represents a user's intent to interact with a conversational agent. You can provide information for the @@ -482,12 +515,13 @@ async def delete_intent( r"""Deletes the specified intent. Args: - request (:class:`~.intent.DeleteIntentRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.DeleteIntentRequest`): The request object. The request message for [Intents.DeleteIntent][google.cloud.dialogflow.cx.v3beta1.Intents.DeleteIntent]. name (:class:`str`): Required. The name of the intent to delete. Format: ``projects//locations//agents//intents/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. diff --git a/google/cloud/dialogflowcx_v3beta1/services/intents/client.py b/google/cloud/dialogflowcx_v3beta1/services/intents/client.py index 44250d8e..1418f739 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/intents/client.py +++ b/google/cloud/dialogflowcx_v3beta1/services/intents/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: + IntentsClient: 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. + IntentsClient: The constructed client. """ credentials = service_account.Credentials.from_service_account_file(filename) kwargs["credentials"] = credentials @@ -250,10 +266,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, ~.IntentsTransport]): The + transport (Union[str, IntentsTransport]): 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 @@ -289,21 +305,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: @@ -346,7 +358,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,12 +376,13 @@ def list_intents( agent. Args: - request (:class:`~.intent.ListIntentsRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.ListIntentsRequest): The request object. The request message for [Intents.ListIntents][google.cloud.dialogflow.cx.v3beta1.Intents.ListIntents]. - parent (:class:`str`): + parent (str): Required. The agent to list all intents for. Format: ``projects//locations//agents/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -381,7 +394,7 @@ def list_intents( sent along with the request as metadata. Returns: - ~.pagers.ListIntentsPager: + google.cloud.dialogflowcx_v3beta1.services.intents.pagers.ListIntentsPager: The response message for [Intents.ListIntents][google.cloud.dialogflow.cx.v3beta1.Intents.ListIntents]. @@ -446,12 +459,13 @@ def get_intent( r"""Retrieves the specified intent. Args: - request (:class:`~.intent.GetIntentRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.GetIntentRequest): The request object. The request message for [Intents.GetIntent][google.cloud.dialogflow.cx.v3beta1.Intents.GetIntent]. - name (:class:`str`): + name (str): Required. The name of the intent. Format: ``projects//locations//agents//intents/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -463,7 +477,7 @@ def get_intent( sent along with the request as metadata. Returns: - ~.intent.Intent: + google.cloud.dialogflowcx_v3beta1.types.Intent: An intent represents a user's intent to interact with a conversational agent. You can provide information for the @@ -525,16 +539,17 @@ def create_intent( r"""Creates an intent in the specified agent. Args: - request (:class:`~.gcdc_intent.CreateIntentRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.CreateIntentRequest): The request object. The request message for [Intents.CreateIntent][google.cloud.dialogflow.cx.v3beta1.Intents.CreateIntent]. - parent (:class:`str`): + parent (str): Required. The agent to create an intent for. Format: ``projects//locations//agents/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - intent (:class:`~.gcdc_intent.Intent`): + intent (google.cloud.dialogflowcx_v3beta1.types.Intent): Required. The intent to create. This corresponds to the ``intent`` field on the ``request`` instance; if ``request`` is provided, this @@ -547,7 +562,7 @@ def create_intent( sent along with the request as metadata. Returns: - ~.gcdc_intent.Intent: + google.cloud.dialogflowcx_v3beta1.types.Intent: An intent represents a user's intent to interact with a conversational agent. You can provide information for the @@ -611,18 +626,19 @@ def update_intent( r"""Updates the specified intent. Args: - request (:class:`~.gcdc_intent.UpdateIntentRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.UpdateIntentRequest): The request object. The request message for [Intents.UpdateIntent][google.cloud.dialogflow.cx.v3beta1.Intents.UpdateIntent]. - intent (:class:`~.gcdc_intent.Intent`): + intent (google.cloud.dialogflowcx_v3beta1.types.Intent): Required. The intent to update. This corresponds to the ``intent`` 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): The mask to control which fields get updated. If the mask is not present, all fields will be updated. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -634,7 +650,7 @@ def update_intent( sent along with the request as metadata. Returns: - ~.gcdc_intent.Intent: + google.cloud.dialogflowcx_v3beta1.types.Intent: An intent represents a user's intent to interact with a conversational agent. You can provide information for the @@ -699,12 +715,13 @@ def delete_intent( r"""Deletes the specified intent. Args: - request (:class:`~.intent.DeleteIntentRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.DeleteIntentRequest): The request object. The request message for [Intents.DeleteIntent][google.cloud.dialogflow.cx.v3beta1.Intents.DeleteIntent]. - name (:class:`str`): + name (str): Required. The name of the intent to delete. Format: ``projects//locations//agents//intents/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. diff --git a/google/cloud/dialogflowcx_v3beta1/services/intents/pagers.py b/google/cloud/dialogflowcx_v3beta1/services/intents/pagers.py index 2f072ca1..f3f8d5e0 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/intents/pagers.py +++ b/google/cloud/dialogflowcx_v3beta1/services/intents/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.dialogflowcx_v3beta1.types import intent @@ -24,7 +33,7 @@ class ListIntentsPager: """A pager for iterating through ``list_intents`` requests. This class thinly wraps an initial - :class:`~.intent.ListIntentsResponse` object, and + :class:`google.cloud.dialogflowcx_v3beta1.types.ListIntentsResponse` object, and provides an ``__iter__`` method to iterate through its ``intents`` field. @@ -33,7 +42,7 @@ class ListIntentsPager: through the ``intents`` field on the corresponding responses. - All the usual :class:`~.intent.ListIntentsResponse` + All the usual :class:`google.cloud.dialogflowcx_v3beta1.types.ListIntentsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -51,9 +60,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.intent.ListIntentsRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.ListIntentsRequest): The initial request object. - response (:class:`~.intent.ListIntentsResponse`): + response (google.cloud.dialogflowcx_v3beta1.types.ListIntentsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -86,7 +95,7 @@ class ListIntentsAsyncPager: """A pager for iterating through ``list_intents`` requests. This class thinly wraps an initial - :class:`~.intent.ListIntentsResponse` object, and + :class:`google.cloud.dialogflowcx_v3beta1.types.ListIntentsResponse` object, and provides an ``__aiter__`` method to iterate through its ``intents`` field. @@ -95,7 +104,7 @@ class ListIntentsAsyncPager: through the ``intents`` field on the corresponding responses. - All the usual :class:`~.intent.ListIntentsResponse` + All the usual :class:`google.cloud.dialogflowcx_v3beta1.types.ListIntentsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -113,9 +122,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.intent.ListIntentsRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.ListIntentsRequest): The initial request object. - response (:class:`~.intent.ListIntentsResponse`): + response (google.cloud.dialogflowcx_v3beta1.types.ListIntentsResponse): 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/dialogflowcx_v3beta1/services/intents/transports/grpc.py b/google/cloud/dialogflowcx_v3beta1/services/intents/transports/grpc.py index 6d640e23..3cf59920 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/intents/transports/grpc.py +++ b/google/cloud/dialogflowcx_v3beta1/services/intents/transports/grpc.py @@ -60,6 +60,7 @@ def __init__( api_mtls_endpoint: str = None, client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, quota_project_id: Optional[str] = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: @@ -90,6 +91,10 @@ def __init__( ``api_mtls_endpoint`` is None. ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials for grpc channel. It is ignored if ``channel`` is provided. + client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]): + A callback to provide client certificate bytes and private key bytes, + both in PEM format. It is used to configure mutual TLS channel. It is + ignored if ``channel`` or ``ssl_channel_credentials`` is provided. quota_project_id (Optional[str]): An optional project to use for billing and quota. client_info (google.api_core.gapic_v1.client_info.ClientInfo): @@ -106,6 +111,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -115,11 +125,6 @@ def __init__( 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 @@ -163,12 +168,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ diff --git a/google/cloud/dialogflowcx_v3beta1/services/intents/transports/grpc_asyncio.py b/google/cloud/dialogflowcx_v3beta1/services/intents/transports/grpc_asyncio.py index dbe9a43c..2a44ac56 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/intents/transports/grpc_asyncio.py +++ b/google/cloud/dialogflowcx_v3beta1/services/intents/transports/grpc_asyncio.py @@ -104,6 +104,7 @@ def __init__( api_mtls_endpoint: str = None, client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, quota_project_id=None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: @@ -135,6 +136,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): @@ -151,6 +156,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -160,11 +170,6 @@ def __init__( 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 @@ -208,12 +213,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ diff --git a/google/cloud/dialogflowcx_v3beta1/services/pages/async_client.py b/google/cloud/dialogflowcx_v3beta1/services/pages/async_client.py index b16d077b..1d99a61b 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/pages/async_client.py +++ b/google/cloud/dialogflowcx_v3beta1/services/pages/async_client.py @@ -83,7 +83,36 @@ class PagesAsyncClient: common_location_path = staticmethod(PagesClient.common_location_path) parse_common_location_path = staticmethod(PagesClient.parse_common_location_path) - from_service_account_file = PagesClient.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: + PagesAsyncClient: The constructed client. + """ + return PagesClient.from_service_account_info.__func__(PagesAsyncClient, 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: + PagesAsyncClient: The constructed client. + """ + return PagesClient.from_service_account_file.__func__(PagesAsyncClient, filename, *args, **kwargs) # type: ignore + from_service_account_json = from_service_account_file @property @@ -159,12 +188,13 @@ async def list_pages( r"""Returns the list of all pages in the specified flow. Args: - request (:class:`~.page.ListPagesRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.ListPagesRequest`): The request object. The request message for [Pages.ListPages][google.cloud.dialogflow.cx.v3beta1.Pages.ListPages]. parent (:class:`str`): Required. The flow to list all pages for. Format: ``projects//locations//agents//flows/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -176,7 +206,7 @@ async def list_pages( sent along with the request as metadata. Returns: - ~.pagers.ListPagesAsyncPager: + google.cloud.dialogflowcx_v3beta1.services.pages.pagers.ListPagesAsyncPager: The response message for [Pages.ListPages][google.cloud.dialogflow.cx.v3beta1.Pages.ListPages]. @@ -240,12 +270,13 @@ async def get_page( r"""Retrieves the specified page. Args: - request (:class:`~.page.GetPageRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.GetPageRequest`): The request object. The request message for [Pages.GetPage][google.cloud.dialogflow.cx.v3beta1.Pages.GetPage]. name (:class:`str`): Required. The name of the page. Format: ``projects//locations//agents//flows//pages/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -257,28 +288,29 @@ async def get_page( sent along with the request as metadata. Returns: - ~.page.Page: - A Dialogflow CX conversation (session) can be described - and visualized as a state machine. The states of a CX - session are represented by pages. - - For each flow, you define many pages, where your - combined pages can handle a complete conversation on the - topics the flow is designed for. At any given moment, - exactly one page is the current page, the current page - is considered active, and the flow associated with that - page is considered active. Every flow has a special - start page. When a flow initially becomes active, the - start page page becomes the current page. For each - conversational turn, the current page will either stay - the same or transition to another page. - - You configure each page to collect information from the - end-user that is relevant for the conversational state - represented by the page. - - For more information, see the `Page - guide `__. + google.cloud.dialogflowcx_v3beta1.types.Page: + A Dialogflow CX conversation (session) can be described and visualized as a + state machine. The states of a CX session are + represented by pages. + + For each flow, you define many pages, where your + combined pages can handle a complete conversation on + the topics the flow is designed for. At any given + moment, exactly one page is the current page, the + current page is considered active, and the flow + associated with that page is considered active. Every + flow has a special start page. When a flow initially + becomes active, the start page page becomes the + current page. For each conversational turn, the + current page will either stay the same or transition + to another page. + + You configure each page to collect information from + the end-user that is relevant for the conversational + state represented by the page. + + For more information, see the [Page + guide](\ https://cloud.google.com/dialogflow/cx/docs/concept/page). """ # Create or coerce a protobuf request object. @@ -332,16 +364,17 @@ async def create_page( r"""Creates a page in the specified flow. Args: - request (:class:`~.gcdc_page.CreatePageRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.CreatePageRequest`): The request object. The request message for [Pages.CreatePage][google.cloud.dialogflow.cx.v3beta1.Pages.CreatePage]. parent (:class:`str`): Required. The flow to create a page for. Format: ``projects//locations//agents//flows/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - page (:class:`~.gcdc_page.Page`): + page (:class:`google.cloud.dialogflowcx_v3beta1.types.Page`): Required. The page to create. This corresponds to the ``page`` field on the ``request`` instance; if ``request`` is provided, this @@ -354,28 +387,29 @@ async def create_page( sent along with the request as metadata. Returns: - ~.gcdc_page.Page: - A Dialogflow CX conversation (session) can be described - and visualized as a state machine. The states of a CX - session are represented by pages. - - For each flow, you define many pages, where your - combined pages can handle a complete conversation on the - topics the flow is designed for. At any given moment, - exactly one page is the current page, the current page - is considered active, and the flow associated with that - page is considered active. Every flow has a special - start page. When a flow initially becomes active, the - start page page becomes the current page. For each - conversational turn, the current page will either stay - the same or transition to another page. - - You configure each page to collect information from the - end-user that is relevant for the conversational state - represented by the page. - - For more information, see the `Page - guide `__. + google.cloud.dialogflowcx_v3beta1.types.Page: + A Dialogflow CX conversation (session) can be described and visualized as a + state machine. The states of a CX session are + represented by pages. + + For each flow, you define many pages, where your + combined pages can handle a complete conversation on + the topics the flow is designed for. At any given + moment, exactly one page is the current page, the + current page is considered active, and the flow + associated with that page is considered active. Every + flow has a special start page. When a flow initially + becomes active, the start page page becomes the + current page. For each conversational turn, the + current page will either stay the same or transition + to another page. + + You configure each page to collect information from + the end-user that is relevant for the conversational + state represented by the page. + + For more information, see the [Page + guide](\ https://cloud.google.com/dialogflow/cx/docs/concept/page). """ # Create or coerce a protobuf request object. @@ -431,18 +465,19 @@ async def update_page( r"""Updates the specified page. Args: - request (:class:`~.gcdc_page.UpdatePageRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.UpdatePageRequest`): The request object. The request message for [Pages.UpdatePage][google.cloud.dialogflow.cx.v3beta1.Pages.UpdatePage]. - page (:class:`~.gcdc_page.Page`): + page (:class:`google.cloud.dialogflowcx_v3beta1.types.Page`): Required. The page to update. This corresponds to the ``page`` 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`): The mask to control which fields get updated. If the mask is not present, all fields will be updated. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -454,28 +489,29 @@ async def update_page( sent along with the request as metadata. Returns: - ~.gcdc_page.Page: - A Dialogflow CX conversation (session) can be described - and visualized as a state machine. The states of a CX - session are represented by pages. - - For each flow, you define many pages, where your - combined pages can handle a complete conversation on the - topics the flow is designed for. At any given moment, - exactly one page is the current page, the current page - is considered active, and the flow associated with that - page is considered active. Every flow has a special - start page. When a flow initially becomes active, the - start page page becomes the current page. For each - conversational turn, the current page will either stay - the same or transition to another page. - - You configure each page to collect information from the - end-user that is relevant for the conversational state - represented by the page. - - For more information, see the `Page - guide `__. + google.cloud.dialogflowcx_v3beta1.types.Page: + A Dialogflow CX conversation (session) can be described and visualized as a + state machine. The states of a CX session are + represented by pages. + + For each flow, you define many pages, where your + combined pages can handle a complete conversation on + the topics the flow is designed for. At any given + moment, exactly one page is the current page, the + current page is considered active, and the flow + associated with that page is considered active. Every + flow has a special start page. When a flow initially + becomes active, the start page page becomes the + current page. For each conversational turn, the + current page will either stay the same or transition + to another page. + + You configure each page to collect information from + the end-user that is relevant for the conversational + state represented by the page. + + For more information, see the [Page + guide](\ https://cloud.google.com/dialogflow/cx/docs/concept/page). """ # Create or coerce a protobuf request object. @@ -532,12 +568,13 @@ async def delete_page( r"""Deletes the specified page. Args: - request (:class:`~.page.DeletePageRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.DeletePageRequest`): The request object. The request message for [Pages.DeletePage][google.cloud.dialogflow.cx.v3beta1.Pages.DeletePage]. name (:class:`str`): Required. The name of the page to delete. Format: ``projects//locations//agents//Flows//pages/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. diff --git a/google/cloud/dialogflowcx_v3beta1/services/pages/client.py b/google/cloud/dialogflowcx_v3beta1/services/pages/client.py index 011f3033..6e97331b 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/pages/client.py +++ b/google/cloud/dialogflowcx_v3beta1/services/pages/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: + PagesClient: 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. + PagesClient: The constructed client. """ credentials = service_account.Credentials.from_service_account_file(filename) kwargs["credentials"] = credentials @@ -323,10 +339,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, ~.PagesTransport]): The + transport (Union[str, PagesTransport]): 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 @@ -362,21 +378,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: @@ -419,7 +431,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, ) @@ -436,12 +448,13 @@ def list_pages( r"""Returns the list of all pages in the specified flow. Args: - request (:class:`~.page.ListPagesRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.ListPagesRequest): The request object. The request message for [Pages.ListPages][google.cloud.dialogflow.cx.v3beta1.Pages.ListPages]. - parent (:class:`str`): + parent (str): Required. The flow to list all pages for. Format: ``projects//locations//agents//flows/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -453,7 +466,7 @@ def list_pages( sent along with the request as metadata. Returns: - ~.pagers.ListPagesPager: + google.cloud.dialogflowcx_v3beta1.services.pages.pagers.ListPagesPager: The response message for [Pages.ListPages][google.cloud.dialogflow.cx.v3beta1.Pages.ListPages]. @@ -518,12 +531,13 @@ def get_page( r"""Retrieves the specified page. Args: - request (:class:`~.page.GetPageRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.GetPageRequest): The request object. The request message for [Pages.GetPage][google.cloud.dialogflow.cx.v3beta1.Pages.GetPage]. - name (:class:`str`): + name (str): Required. The name of the page. Format: ``projects//locations//agents//flows//pages/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -535,28 +549,29 @@ def get_page( sent along with the request as metadata. Returns: - ~.page.Page: - A Dialogflow CX conversation (session) can be described - and visualized as a state machine. The states of a CX - session are represented by pages. - - For each flow, you define many pages, where your - combined pages can handle a complete conversation on the - topics the flow is designed for. At any given moment, - exactly one page is the current page, the current page - is considered active, and the flow associated with that - page is considered active. Every flow has a special - start page. When a flow initially becomes active, the - start page page becomes the current page. For each - conversational turn, the current page will either stay - the same or transition to another page. - - You configure each page to collect information from the - end-user that is relevant for the conversational state - represented by the page. - - For more information, see the `Page - guide `__. + google.cloud.dialogflowcx_v3beta1.types.Page: + A Dialogflow CX conversation (session) can be described and visualized as a + state machine. The states of a CX session are + represented by pages. + + For each flow, you define many pages, where your + combined pages can handle a complete conversation on + the topics the flow is designed for. At any given + moment, exactly one page is the current page, the + current page is considered active, and the flow + associated with that page is considered active. Every + flow has a special start page. When a flow initially + becomes active, the start page page becomes the + current page. For each conversational turn, the + current page will either stay the same or transition + to another page. + + You configure each page to collect information from + the end-user that is relevant for the conversational + state represented by the page. + + For more information, see the [Page + guide](\ https://cloud.google.com/dialogflow/cx/docs/concept/page). """ # Create or coerce a protobuf request object. @@ -611,16 +626,17 @@ def create_page( r"""Creates a page in the specified flow. Args: - request (:class:`~.gcdc_page.CreatePageRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.CreatePageRequest): The request object. The request message for [Pages.CreatePage][google.cloud.dialogflow.cx.v3beta1.Pages.CreatePage]. - parent (:class:`str`): + parent (str): Required. The flow to create a page for. Format: ``projects//locations//agents//flows/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - page (:class:`~.gcdc_page.Page`): + page (google.cloud.dialogflowcx_v3beta1.types.Page): Required. The page to create. This corresponds to the ``page`` field on the ``request`` instance; if ``request`` is provided, this @@ -633,28 +649,29 @@ def create_page( sent along with the request as metadata. Returns: - ~.gcdc_page.Page: - A Dialogflow CX conversation (session) can be described - and visualized as a state machine. The states of a CX - session are represented by pages. - - For each flow, you define many pages, where your - combined pages can handle a complete conversation on the - topics the flow is designed for. At any given moment, - exactly one page is the current page, the current page - is considered active, and the flow associated with that - page is considered active. Every flow has a special - start page. When a flow initially becomes active, the - start page page becomes the current page. For each - conversational turn, the current page will either stay - the same or transition to another page. - - You configure each page to collect information from the - end-user that is relevant for the conversational state - represented by the page. - - For more information, see the `Page - guide `__. + google.cloud.dialogflowcx_v3beta1.types.Page: + A Dialogflow CX conversation (session) can be described and visualized as a + state machine. The states of a CX session are + represented by pages. + + For each flow, you define many pages, where your + combined pages can handle a complete conversation on + the topics the flow is designed for. At any given + moment, exactly one page is the current page, the + current page is considered active, and the flow + associated with that page is considered active. Every + flow has a special start page. When a flow initially + becomes active, the start page page becomes the + current page. For each conversational turn, the + current page will either stay the same or transition + to another page. + + You configure each page to collect information from + the end-user that is relevant for the conversational + state represented by the page. + + For more information, see the [Page + guide](\ https://cloud.google.com/dialogflow/cx/docs/concept/page). """ # Create or coerce a protobuf request object. @@ -711,18 +728,19 @@ def update_page( r"""Updates the specified page. Args: - request (:class:`~.gcdc_page.UpdatePageRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.UpdatePageRequest): The request object. The request message for [Pages.UpdatePage][google.cloud.dialogflow.cx.v3beta1.Pages.UpdatePage]. - page (:class:`~.gcdc_page.Page`): + page (google.cloud.dialogflowcx_v3beta1.types.Page): Required. The page to update. This corresponds to the ``page`` 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): The mask to control which fields get updated. If the mask is not present, all fields will be updated. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -734,28 +752,29 @@ def update_page( sent along with the request as metadata. Returns: - ~.gcdc_page.Page: - A Dialogflow CX conversation (session) can be described - and visualized as a state machine. The states of a CX - session are represented by pages. - - For each flow, you define many pages, where your - combined pages can handle a complete conversation on the - topics the flow is designed for. At any given moment, - exactly one page is the current page, the current page - is considered active, and the flow associated with that - page is considered active. Every flow has a special - start page. When a flow initially becomes active, the - start page page becomes the current page. For each - conversational turn, the current page will either stay - the same or transition to another page. - - You configure each page to collect information from the - end-user that is relevant for the conversational state - represented by the page. - - For more information, see the `Page - guide `__. + google.cloud.dialogflowcx_v3beta1.types.Page: + A Dialogflow CX conversation (session) can be described and visualized as a + state machine. The states of a CX session are + represented by pages. + + For each flow, you define many pages, where your + combined pages can handle a complete conversation on + the topics the flow is designed for. At any given + moment, exactly one page is the current page, the + current page is considered active, and the flow + associated with that page is considered active. Every + flow has a special start page. When a flow initially + becomes active, the start page page becomes the + current page. For each conversational turn, the + current page will either stay the same or transition + to another page. + + You configure each page to collect information from + the end-user that is relevant for the conversational + state represented by the page. + + For more information, see the [Page + guide](\ https://cloud.google.com/dialogflow/cx/docs/concept/page). """ # Create or coerce a protobuf request object. @@ -813,12 +832,13 @@ def delete_page( r"""Deletes the specified page. Args: - request (:class:`~.page.DeletePageRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.DeletePageRequest): The request object. The request message for [Pages.DeletePage][google.cloud.dialogflow.cx.v3beta1.Pages.DeletePage]. - name (:class:`str`): + name (str): Required. The name of the page to delete. Format: ``projects//locations//agents//Flows//pages/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. diff --git a/google/cloud/dialogflowcx_v3beta1/services/pages/pagers.py b/google/cloud/dialogflowcx_v3beta1/services/pages/pagers.py index caf07d79..c075da86 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/pages/pagers.py +++ b/google/cloud/dialogflowcx_v3beta1/services/pages/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.dialogflowcx_v3beta1.types import page @@ -24,7 +33,7 @@ class ListPagesPager: """A pager for iterating through ``list_pages`` requests. This class thinly wraps an initial - :class:`~.page.ListPagesResponse` object, and + :class:`google.cloud.dialogflowcx_v3beta1.types.ListPagesResponse` object, and provides an ``__iter__`` method to iterate through its ``pages`` field. @@ -33,7 +42,7 @@ class ListPagesPager: through the ``pages`` field on the corresponding responses. - All the usual :class:`~.page.ListPagesResponse` + All the usual :class:`google.cloud.dialogflowcx_v3beta1.types.ListPagesResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -51,9 +60,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.page.ListPagesRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.ListPagesRequest): The initial request object. - response (:class:`~.page.ListPagesResponse`): + response (google.cloud.dialogflowcx_v3beta1.types.ListPagesResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -86,7 +95,7 @@ class ListPagesAsyncPager: """A pager for iterating through ``list_pages`` requests. This class thinly wraps an initial - :class:`~.page.ListPagesResponse` object, and + :class:`google.cloud.dialogflowcx_v3beta1.types.ListPagesResponse` object, and provides an ``__aiter__`` method to iterate through its ``pages`` field. @@ -95,7 +104,7 @@ class ListPagesAsyncPager: through the ``pages`` field on the corresponding responses. - All the usual :class:`~.page.ListPagesResponse` + All the usual :class:`google.cloud.dialogflowcx_v3beta1.types.ListPagesResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -113,9 +122,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.page.ListPagesRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.ListPagesRequest): The initial request object. - response (:class:`~.page.ListPagesResponse`): + response (google.cloud.dialogflowcx_v3beta1.types.ListPagesResponse): 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/dialogflowcx_v3beta1/services/pages/transports/grpc.py b/google/cloud/dialogflowcx_v3beta1/services/pages/transports/grpc.py index ebb93d43..e9879286 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/pages/transports/grpc.py +++ b/google/cloud/dialogflowcx_v3beta1/services/pages/transports/grpc.py @@ -60,6 +60,7 @@ def __init__( api_mtls_endpoint: str = None, client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, quota_project_id: Optional[str] = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: @@ -90,6 +91,10 @@ def __init__( ``api_mtls_endpoint`` is None. ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials for grpc channel. It is ignored if ``channel`` is provided. + client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]): + A callback to provide client certificate bytes and private key bytes, + both in PEM format. It is used to configure mutual TLS channel. It is + ignored if ``channel`` or ``ssl_channel_credentials`` is provided. quota_project_id (Optional[str]): An optional project to use for billing and quota. client_info (google.api_core.gapic_v1.client_info.ClientInfo): @@ -106,6 +111,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -115,11 +125,6 @@ def __init__( 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 @@ -163,12 +168,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ diff --git a/google/cloud/dialogflowcx_v3beta1/services/pages/transports/grpc_asyncio.py b/google/cloud/dialogflowcx_v3beta1/services/pages/transports/grpc_asyncio.py index 15048535..57bd8b7b 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/pages/transports/grpc_asyncio.py +++ b/google/cloud/dialogflowcx_v3beta1/services/pages/transports/grpc_asyncio.py @@ -104,6 +104,7 @@ def __init__( api_mtls_endpoint: str = None, client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, quota_project_id=None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: @@ -135,6 +136,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): @@ -151,6 +156,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -160,11 +170,6 @@ def __init__( 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 @@ -208,12 +213,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ diff --git a/google/cloud/dialogflowcx_v3beta1/services/security_settings_service/async_client.py b/google/cloud/dialogflowcx_v3beta1/services/security_settings_service/async_client.py index 537126f5..72c613ab 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/security_settings_service/async_client.py +++ b/google/cloud/dialogflowcx_v3beta1/services/security_settings_service/async_client.py @@ -88,7 +88,36 @@ class SecuritySettingsServiceAsyncClient: SecuritySettingsServiceClient.parse_common_location_path ) - from_service_account_file = SecuritySettingsServiceClient.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: + SecuritySettingsServiceAsyncClient: The constructed client. + """ + return SecuritySettingsServiceClient.from_service_account_info.__func__(SecuritySettingsServiceAsyncClient, 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: + SecuritySettingsServiceAsyncClient: The constructed client. + """ + return SecuritySettingsServiceClient.from_service_account_file.__func__(SecuritySettingsServiceAsyncClient, filename, *args, **kwargs) # type: ignore + from_service_account_json = from_service_account_file @property @@ -166,7 +195,7 @@ async def create_security_settings( r"""Create security settings in the specified location. Args: - request (:class:`~.gcdc_security_settings.CreateSecuritySettingsRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.CreateSecuritySettingsRequest`): The request object. The request message for [SecuritySettings.CreateSecuritySettings][]. parent (:class:`str`): @@ -174,12 +203,14 @@ async def create_security_settings( [SecuritySettings][google.cloud.dialogflow.cx.v3beta1.SecuritySettings] for. Format: ``projects//locations/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - security_settings (:class:`~.gcdc_security_settings.SecuritySettings`): + security_settings (:class:`google.cloud.dialogflowcx_v3beta1.types.SecuritySettings`): Required. The security settings to create. + This corresponds to the ``security_settings`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -191,7 +222,7 @@ async def create_security_settings( sent along with the request as metadata. Returns: - ~.gcdc_security_settings.SecuritySettings: + google.cloud.dialogflowcx_v3beta1.types.SecuritySettings: Represents the settings related to security issues, such as data redaction and data retention. It may take hours @@ -254,12 +285,13 @@ async def get_security_settings( The returned settings may be stale by up to 1 minute. Args: - request (:class:`~.security_settings.GetSecuritySettingsRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.GetSecuritySettingsRequest`): The request object. The request message for [SecuritySettingsService.GetSecuritySettings][google.cloud.dialogflow.cx.v3beta1.SecuritySettingsService.GetSecuritySettings]. name (:class:`str`): Required. Resource name of the settings. Format: ``projects//locations//securitySettings/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -271,7 +303,7 @@ async def get_security_settings( sent along with the request as metadata. Returns: - ~.security_settings.SecuritySettings: + google.cloud.dialogflowcx_v3beta1.types.SecuritySettings: Represents the settings related to security issues, such as data redaction and data retention. It may take hours @@ -332,19 +364,21 @@ async def update_security_settings( [SecuritySettings][google.cloud.dialogflow.cx.v3beta1.SecuritySettings]. Args: - request (:class:`~.gcdc_security_settings.UpdateSecuritySettingsRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.UpdateSecuritySettingsRequest`): The request object. The request message for [SecuritySettingsService.UpdateSecuritySettings][google.cloud.dialogflow.cx.v3beta1.SecuritySettingsService.UpdateSecuritySettings]. - security_settings (:class:`~.gcdc_security_settings.SecuritySettings`): + security_settings (:class:`google.cloud.dialogflowcx_v3beta1.types.SecuritySettings`): Required. [SecuritySettings] object that contains values for each of the fields to update. + This corresponds to the ``security_settings`` 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`): Required. The mask to control which fields get updated. If the mask is not present, all fields will be updated. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -356,7 +390,7 @@ async def update_security_settings( sent along with the request as metadata. Returns: - ~.gcdc_security_settings.SecuritySettings: + google.cloud.dialogflowcx_v3beta1.types.SecuritySettings: Represents the settings related to security issues, such as data redaction and data retention. It may take hours @@ -420,13 +454,14 @@ async def list_security_settings( specified location. Args: - request (:class:`~.security_settings.ListSecuritySettingsRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.ListSecuritySettingsRequest`): The request object. The request message for [SecuritySettings.ListSecuritySettings][]. parent (:class:`str`): Required. The location to list all security settings for. Format: ``projects//locations/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -438,7 +473,7 @@ async def list_security_settings( sent along with the request as metadata. Returns: - ~.pagers.ListSecuritySettingsAsyncPager: + google.cloud.dialogflowcx_v3beta1.services.security_settings_service.pagers.ListSecuritySettingsAsyncPager: The response message for [SecuritySettings.ListSecuritySettings][]. @@ -503,7 +538,7 @@ async def delete_security_settings( [SecuritySettings][google.cloud.dialogflow.cx.v3beta1.SecuritySettings]. Args: - request (:class:`~.security_settings.DeleteSecuritySettingsRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.DeleteSecuritySettingsRequest`): The request object. The request message for [SecuritySettings.DeleteSecuritySettings][]. name (:class:`str`): @@ -511,6 +546,7 @@ async def delete_security_settings( [SecuritySettings][google.cloud.dialogflow.cx.v3beta1.SecuritySettings] to delete. Format: ``projects//locations//securitySettings/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. diff --git a/google/cloud/dialogflowcx_v3beta1/services/security_settings_service/client.py b/google/cloud/dialogflowcx_v3beta1/services/security_settings_service/client.py index a425d7e7..e9cce02b 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/security_settings_service/client.py +++ b/google/cloud/dialogflowcx_v3beta1/services/security_settings_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: + SecuritySettingsServiceClient: 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. + SecuritySettingsServiceClient: The constructed client. """ credentials = service_account.Credentials.from_service_account_file(filename) kwargs["credentials"] = credentials @@ -238,10 +254,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, ~.SecuritySettingsServiceTransport]): The + transport (Union[str, SecuritySettingsServiceTransport]): 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 @@ -277,21 +293,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: @@ -334,7 +346,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, ) @@ -352,20 +364,22 @@ def create_security_settings( r"""Create security settings in the specified location. Args: - request (:class:`~.gcdc_security_settings.CreateSecuritySettingsRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.CreateSecuritySettingsRequest): The request object. The request message for [SecuritySettings.CreateSecuritySettings][]. - parent (:class:`str`): + parent (str): Required. The location to create an [SecuritySettings][google.cloud.dialogflow.cx.v3beta1.SecuritySettings] for. Format: ``projects//locations/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - security_settings (:class:`~.gcdc_security_settings.SecuritySettings`): + security_settings (google.cloud.dialogflowcx_v3beta1.types.SecuritySettings): Required. The security settings to create. + This corresponds to the ``security_settings`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -377,7 +391,7 @@ def create_security_settings( sent along with the request as metadata. Returns: - ~.gcdc_security_settings.SecuritySettings: + google.cloud.dialogflowcx_v3beta1.types.SecuritySettings: Represents the settings related to security issues, such as data redaction and data retention. It may take hours @@ -443,12 +457,13 @@ def get_security_settings( The returned settings may be stale by up to 1 minute. Args: - request (:class:`~.security_settings.GetSecuritySettingsRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.GetSecuritySettingsRequest): The request object. The request message for [SecuritySettingsService.GetSecuritySettings][google.cloud.dialogflow.cx.v3beta1.SecuritySettingsService.GetSecuritySettings]. - name (:class:`str`): + name (str): Required. Resource name of the settings. Format: ``projects//locations//securitySettings/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -460,7 +475,7 @@ def get_security_settings( sent along with the request as metadata. Returns: - ~.security_settings.SecuritySettings: + google.cloud.dialogflowcx_v3beta1.types.SecuritySettings: Represents the settings related to security issues, such as data redaction and data retention. It may take hours @@ -522,19 +537,21 @@ def update_security_settings( [SecuritySettings][google.cloud.dialogflow.cx.v3beta1.SecuritySettings]. Args: - request (:class:`~.gcdc_security_settings.UpdateSecuritySettingsRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.UpdateSecuritySettingsRequest): The request object. The request message for [SecuritySettingsService.UpdateSecuritySettings][google.cloud.dialogflow.cx.v3beta1.SecuritySettingsService.UpdateSecuritySettings]. - security_settings (:class:`~.gcdc_security_settings.SecuritySettings`): + security_settings (google.cloud.dialogflowcx_v3beta1.types.SecuritySettings): Required. [SecuritySettings] object that contains values for each of the fields to update. + This corresponds to the ``security_settings`` 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): Required. The mask to control which fields get updated. If the mask is not present, all fields will be updated. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -546,7 +563,7 @@ def update_security_settings( sent along with the request as metadata. Returns: - ~.gcdc_security_settings.SecuritySettings: + google.cloud.dialogflowcx_v3beta1.types.SecuritySettings: Represents the settings related to security issues, such as data redaction and data retention. It may take hours @@ -613,13 +630,14 @@ def list_security_settings( specified location. Args: - request (:class:`~.security_settings.ListSecuritySettingsRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.ListSecuritySettingsRequest): The request object. The request message for [SecuritySettings.ListSecuritySettings][]. - parent (:class:`str`): + parent (str): Required. The location to list all security settings for. Format: ``projects//locations/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -631,7 +649,7 @@ def list_security_settings( sent along with the request as metadata. Returns: - ~.pagers.ListSecuritySettingsPager: + google.cloud.dialogflowcx_v3beta1.services.security_settings_service.pagers.ListSecuritySettingsPager: The response message for [SecuritySettings.ListSecuritySettings][]. @@ -697,14 +715,15 @@ def delete_security_settings( [SecuritySettings][google.cloud.dialogflow.cx.v3beta1.SecuritySettings]. Args: - request (:class:`~.security_settings.DeleteSecuritySettingsRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.DeleteSecuritySettingsRequest): The request object. The request message for [SecuritySettings.DeleteSecuritySettings][]. - name (:class:`str`): + name (str): Required. The name of the [SecuritySettings][google.cloud.dialogflow.cx.v3beta1.SecuritySettings] to delete. Format: ``projects//locations//securitySettings/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. diff --git a/google/cloud/dialogflowcx_v3beta1/services/security_settings_service/pagers.py b/google/cloud/dialogflowcx_v3beta1/services/security_settings_service/pagers.py index c8de228c..ab825057 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/security_settings_service/pagers.py +++ b/google/cloud/dialogflowcx_v3beta1/services/security_settings_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.dialogflowcx_v3beta1.types import security_settings @@ -24,7 +33,7 @@ class ListSecuritySettingsPager: """A pager for iterating through ``list_security_settings`` requests. This class thinly wraps an initial - :class:`~.security_settings.ListSecuritySettingsResponse` object, and + :class:`google.cloud.dialogflowcx_v3beta1.types.ListSecuritySettingsResponse` object, and provides an ``__iter__`` method to iterate through its ``security_settings`` field. @@ -33,7 +42,7 @@ class ListSecuritySettingsPager: through the ``security_settings`` field on the corresponding responses. - All the usual :class:`~.security_settings.ListSecuritySettingsResponse` + All the usual :class:`google.cloud.dialogflowcx_v3beta1.types.ListSecuritySettingsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -51,9 +60,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.security_settings.ListSecuritySettingsRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.ListSecuritySettingsRequest): The initial request object. - response (:class:`~.security_settings.ListSecuritySettingsResponse`): + response (google.cloud.dialogflowcx_v3beta1.types.ListSecuritySettingsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -86,7 +95,7 @@ class ListSecuritySettingsAsyncPager: """A pager for iterating through ``list_security_settings`` requests. This class thinly wraps an initial - :class:`~.security_settings.ListSecuritySettingsResponse` object, and + :class:`google.cloud.dialogflowcx_v3beta1.types.ListSecuritySettingsResponse` object, and provides an ``__aiter__`` method to iterate through its ``security_settings`` field. @@ -95,7 +104,7 @@ class ListSecuritySettingsAsyncPager: through the ``security_settings`` field on the corresponding responses. - All the usual :class:`~.security_settings.ListSecuritySettingsResponse` + All the usual :class:`google.cloud.dialogflowcx_v3beta1.types.ListSecuritySettingsResponse` 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:`~.security_settings.ListSecuritySettingsRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.ListSecuritySettingsRequest): The initial request object. - response (:class:`~.security_settings.ListSecuritySettingsResponse`): + response (google.cloud.dialogflowcx_v3beta1.types.ListSecuritySettingsResponse): 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/dialogflowcx_v3beta1/services/security_settings_service/transports/grpc.py b/google/cloud/dialogflowcx_v3beta1/services/security_settings_service/transports/grpc.py index 3faaeb17..4e49c3e4 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/security_settings_service/transports/grpc.py +++ b/google/cloud/dialogflowcx_v3beta1/services/security_settings_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): @@ -107,6 +112,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -116,11 +126,6 @@ def __init__( 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 @@ -164,12 +169,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ diff --git a/google/cloud/dialogflowcx_v3beta1/services/security_settings_service/transports/grpc_asyncio.py b/google/cloud/dialogflowcx_v3beta1/services/security_settings_service/transports/grpc_asyncio.py index 921e1eec..f80dd918 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/security_settings_service/transports/grpc_asyncio.py +++ b/google/cloud/dialogflowcx_v3beta1/services/security_settings_service/transports/grpc_asyncio.py @@ -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,6 +137,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): @@ -152,6 +157,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -161,11 +171,6 @@ def __init__( 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 @@ -209,12 +214,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ diff --git a/google/cloud/dialogflowcx_v3beta1/services/session_entity_types/async_client.py b/google/cloud/dialogflowcx_v3beta1/services/session_entity_types/async_client.py index bcde3f15..0f0f9bff 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/session_entity_types/async_client.py +++ b/google/cloud/dialogflowcx_v3beta1/services/session_entity_types/async_client.py @@ -87,7 +87,36 @@ class SessionEntityTypesAsyncClient: SessionEntityTypesClient.parse_common_location_path ) - from_service_account_file = SessionEntityTypesClient.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: + SessionEntityTypesAsyncClient: The constructed client. + """ + return SessionEntityTypesClient.from_service_account_info.__func__(SessionEntityTypesAsyncClient, 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: + SessionEntityTypesAsyncClient: The constructed client. + """ + return SessionEntityTypesClient.from_service_account_file.__func__(SessionEntityTypesAsyncClient, filename, *args, **kwargs) # type: ignore + from_service_account_json = from_service_account_file @property @@ -165,7 +194,7 @@ async def list_session_entity_types( specified session. Args: - request (:class:`~.session_entity_type.ListSessionEntityTypesRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.ListSessionEntityTypesRequest`): The request object. The request message for [SessionEntityTypes.ListSessionEntityTypes][google.cloud.dialogflow.cx.v3beta1.SessionEntityTypes.ListSessionEntityTypes]. parent (:class:`str`): @@ -176,6 +205,7 @@ async def list_session_entity_types( ``projects//locations//agents//environments//sessions/``. If ``Environment ID`` is not specified, we assume default 'draft' environment. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -187,7 +217,7 @@ async def list_session_entity_types( sent along with the request as metadata. Returns: - ~.pagers.ListSessionEntityTypesAsyncPager: + google.cloud.dialogflowcx_v3beta1.services.session_entity_types.pagers.ListSessionEntityTypesAsyncPager: The response message for [SessionEntityTypes.ListSessionEntityTypes][google.cloud.dialogflow.cx.v3beta1.SessionEntityTypes.ListSessionEntityTypes]. @@ -251,7 +281,7 @@ async def get_session_entity_type( r"""Retrieves the specified session entity type. Args: - request (:class:`~.session_entity_type.GetSessionEntityTypeRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.GetSessionEntityTypeRequest`): The request object. The request message for [SessionEntityTypes.GetSessionEntityType][google.cloud.dialogflow.cx.v3beta1.SessionEntityTypes.GetSessionEntityType]. name (:class:`str`): @@ -261,6 +291,7 @@ async def get_session_entity_type( ``projects//locations//agents//environments//sessions//entityTypes/``. If ``Environment ID`` is not specified, we assume default 'draft' environment. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -272,24 +303,24 @@ async def get_session_entity_type( sent along with the request as metadata. Returns: - ~.session_entity_type.SessionEntityType: - Session entity types are referred to as **User** entity - types and are entities that are built for an individual - user such as favorites, preferences, playlists, and so - on. + google.cloud.dialogflowcx_v3beta1.types.SessionEntityType: + Session entity types are referred to as **User** entity types and are + entities that are built for an individual user such + as favorites, preferences, playlists, and so on. - You can redefine a session entity type at the session - level to extend or replace a [custom entity - type][google.cloud.dialogflow.cx.v3beta1.EntityType] at - the user session level (we refer to the entity types - defined at the agent level as "custom entity types"). + You can redefine a session entity type at the session + level to extend or replace a [custom entity + type][google.cloud.dialogflow.cx.v3beta1.EntityType] + at the user session level (we refer to the entity + types defined at the agent level as "custom entity + types"). - Note: session entity types apply to all queries, - regardless of the language. + Note: session entity types apply to all queries, + regardless of the language. - For more information about entity types, see the - `Dialogflow - documentation `__. + For more information about entity types, see the + [Dialogflow + documentation](\ https://cloud.google.com/dialogflow/docs/entities-overview). """ # Create or coerce a protobuf request object. @@ -345,7 +376,7 @@ async def create_session_entity_type( overrides the session entity type. Args: - request (:class:`~.gcdc_session_entity_type.CreateSessionEntityTypeRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.CreateSessionEntityTypeRequest`): The request object. The request message for [SessionEntityTypes.CreateSessionEntityType][google.cloud.dialogflow.cx.v3beta1.SessionEntityTypes.CreateSessionEntityType]. parent (:class:`str`): @@ -356,12 +387,14 @@ async def create_session_entity_type( ``projects//locations//agents//environments//sessions/``. If ``Environment ID`` is not specified, we assume default 'draft' environment. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - session_entity_type (:class:`~.gcdc_session_entity_type.SessionEntityType`): + session_entity_type (:class:`google.cloud.dialogflowcx_v3beta1.types.SessionEntityType`): Required. The session entity type to create. + This corresponds to the ``session_entity_type`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -373,24 +406,24 @@ async def create_session_entity_type( sent along with the request as metadata. Returns: - ~.gcdc_session_entity_type.SessionEntityType: - Session entity types are referred to as **User** entity - types and are entities that are built for an individual - user such as favorites, preferences, playlists, and so - on. + google.cloud.dialogflowcx_v3beta1.types.SessionEntityType: + Session entity types are referred to as **User** entity types and are + entities that are built for an individual user such + as favorites, preferences, playlists, and so on. - You can redefine a session entity type at the session - level to extend or replace a [custom entity - type][google.cloud.dialogflow.cx.v3beta1.EntityType] at - the user session level (we refer to the entity types - defined at the agent level as "custom entity types"). + You can redefine a session entity type at the session + level to extend or replace a [custom entity + type][google.cloud.dialogflow.cx.v3beta1.EntityType] + at the user session level (we refer to the entity + types defined at the agent level as "custom entity + types"). - Note: session entity types apply to all queries, - regardless of the language. + Note: session entity types apply to all queries, + regardless of the language. - For more information about entity types, see the - `Dialogflow - documentation `__. + For more information about entity types, see the + [Dialogflow + documentation](\ https://cloud.google.com/dialogflow/docs/entities-overview). """ # Create or coerce a protobuf request object. @@ -446,22 +479,24 @@ async def update_session_entity_type( r"""Updates the specified session entity type. Args: - request (:class:`~.gcdc_session_entity_type.UpdateSessionEntityTypeRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.UpdateSessionEntityTypeRequest`): The request object. The request message for [SessionEntityTypes.UpdateSessionEntityType][google.cloud.dialogflow.cx.v3beta1.SessionEntityTypes.UpdateSessionEntityType]. - session_entity_type (:class:`~.gcdc_session_entity_type.SessionEntityType`): + session_entity_type (:class:`google.cloud.dialogflowcx_v3beta1.types.SessionEntityType`): Required. The session entity type to update. Format: ``projects//locations//agents//sessions//entityTypes/`` or ``projects//locations//agents//environments//sessions//entityTypes/``. If ``Environment ID`` is not specified, we assume default 'draft' environment. + This corresponds to the ``session_entity_type`` 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`): The mask to control which fields get updated. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -473,24 +508,24 @@ async def update_session_entity_type( sent along with the request as metadata. Returns: - ~.gcdc_session_entity_type.SessionEntityType: - Session entity types are referred to as **User** entity - types and are entities that are built for an individual - user such as favorites, preferences, playlists, and so - on. + google.cloud.dialogflowcx_v3beta1.types.SessionEntityType: + Session entity types are referred to as **User** entity types and are + entities that are built for an individual user such + as favorites, preferences, playlists, and so on. - You can redefine a session entity type at the session - level to extend or replace a [custom entity - type][google.cloud.dialogflow.cx.v3beta1.EntityType] at - the user session level (we refer to the entity types - defined at the agent level as "custom entity types"). + You can redefine a session entity type at the session + level to extend or replace a [custom entity + type][google.cloud.dialogflow.cx.v3beta1.EntityType] + at the user session level (we refer to the entity + types defined at the agent level as "custom entity + types"). - Note: session entity types apply to all queries, - regardless of the language. + Note: session entity types apply to all queries, + regardless of the language. - For more information about entity types, see the - `Dialogflow - documentation `__. + For more information about entity types, see the + [Dialogflow + documentation](\ https://cloud.google.com/dialogflow/docs/entities-overview). """ # Create or coerce a protobuf request object. @@ -547,7 +582,7 @@ async def delete_session_entity_type( r"""Deletes the specified session entity type. Args: - request (:class:`~.session_entity_type.DeleteSessionEntityTypeRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.DeleteSessionEntityTypeRequest`): The request object. The request message for [SessionEntityTypes.DeleteSessionEntityType][google.cloud.dialogflow.cx.v3beta1.SessionEntityTypes.DeleteSessionEntityType]. name (:class:`str`): @@ -558,6 +593,7 @@ async def delete_session_entity_type( ``projects//locations//agents//environments//sessions//entityTypes/``. If ``Environment ID`` is not specified, we assume default 'draft' environment. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. diff --git a/google/cloud/dialogflowcx_v3beta1/services/session_entity_types/client.py b/google/cloud/dialogflowcx_v3beta1/services/session_entity_types/client.py index 3fe6e56d..499d4724 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/session_entity_types/client.py +++ b/google/cloud/dialogflowcx_v3beta1/services/session_entity_types/client.py @@ -119,6 +119,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: + SessionEntityTypesClient: 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 @@ -131,7 +147,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. + SessionEntityTypesClient: The constructed client. """ credentials = service_account.Credentials.from_service_account_file(filename) kwargs["credentials"] = credentials @@ -245,10 +261,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, ~.SessionEntityTypesTransport]): The + transport (Union[str, SessionEntityTypesTransport]): 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 @@ -284,21 +300,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: @@ -341,7 +353,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, ) @@ -359,10 +371,10 @@ def list_session_entity_types( specified session. Args: - request (:class:`~.session_entity_type.ListSessionEntityTypesRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.ListSessionEntityTypesRequest): The request object. The request message for [SessionEntityTypes.ListSessionEntityTypes][google.cloud.dialogflow.cx.v3beta1.SessionEntityTypes.ListSessionEntityTypes]. - parent (:class:`str`): + parent (str): Required. The session to list all session entity types from. Format: ``projects//locations//agents//sessions/`` @@ -370,6 +382,7 @@ def list_session_entity_types( ``projects//locations//agents//environments//sessions/``. If ``Environment ID`` is not specified, we assume default 'draft' environment. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -381,7 +394,7 @@ def list_session_entity_types( sent along with the request as metadata. Returns: - ~.pagers.ListSessionEntityTypesPager: + google.cloud.dialogflowcx_v3beta1.services.session_entity_types.pagers.ListSessionEntityTypesPager: The response message for [SessionEntityTypes.ListSessionEntityTypes][google.cloud.dialogflow.cx.v3beta1.SessionEntityTypes.ListSessionEntityTypes]. @@ -448,16 +461,17 @@ def get_session_entity_type( r"""Retrieves the specified session entity type. Args: - request (:class:`~.session_entity_type.GetSessionEntityTypeRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.GetSessionEntityTypeRequest): The request object. The request message for [SessionEntityTypes.GetSessionEntityType][google.cloud.dialogflow.cx.v3beta1.SessionEntityTypes.GetSessionEntityType]. - name (:class:`str`): + name (str): Required. The name of the session entity type. Format: ``projects//locations//agents//sessions//entityTypes/`` or ``projects//locations//agents//environments//sessions//entityTypes/``. If ``Environment ID`` is not specified, we assume default 'draft' environment. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -469,24 +483,24 @@ def get_session_entity_type( sent along with the request as metadata. Returns: - ~.session_entity_type.SessionEntityType: - Session entity types are referred to as **User** entity - types and are entities that are built for an individual - user such as favorites, preferences, playlists, and so - on. + google.cloud.dialogflowcx_v3beta1.types.SessionEntityType: + Session entity types are referred to as **User** entity types and are + entities that are built for an individual user such + as favorites, preferences, playlists, and so on. - You can redefine a session entity type at the session - level to extend or replace a [custom entity - type][google.cloud.dialogflow.cx.v3beta1.EntityType] at - the user session level (we refer to the entity types - defined at the agent level as "custom entity types"). + You can redefine a session entity type at the session + level to extend or replace a [custom entity + type][google.cloud.dialogflow.cx.v3beta1.EntityType] + at the user session level (we refer to the entity + types defined at the agent level as "custom entity + types"). - Note: session entity types apply to all queries, - regardless of the language. + Note: session entity types apply to all queries, + regardless of the language. - For more information about entity types, see the - `Dialogflow - documentation `__. + For more information about entity types, see the + [Dialogflow + documentation](\ https://cloud.google.com/dialogflow/docs/entities-overview). """ # Create or coerce a protobuf request object. @@ -543,10 +557,10 @@ def create_session_entity_type( overrides the session entity type. Args: - request (:class:`~.gcdc_session_entity_type.CreateSessionEntityTypeRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.CreateSessionEntityTypeRequest): The request object. The request message for [SessionEntityTypes.CreateSessionEntityType][google.cloud.dialogflow.cx.v3beta1.SessionEntityTypes.CreateSessionEntityType]. - parent (:class:`str`): + parent (str): Required. The session to create a session entity type for. Format: ``projects//locations//agents//sessions/`` @@ -554,12 +568,14 @@ def create_session_entity_type( ``projects//locations//agents//environments//sessions/``. If ``Environment ID`` is not specified, we assume default 'draft' environment. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - session_entity_type (:class:`~.gcdc_session_entity_type.SessionEntityType`): + session_entity_type (google.cloud.dialogflowcx_v3beta1.types.SessionEntityType): Required. The session entity type to create. + This corresponds to the ``session_entity_type`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -571,24 +587,24 @@ def create_session_entity_type( sent along with the request as metadata. Returns: - ~.gcdc_session_entity_type.SessionEntityType: - Session entity types are referred to as **User** entity - types and are entities that are built for an individual - user such as favorites, preferences, playlists, and so - on. + google.cloud.dialogflowcx_v3beta1.types.SessionEntityType: + Session entity types are referred to as **User** entity types and are + entities that are built for an individual user such + as favorites, preferences, playlists, and so on. - You can redefine a session entity type at the session - level to extend or replace a [custom entity - type][google.cloud.dialogflow.cx.v3beta1.EntityType] at - the user session level (we refer to the entity types - defined at the agent level as "custom entity types"). + You can redefine a session entity type at the session + level to extend or replace a [custom entity + type][google.cloud.dialogflow.cx.v3beta1.EntityType] + at the user session level (we refer to the entity + types defined at the agent level as "custom entity + types"). - Note: session entity types apply to all queries, - regardless of the language. + Note: session entity types apply to all queries, + regardless of the language. - For more information about entity types, see the - `Dialogflow - documentation `__. + For more information about entity types, see the + [Dialogflow + documentation](\ https://cloud.google.com/dialogflow/docs/entities-overview). """ # Create or coerce a protobuf request object. @@ -649,22 +665,24 @@ def update_session_entity_type( r"""Updates the specified session entity type. Args: - request (:class:`~.gcdc_session_entity_type.UpdateSessionEntityTypeRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.UpdateSessionEntityTypeRequest): The request object. The request message for [SessionEntityTypes.UpdateSessionEntityType][google.cloud.dialogflow.cx.v3beta1.SessionEntityTypes.UpdateSessionEntityType]. - session_entity_type (:class:`~.gcdc_session_entity_type.SessionEntityType`): + session_entity_type (google.cloud.dialogflowcx_v3beta1.types.SessionEntityType): Required. The session entity type to update. Format: ``projects//locations//agents//sessions//entityTypes/`` or ``projects//locations//agents//environments//sessions//entityTypes/``. If ``Environment ID`` is not specified, we assume default 'draft' environment. + This corresponds to the ``session_entity_type`` 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): The mask to control which fields get updated. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -676,24 +694,24 @@ def update_session_entity_type( sent along with the request as metadata. Returns: - ~.gcdc_session_entity_type.SessionEntityType: - Session entity types are referred to as **User** entity - types and are entities that are built for an individual - user such as favorites, preferences, playlists, and so - on. + google.cloud.dialogflowcx_v3beta1.types.SessionEntityType: + Session entity types are referred to as **User** entity types and are + entities that are built for an individual user such + as favorites, preferences, playlists, and so on. - You can redefine a session entity type at the session - level to extend or replace a [custom entity - type][google.cloud.dialogflow.cx.v3beta1.EntityType] at - the user session level (we refer to the entity types - defined at the agent level as "custom entity types"). + You can redefine a session entity type at the session + level to extend or replace a [custom entity + type][google.cloud.dialogflow.cx.v3beta1.EntityType] + at the user session level (we refer to the entity + types defined at the agent level as "custom entity + types"). - Note: session entity types apply to all queries, - regardless of the language. + Note: session entity types apply to all queries, + regardless of the language. - For more information about entity types, see the - `Dialogflow - documentation `__. + For more information about entity types, see the + [Dialogflow + documentation](\ https://cloud.google.com/dialogflow/docs/entities-overview). """ # Create or coerce a protobuf request object. @@ -755,10 +773,10 @@ def delete_session_entity_type( r"""Deletes the specified session entity type. Args: - request (:class:`~.session_entity_type.DeleteSessionEntityTypeRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.DeleteSessionEntityTypeRequest): The request object. The request message for [SessionEntityTypes.DeleteSessionEntityType][google.cloud.dialogflow.cx.v3beta1.SessionEntityTypes.DeleteSessionEntityType]. - name (:class:`str`): + name (str): Required. The name of the session entity type to delete. Format: ``projects//locations//agents//sessions//entityTypes/`` @@ -766,6 +784,7 @@ def delete_session_entity_type( ``projects//locations//agents//environments//sessions//entityTypes/``. If ``Environment ID`` is not specified, we assume default 'draft' environment. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. diff --git a/google/cloud/dialogflowcx_v3beta1/services/session_entity_types/pagers.py b/google/cloud/dialogflowcx_v3beta1/services/session_entity_types/pagers.py index 47afb8ca..d602f60b 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/session_entity_types/pagers.py +++ b/google/cloud/dialogflowcx_v3beta1/services/session_entity_types/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.dialogflowcx_v3beta1.types import session_entity_type @@ -24,7 +33,7 @@ class ListSessionEntityTypesPager: """A pager for iterating through ``list_session_entity_types`` requests. This class thinly wraps an initial - :class:`~.session_entity_type.ListSessionEntityTypesResponse` object, and + :class:`google.cloud.dialogflowcx_v3beta1.types.ListSessionEntityTypesResponse` object, and provides an ``__iter__`` method to iterate through its ``session_entity_types`` field. @@ -33,7 +42,7 @@ class ListSessionEntityTypesPager: through the ``session_entity_types`` field on the corresponding responses. - All the usual :class:`~.session_entity_type.ListSessionEntityTypesResponse` + All the usual :class:`google.cloud.dialogflowcx_v3beta1.types.ListSessionEntityTypesResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -51,9 +60,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.session_entity_type.ListSessionEntityTypesRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.ListSessionEntityTypesRequest): The initial request object. - response (:class:`~.session_entity_type.ListSessionEntityTypesResponse`): + response (google.cloud.dialogflowcx_v3beta1.types.ListSessionEntityTypesResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -86,7 +95,7 @@ class ListSessionEntityTypesAsyncPager: """A pager for iterating through ``list_session_entity_types`` requests. This class thinly wraps an initial - :class:`~.session_entity_type.ListSessionEntityTypesResponse` object, and + :class:`google.cloud.dialogflowcx_v3beta1.types.ListSessionEntityTypesResponse` object, and provides an ``__aiter__`` method to iterate through its ``session_entity_types`` field. @@ -95,7 +104,7 @@ class ListSessionEntityTypesAsyncPager: through the ``session_entity_types`` field on the corresponding responses. - All the usual :class:`~.session_entity_type.ListSessionEntityTypesResponse` + All the usual :class:`google.cloud.dialogflowcx_v3beta1.types.ListSessionEntityTypesResponse` 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:`~.session_entity_type.ListSessionEntityTypesRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.ListSessionEntityTypesRequest): The initial request object. - response (:class:`~.session_entity_type.ListSessionEntityTypesResponse`): + response (google.cloud.dialogflowcx_v3beta1.types.ListSessionEntityTypesResponse): 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/dialogflowcx_v3beta1/services/session_entity_types/transports/grpc.py b/google/cloud/dialogflowcx_v3beta1/services/session_entity_types/transports/grpc.py index a628cb1e..8ba8b9fd 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/session_entity_types/transports/grpc.py +++ b/google/cloud/dialogflowcx_v3beta1/services/session_entity_types/transports/grpc.py @@ -62,6 +62,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: @@ -92,6 +93,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): @@ -108,6 +113,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -117,11 +127,6 @@ def __init__( 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 @@ -165,12 +170,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ diff --git a/google/cloud/dialogflowcx_v3beta1/services/session_entity_types/transports/grpc_asyncio.py b/google/cloud/dialogflowcx_v3beta1/services/session_entity_types/transports/grpc_asyncio.py index d4b5ed89..07d07354 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/session_entity_types/transports/grpc_asyncio.py +++ b/google/cloud/dialogflowcx_v3beta1/services/session_entity_types/transports/grpc_asyncio.py @@ -106,6 +106,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: @@ -137,6 +138,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): @@ -153,6 +158,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -162,11 +172,6 @@ def __init__( 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 @@ -210,12 +215,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ diff --git a/google/cloud/dialogflowcx_v3beta1/services/sessions/async_client.py b/google/cloud/dialogflowcx_v3beta1/services/sessions/async_client.py index a32034c1..36786e90 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/sessions/async_client.py +++ b/google/cloud/dialogflowcx_v3beta1/services/sessions/async_client.py @@ -102,7 +102,36 @@ class SessionsAsyncClient: common_location_path = staticmethod(SessionsClient.common_location_path) parse_common_location_path = staticmethod(SessionsClient.parse_common_location_path) - from_service_account_file = SessionsClient.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: + SessionsAsyncClient: The constructed client. + """ + return SessionsClient.from_service_account_info.__func__(SessionsAsyncClient, 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: + SessionsAsyncClient: The constructed client. + """ + return SessionsClient.from_service_account_file.__func__(SessionsAsyncClient, filename, *args, **kwargs) # type: ignore + from_service_account_json = from_service_account_file @property @@ -184,7 +213,7 @@ async def detect_intent( environments `__. Args: - request (:class:`~.session.DetectIntentRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.DetectIntentRequest`): The request object. The request to detect user's intent. retry (google.api_core.retry.Retry): Designation of what errors, if any, @@ -194,7 +223,7 @@ async def detect_intent( sent along with the request as metadata. Returns: - ~.session.DetectIntentResponse: + google.cloud.dialogflowcx_v3beta1.types.DetectIntentResponse: The message returned from the DetectIntent method. @@ -247,7 +276,7 @@ def streaming_detect_intent( environments `__. Args: - requests (AsyncIterator[`~.session.StreamingDetectIntentRequest`]): + requests (AsyncIterator[`google.cloud.dialogflowcx_v3beta1.types.StreamingDetectIntentRequest`]): The request object AsyncIterator. The top-level message sent by the client to the [Sessions.StreamingDetectIntent][google.cloud.dialogflow.cx.v3beta1.Sessions.StreamingDetectIntent] @@ -289,20 +318,18 @@ def streaming_detect_intent( sent along with the request as metadata. Returns: - AsyncIterable[~.session.StreamingDetectIntentResponse]: + AsyncIterable[google.cloud.dialogflowcx_v3beta1.types.StreamingDetectIntentResponse]: The top-level message returned from the - ``StreamingDetectIntent`` method. - - Multiple response messages can be returned in order: + StreamingDetectIntent method. - 1. If the input was set to streaming audio, the first - one or more messages contain ``recognition_result``. - Each ``recognition_result`` represents a more - complete transcript of what the user said. The last - ``recognition_result`` has ``is_final`` set to - ``true``. + Multiple response messages can be returned in order: - 2. The last message contains ``detect_intent_response``. + 1. If the input was set to streaming audio, the first + one or more messages contain recognition_result. + Each recognition_result represents a more complete + transcript of what the user said. The last + recognition_result has is_final set to true. + 2. The last message contains detect_intent_response. """ @@ -332,7 +359,7 @@ async def match_intent( change the session status. Args: - request (:class:`~.session.MatchIntentRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.MatchIntentRequest`): The request object. Request of [MatchIntent][]. retry (google.api_core.retry.Retry): Designation of what errors, if any, @@ -342,7 +369,7 @@ async def match_intent( sent along with the request as metadata. Returns: - ~.session.MatchIntentResponse: + google.cloud.dialogflowcx_v3beta1.types.MatchIntentResponse: Response of [MatchIntent][]. """ # Create or coerce a protobuf request object. @@ -386,7 +413,7 @@ async def fulfill_intent( Otherwise, the behavior is undefined. Args: - request (:class:`~.session.FulfillIntentRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.FulfillIntentRequest`): The request object. Request of [FulfillIntent][] retry (google.api_core.retry.Retry): Designation of what errors, if any, @@ -396,7 +423,7 @@ async def fulfill_intent( sent along with the request as metadata. Returns: - ~.session.FulfillIntentResponse: + google.cloud.dialogflowcx_v3beta1.types.FulfillIntentResponse: Response of [FulfillIntent][] """ # Create or coerce a protobuf request object. diff --git a/google/cloud/dialogflowcx_v3beta1/services/sessions/client.py b/google/cloud/dialogflowcx_v3beta1/services/sessions/client.py index 86069279..cb983edb 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/sessions/client.py +++ b/google/cloud/dialogflowcx_v3beta1/services/sessions/client.py @@ -123,6 +123,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: + SessionsClient: 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 @@ -135,7 +151,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. + SessionsClient: The constructed client. """ credentials = service_account.Credentials.from_service_account_file(filename) kwargs["credentials"] = credentials @@ -371,10 +387,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, ~.SessionsTransport]): The + transport (Union[str, SessionsTransport]): 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 @@ -410,21 +426,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: @@ -467,7 +479,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, ) @@ -490,7 +502,7 @@ def detect_intent( environments `__. Args: - request (:class:`~.session.DetectIntentRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.DetectIntentRequest): The request object. The request to detect user's intent. retry (google.api_core.retry.Retry): Designation of what errors, if any, @@ -500,7 +512,7 @@ def detect_intent( sent along with the request as metadata. Returns: - ~.session.DetectIntentResponse: + google.cloud.dialogflowcx_v3beta1.types.DetectIntentResponse: The message returned from the DetectIntent method. @@ -548,7 +560,7 @@ def streaming_detect_intent( environments `__. Args: - requests (Iterator[`~.session.StreamingDetectIntentRequest`]): + requests (Iterator[google.cloud.dialogflowcx_v3beta1.types.StreamingDetectIntentRequest]): The request object iterator. The top-level message sent by the client to the [Sessions.StreamingDetectIntent][google.cloud.dialogflow.cx.v3beta1.Sessions.StreamingDetectIntent] @@ -590,20 +602,18 @@ def streaming_detect_intent( sent along with the request as metadata. Returns: - Iterable[~.session.StreamingDetectIntentResponse]: + Iterable[google.cloud.dialogflowcx_v3beta1.types.StreamingDetectIntentResponse]: The top-level message returned from the - ``StreamingDetectIntent`` method. - - Multiple response messages can be returned in order: + StreamingDetectIntent method. - 1. If the input was set to streaming audio, the first - one or more messages contain ``recognition_result``. - Each ``recognition_result`` represents a more - complete transcript of what the user said. The last - ``recognition_result`` has ``is_final`` set to - ``true``. + Multiple response messages can be returned in order: - 2. The last message contains ``detect_intent_response``. + 1. If the input was set to streaming audio, the first + one or more messages contain recognition_result. + Each recognition_result represents a more complete + transcript of what the user said. The last + recognition_result has is_final set to true. + 2. The last message contains detect_intent_response. """ @@ -629,7 +639,7 @@ def match_intent( change the session status. Args: - request (:class:`~.session.MatchIntentRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.MatchIntentRequest): The request object. Request of [MatchIntent][]. retry (google.api_core.retry.Retry): Designation of what errors, if any, @@ -639,7 +649,7 @@ def match_intent( sent along with the request as metadata. Returns: - ~.session.MatchIntentResponse: + google.cloud.dialogflowcx_v3beta1.types.MatchIntentResponse: Response of [MatchIntent][]. """ # Create or coerce a protobuf request object. @@ -684,7 +694,7 @@ def fulfill_intent( Otherwise, the behavior is undefined. Args: - request (:class:`~.session.FulfillIntentRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.FulfillIntentRequest): The request object. Request of [FulfillIntent][] retry (google.api_core.retry.Retry): Designation of what errors, if any, @@ -694,7 +704,7 @@ def fulfill_intent( sent along with the request as metadata. Returns: - ~.session.FulfillIntentResponse: + google.cloud.dialogflowcx_v3beta1.types.FulfillIntentResponse: Response of [FulfillIntent][] """ # Create or coerce a protobuf request object. diff --git a/google/cloud/dialogflowcx_v3beta1/services/sessions/transports/grpc.py b/google/cloud/dialogflowcx_v3beta1/services/sessions/transports/grpc.py index 6f8f0b17..91cd771e 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/sessions/transports/grpc.py +++ b/google/cloud/dialogflowcx_v3beta1/services/sessions/transports/grpc.py @@ -60,6 +60,7 @@ def __init__( api_mtls_endpoint: str = None, client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, quota_project_id: Optional[str] = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: @@ -90,6 +91,10 @@ def __init__( ``api_mtls_endpoint`` is None. ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials for grpc channel. It is ignored if ``channel`` is provided. + client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]): + A callback to provide client certificate bytes and private key bytes, + both in PEM format. It is used to configure mutual TLS channel. It is + ignored if ``channel`` or ``ssl_channel_credentials`` is provided. quota_project_id (Optional[str]): An optional project to use for billing and quota. client_info (google.api_core.gapic_v1.client_info.ClientInfo): @@ -106,6 +111,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -115,11 +125,6 @@ def __init__( 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 @@ -163,12 +168,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ diff --git a/google/cloud/dialogflowcx_v3beta1/services/sessions/transports/grpc_asyncio.py b/google/cloud/dialogflowcx_v3beta1/services/sessions/transports/grpc_asyncio.py index 38ce2091..99dcbcb2 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/sessions/transports/grpc_asyncio.py +++ b/google/cloud/dialogflowcx_v3beta1/services/sessions/transports/grpc_asyncio.py @@ -104,6 +104,7 @@ def __init__( api_mtls_endpoint: str = None, client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, quota_project_id=None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: @@ -135,6 +136,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): @@ -151,6 +156,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -160,11 +170,6 @@ def __init__( 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 @@ -208,12 +213,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ diff --git a/google/cloud/dialogflowcx_v3beta1/services/test_cases/__init__.py b/google/cloud/dialogflowcx_v3beta1/services/test_cases/__init__.py new file mode 100644 index 00000000..77517b44 --- /dev/null +++ b/google/cloud/dialogflowcx_v3beta1/services/test_cases/__init__.py @@ -0,0 +1,24 @@ +# -*- 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. +# + +from .client import TestCasesClient +from .async_client import TestCasesAsyncClient + +__all__ = ( + "TestCasesClient", + "TestCasesAsyncClient", +) diff --git a/google/cloud/dialogflowcx_v3beta1/services/test_cases/async_client.py b/google/cloud/dialogflowcx_v3beta1/services/test_cases/async_client.py new file mode 100644 index 00000000..fd2e5649 --- /dev/null +++ b/google/cloud/dialogflowcx_v3beta1/services/test_cases/async_client.py @@ -0,0 +1,984 @@ +# -*- 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. +# + +from collections import OrderedDict +import functools +import re +from typing import Dict, Sequence, Tuple, Type, Union +import pkg_resources + +import google.api_core.client_options as ClientOptions # type: ignore +from google.api_core import exceptions # type: ignore +from google.api_core import gapic_v1 # type: ignore +from google.api_core import retry as retries # type: ignore +from google.auth import credentials # type: ignore +from google.oauth2 import service_account # type: ignore + +from google.api_core import operation # type: ignore +from google.api_core import operation_async # type: ignore +from google.cloud.dialogflowcx_v3beta1.services.test_cases import pagers +from google.cloud.dialogflowcx_v3beta1.types import test_case +from google.cloud.dialogflowcx_v3beta1.types import test_case as gcdc_test_case +from google.protobuf import field_mask_pb2 as field_mask # type: ignore +from google.protobuf import timestamp_pb2 as timestamp # type: ignore + +from .transports.base import TestCasesTransport, DEFAULT_CLIENT_INFO +from .transports.grpc_asyncio import TestCasesGrpcAsyncIOTransport +from .client import TestCasesClient + + +class TestCasesAsyncClient: + """Service for managing [Test + Cases][google.cloud.dialogflow.cx.v3beta1.TestCase] and [Test Case + Results][google.cloud.dialogflow.cx.v3beta1.TestCaseResult]. + """ + + _client: TestCasesClient + + DEFAULT_ENDPOINT = TestCasesClient.DEFAULT_ENDPOINT + DEFAULT_MTLS_ENDPOINT = TestCasesClient.DEFAULT_MTLS_ENDPOINT + + agent_path = staticmethod(TestCasesClient.agent_path) + parse_agent_path = staticmethod(TestCasesClient.parse_agent_path) + entity_type_path = staticmethod(TestCasesClient.entity_type_path) + parse_entity_type_path = staticmethod(TestCasesClient.parse_entity_type_path) + environment_path = staticmethod(TestCasesClient.environment_path) + parse_environment_path = staticmethod(TestCasesClient.parse_environment_path) + flow_path = staticmethod(TestCasesClient.flow_path) + parse_flow_path = staticmethod(TestCasesClient.parse_flow_path) + intent_path = staticmethod(TestCasesClient.intent_path) + parse_intent_path = staticmethod(TestCasesClient.parse_intent_path) + page_path = staticmethod(TestCasesClient.page_path) + parse_page_path = staticmethod(TestCasesClient.parse_page_path) + test_case_path = staticmethod(TestCasesClient.test_case_path) + parse_test_case_path = staticmethod(TestCasesClient.parse_test_case_path) + test_case_result_path = staticmethod(TestCasesClient.test_case_result_path) + parse_test_case_result_path = staticmethod( + TestCasesClient.parse_test_case_result_path + ) + transition_route_group_path = staticmethod( + TestCasesClient.transition_route_group_path + ) + parse_transition_route_group_path = staticmethod( + TestCasesClient.parse_transition_route_group_path + ) + webhook_path = staticmethod(TestCasesClient.webhook_path) + parse_webhook_path = staticmethod(TestCasesClient.parse_webhook_path) + + common_billing_account_path = staticmethod( + TestCasesClient.common_billing_account_path + ) + parse_common_billing_account_path = staticmethod( + TestCasesClient.parse_common_billing_account_path + ) + + common_folder_path = staticmethod(TestCasesClient.common_folder_path) + parse_common_folder_path = staticmethod(TestCasesClient.parse_common_folder_path) + + common_organization_path = staticmethod(TestCasesClient.common_organization_path) + parse_common_organization_path = staticmethod( + TestCasesClient.parse_common_organization_path + ) + + common_project_path = staticmethod(TestCasesClient.common_project_path) + parse_common_project_path = staticmethod(TestCasesClient.parse_common_project_path) + + common_location_path = staticmethod(TestCasesClient.common_location_path) + parse_common_location_path = staticmethod( + TestCasesClient.parse_common_location_path + ) + + @classmethod + def from_service_account_info(cls, info: dict, *args, **kwargs): + """Creates an instance of this client using the provided credentials info. + + Args: + info (dict): The service account private key info. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + TestCasesAsyncClient: The constructed client. + """ + return TestCasesClient.from_service_account_info.__func__(TestCasesAsyncClient, 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: + TestCasesAsyncClient: The constructed client. + """ + return TestCasesClient.from_service_account_file.__func__(TestCasesAsyncClient, filename, *args, **kwargs) # type: ignore + + from_service_account_json = from_service_account_file + + @property + def transport(self) -> TestCasesTransport: + """Return the transport used by the client instance. + + Returns: + TestCasesTransport: The transport used by the client instance. + """ + return self._client.transport + + get_transport_class = functools.partial( + type(TestCasesClient).get_transport_class, type(TestCasesClient) + ) + + def __init__( + self, + *, + credentials: credentials.Credentials = None, + transport: Union[str, TestCasesTransport] = "grpc_asyncio", + client_options: ClientOptions = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + ) -> None: + """Instantiate the test cases client. + + Args: + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + transport (Union[str, ~.TestCasesTransport]): The + transport to use. If set to None, a transport is chosen + automatically. + client_options (ClientOptions): Custom options for the client. It + won't take effect if a ``transport`` instance is provided. + (1) The ``api_endpoint`` property can be used to override the + default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT + environment variable can also be used to override the endpoint: + "always" (always use the default mTLS endpoint), "never" (always + use the default regular endpoint) and "auto" (auto switch to the + default mTLS endpoint if client certificate is present, this is + the default value). However, the ``api_endpoint`` property takes + precedence if provided. + (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable + is "true", then the ``client_cert_source`` property can be used + to provide client certificate for mutual TLS transport. If + not provided, the default SSL client certificate will be used if + present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not + set, no client certificate will be used. + + Raises: + google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport + creation failed for any reason. + """ + + self._client = TestCasesClient( + credentials=credentials, + transport=transport, + client_options=client_options, + client_info=client_info, + ) + + async def list_test_cases( + self, + request: test_case.ListTestCasesRequest = None, + *, + parent: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListTestCasesAsyncPager: + r"""Fetches a list of test cases for a given agent. + + Args: + request (:class:`google.cloud.dialogflowcx_v3beta1.types.ListTestCasesRequest`): + The request object. The request message for + [TestCases.ListTestCases][google.cloud.dialogflow.cx.v3beta1.TestCases.ListTestCases]. + parent (:class:`str`): + Required. The agent to list all pages for. Format: + ``projects//locations//agents/``. + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.dialogflowcx_v3beta1.services.test_cases.pagers.ListTestCasesAsyncPager: + The response message for + [TestCases.ListTestCases][google.cloud.dialogflow.cx.v3beta1.TestCases.ListTestCases]. + + Iterating over this object will yield results and + resolve additional pages automatically. + + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([parent]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = test_case.ListTestCasesRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + + if parent is not None: + request.parent = parent + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.list_test_cases, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = await rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # This method is paged; wrap the response in a pager, which provides + # an `__aiter__` convenience method. + response = pagers.ListTestCasesAsyncPager( + method=rpc, request=request, response=response, metadata=metadata, + ) + + # Done; return the response. + return response + + async def batch_delete_test_cases( + self, + request: test_case.BatchDeleteTestCasesRequest = None, + *, + parent: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + r"""Batch deletes test cases. + + Args: + request (:class:`google.cloud.dialogflowcx_v3beta1.types.BatchDeleteTestCasesRequest`): + The request object. The request message for + [TestCases.BatchDeleteTestCases][google.cloud.dialogflow.cx.v3beta1.TestCases.BatchDeleteTestCases]. + parent (:class:`str`): + Required. The agent to delete test cases from. Format: + ``projects//locations//agents/``. + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([parent]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = test_case.BatchDeleteTestCasesRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + + if parent is not None: + request.parent = parent + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.batch_delete_test_cases, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + await rpc( + request, retry=retry, timeout=timeout, metadata=metadata, + ) + + async def get_test_case( + self, + request: test_case.GetTestCaseRequest = None, + *, + name: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> test_case.TestCase: + r"""Gets a test case. + + Args: + request (:class:`google.cloud.dialogflowcx_v3beta1.types.GetTestCaseRequest`): + The request object. The request message for + [TestCases.GetTestCase][google.cloud.dialogflow.cx.v3beta1.TestCases.GetTestCase]. + name (:class:`str`): + Required. The name of the testcase. Format: + ``projects//locations//agents//testCases/``. + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.dialogflowcx_v3beta1.types.TestCase: + Represents a test case. + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = test_case.GetTestCaseRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.get_test_case, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = await rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + + async def create_test_case( + self, + request: gcdc_test_case.CreateTestCaseRequest = None, + *, + parent: str = None, + test_case: gcdc_test_case.TestCase = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_test_case.TestCase: + r"""Creates a test case for the given agent. + + Args: + request (:class:`google.cloud.dialogflowcx_v3beta1.types.CreateTestCaseRequest`): + The request object. The request message for + [TestCases.CreateTestCase][google.cloud.dialogflow.cx.v3beta1.TestCases.CreateTestCase]. + parent (:class:`str`): + Required. The agent to create the test case for. Format: + ``projects//locations//agents/``. + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + test_case (:class:`google.cloud.dialogflowcx_v3beta1.types.TestCase`): + Required. The test case to create. + This corresponds to the ``test_case`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.dialogflowcx_v3beta1.types.TestCase: + Represents a test case. + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([parent, test_case]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = gcdc_test_case.CreateTestCaseRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + + if parent is not None: + request.parent = parent + if test_case is not None: + request.test_case = test_case + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.create_test_case, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = await rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + + async def update_test_case( + self, + request: gcdc_test_case.UpdateTestCaseRequest = None, + *, + test_case: gcdc_test_case.TestCase = None, + update_mask: field_mask.FieldMask = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_test_case.TestCase: + r"""Updates the specified test case. + + Args: + request (:class:`google.cloud.dialogflowcx_v3beta1.types.UpdateTestCaseRequest`): + The request object. The request message for + [TestCases.UpdateTestCase][google.cloud.dialogflow.cx.v3beta1.TestCases.UpdateTestCase]. + test_case (:class:`google.cloud.dialogflowcx_v3beta1.types.TestCase`): + Required. The test case to update. + This corresponds to the ``test_case`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + update_mask (:class:`google.protobuf.field_mask_pb2.FieldMask`): + Required. The mask to specify which fields should be + updated. The + [``creationTime``][google.cloud.dialogflow.cx.v3beta1.TestCase.creation_time] + and + [``lastTestResult``][google.cloud.dialogflow.cx.v3beta1.TestCase.last_test_result] + cannot be updated. + + This corresponds to the ``update_mask`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.dialogflowcx_v3beta1.types.TestCase: + Represents a test case. + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([test_case, update_mask]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = gcdc_test_case.UpdateTestCaseRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + + if test_case is not None: + request.test_case = test_case + if update_mask is not None: + request.update_mask = update_mask + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.update_test_case, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("test_case.name", request.test_case.name),) + ), + ) + + # Send the request. + response = await rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + + async def run_test_case( + self, + request: test_case.RunTestCaseRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operation_async.AsyncOperation: + r"""Kicks off a test case run. + + Args: + request (:class:`google.cloud.dialogflowcx_v3beta1.types.RunTestCaseRequest`): + The request object. The request message for + [TestCases.RunTestCase][google.cloud.dialogflow.cx.v3beta1.TestCases.RunTestCase]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.api_core.operation_async.AsyncOperation: + An object representing a long-running operation. + + The result type for the operation will be + :class:`google.cloud.dialogflowcx_v3beta1.types.RunTestCaseResponse` + The response message for + [TestCases.RunTestCase][google.cloud.dialogflow.cx.v3beta1.TestCases.RunTestCase]. + + """ + # Create or coerce a protobuf request object. + + request = test_case.RunTestCaseRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.run_test_case, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = await rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Wrap the response in an operation future. + response = operation_async.from_gapic( + response, + self._client._transport.operations_client, + test_case.RunTestCaseResponse, + metadata_type=test_case.RunTestCaseMetadata, + ) + + # Done; return the response. + return response + + async def batch_run_test_cases( + self, + request: test_case.BatchRunTestCasesRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operation_async.AsyncOperation: + r"""Kicks off a batch run of test cases. + + Args: + request (:class:`google.cloud.dialogflowcx_v3beta1.types.BatchRunTestCasesRequest`): + The request object. The request message for + [TestCases.BatchRunTestCases][google.cloud.dialogflow.cx.v3beta1.TestCases.BatchRunTestCases]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.api_core.operation_async.AsyncOperation: + An object representing a long-running operation. + + The result type for the operation will be + :class:`google.cloud.dialogflowcx_v3beta1.types.BatchRunTestCasesResponse` + The response message for + [TestCases.BatchRunTestCases][google.cloud.dialogflow.cx.v3beta1.TestCases.BatchRunTestCases]. + + """ + # Create or coerce a protobuf request object. + + request = test_case.BatchRunTestCasesRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.batch_run_test_cases, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = await rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Wrap the response in an operation future. + response = operation_async.from_gapic( + response, + self._client._transport.operations_client, + test_case.BatchRunTestCasesResponse, + metadata_type=test_case.BatchRunTestCasesMetadata, + ) + + # Done; return the response. + return response + + async def calculate_coverage( + self, + request: test_case.CalculateCoverageRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> test_case.CalculateCoverageResponse: + r"""Calculates the test coverage for an agent. + + Args: + request (:class:`google.cloud.dialogflowcx_v3beta1.types.CalculateCoverageRequest`): + The request object. The request message for + [TestCases.CalculateCoverage][google.cloud.dialogflow.cx.v3beta1.TestCases.CalculateCoverage]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.dialogflowcx_v3beta1.types.CalculateCoverageResponse: + The response message for + [TestCases.CalculateCoverage][google.cloud.dialogflow.cx.v3beta1.TestCases.CalculateCoverage]. + + """ + # Create or coerce a protobuf request object. + + request = test_case.CalculateCoverageRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.calculate_coverage, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("agent", request.agent),)), + ) + + # Send the request. + response = await rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + + async def import_test_cases( + self, + request: test_case.ImportTestCasesRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operation_async.AsyncOperation: + r"""Imports the test cases from a Cloud Storage bucket or + a local file. It always creates new test cases and won't + overwite any existing ones. The provided ID in the + imported test case is neglected. + + Args: + request (:class:`google.cloud.dialogflowcx_v3beta1.types.ImportTestCasesRequest`): + The request object. The request message for + [TestCases.ImportTestCases][google.cloud.dialogflow.cx.v3beta1.TestCases.ImportTestCases]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.api_core.operation_async.AsyncOperation: + An object representing a long-running operation. + + The result type for the operation will be + :class:`google.cloud.dialogflowcx_v3beta1.types.ImportTestCasesResponse` + The response message for + [TestCases.ImportTestCases][google.cloud.dialogflow.cx.v3beta1.TestCases.ImportTestCases]. + + """ + # Create or coerce a protobuf request object. + + request = test_case.ImportTestCasesRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.import_test_cases, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = await rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Wrap the response in an operation future. + response = operation_async.from_gapic( + response, + self._client._transport.operations_client, + test_case.ImportTestCasesResponse, + metadata_type=test_case.ImportTestCasesMetadata, + ) + + # Done; return the response. + return response + + async def export_test_cases( + self, + request: test_case.ExportTestCasesRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operation_async.AsyncOperation: + r"""Exports the test cases under the agent to a Cloud + Storage bucket or a local file. Filter can be applied to + export a subset of test cases. + + Args: + request (:class:`google.cloud.dialogflowcx_v3beta1.types.ExportTestCasesRequest`): + The request object. The request message for + [TestCases.ExportTestCases][google.cloud.dialogflow.cx.v3beta1.TestCases.ExportTestCases]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.api_core.operation_async.AsyncOperation: + An object representing a long-running operation. + + The result type for the operation will be + :class:`google.cloud.dialogflowcx_v3beta1.types.ExportTestCasesResponse` + The response message for + [TestCases.ExportTestCases][google.cloud.dialogflow.cx.v3beta1.TestCases.ExportTestCases]. + + """ + # Create or coerce a protobuf request object. + + request = test_case.ExportTestCasesRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.export_test_cases, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = await rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Wrap the response in an operation future. + response = operation_async.from_gapic( + response, + self._client._transport.operations_client, + test_case.ExportTestCasesResponse, + metadata_type=test_case.ExportTestCasesMetadata, + ) + + # Done; return the response. + return response + + async def list_test_case_results( + self, + request: test_case.ListTestCaseResultsRequest = None, + *, + parent: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListTestCaseResultsAsyncPager: + r"""Fetches a list of results for a given test case. + + Args: + request (:class:`google.cloud.dialogflowcx_v3beta1.types.ListTestCaseResultsRequest`): + The request object. The request message for + [TestCases.ListTestCaseResults][google.cloud.dialogflow.cx.v3beta1.TestCases.ListTestCaseResults]. + parent (:class:`str`): + Required. The test case to list results for. Format: + ``projects//locations//agents// testCases/``. + Specify a ``-`` as a wildcard for TestCase ID to list + results across multiple test cases. + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.dialogflowcx_v3beta1.services.test_cases.pagers.ListTestCaseResultsAsyncPager: + The response message for + [TestCases.ListTestCaseResults][google.cloud.dialogflow.cx.v3beta1.TestCases.ListTestCaseResults]. + + Iterating over this object will yield results and + resolve additional pages automatically. + + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([parent]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = test_case.ListTestCaseResultsRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + + if parent is not None: + request.parent = parent + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.list_test_case_results, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = await rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # This method is paged; wrap the response in a pager, which provides + # an `__aiter__` convenience method. + response = pagers.ListTestCaseResultsAsyncPager( + method=rpc, request=request, response=response, metadata=metadata, + ) + + # Done; return the response. + return response + + +try: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=pkg_resources.get_distribution( + "google-cloud-dialogflowcx", + ).version, + ) +except pkg_resources.DistributionNotFound: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() + + +__all__ = ("TestCasesAsyncClient",) diff --git a/google/cloud/dialogflowcx_v3beta1/services/test_cases/client.py b/google/cloud/dialogflowcx_v3beta1/services/test_cases/client.py new file mode 100644 index 00000000..638793ed --- /dev/null +++ b/google/cloud/dialogflowcx_v3beta1/services/test_cases/client.py @@ -0,0 +1,1311 @@ +# -*- 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. +# + +from collections import OrderedDict +from distutils import util +import os +import re +from typing import Callable, Dict, Optional, Sequence, Tuple, Type, Union +import pkg_resources + +from google.api_core import client_options as client_options_lib # type: ignore +from google.api_core import exceptions # type: ignore +from google.api_core import gapic_v1 # type: ignore +from google.api_core import retry as retries # type: ignore +from google.auth import credentials # type: ignore +from google.auth.transport import mtls # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth.exceptions import MutualTLSChannelError # type: ignore +from google.oauth2 import service_account # type: ignore + +from google.api_core import operation # type: ignore +from google.api_core import operation_async # type: ignore +from google.cloud.dialogflowcx_v3beta1.services.test_cases import pagers +from google.cloud.dialogflowcx_v3beta1.types import test_case +from google.cloud.dialogflowcx_v3beta1.types import test_case as gcdc_test_case +from google.protobuf import field_mask_pb2 as field_mask # type: ignore +from google.protobuf import timestamp_pb2 as timestamp # type: ignore + +from .transports.base import TestCasesTransport, DEFAULT_CLIENT_INFO +from .transports.grpc import TestCasesGrpcTransport +from .transports.grpc_asyncio import TestCasesGrpcAsyncIOTransport + + +class TestCasesClientMeta(type): + """Metaclass for the TestCases client. + + This provides class-level methods for building and retrieving + support objects (e.g. transport) without polluting the client instance + objects. + """ + + _transport_registry = OrderedDict() # type: Dict[str, Type[TestCasesTransport]] + _transport_registry["grpc"] = TestCasesGrpcTransport + _transport_registry["grpc_asyncio"] = TestCasesGrpcAsyncIOTransport + + def get_transport_class(cls, label: str = None,) -> Type[TestCasesTransport]: + """Return an appropriate transport class. + + Args: + label: The name of the desired transport. If none is + provided, then the first transport in the registry is used. + + Returns: + The transport class to use. + """ + # If a specific transport is requested, return that one. + if label: + return cls._transport_registry[label] + + # No transport is requested; return the default (that is, the first one + # in the dictionary). + return next(iter(cls._transport_registry.values())) + + +class TestCasesClient(metaclass=TestCasesClientMeta): + """Service for managing [Test + Cases][google.cloud.dialogflow.cx.v3beta1.TestCase] and [Test Case + Results][google.cloud.dialogflow.cx.v3beta1.TestCaseResult]. + """ + + @staticmethod + def _get_default_mtls_endpoint(api_endpoint): + """Convert api endpoint to mTLS endpoint. + Convert "*.sandbox.googleapis.com" and "*.googleapis.com" to + "*.mtls.sandbox.googleapis.com" and "*.mtls.googleapis.com" respectively. + Args: + api_endpoint (Optional[str]): the api endpoint to convert. + Returns: + str: converted mTLS api endpoint. + """ + if not api_endpoint: + return api_endpoint + + mtls_endpoint_re = re.compile( + r"(?P[^.]+)(?P\.mtls)?(?P\.sandbox)?(?P\.googleapis\.com)?" + ) + + m = mtls_endpoint_re.match(api_endpoint) + name, mtls, sandbox, googledomain = m.groups() + if mtls or not googledomain: + return api_endpoint + + if sandbox: + return api_endpoint.replace( + "sandbox.googleapis.com", "mtls.sandbox.googleapis.com" + ) + + return api_endpoint.replace(".googleapis.com", ".mtls.googleapis.com") + + DEFAULT_ENDPOINT = "dialogflow.googleapis.com" + DEFAULT_MTLS_ENDPOINT = _get_default_mtls_endpoint.__func__( # type: ignore + DEFAULT_ENDPOINT + ) + + @classmethod + def from_service_account_info(cls, info: dict, *args, **kwargs): + """Creates an instance of this client using the provided credentials info. + + Args: + info (dict): The service account private key info. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + TestCasesClient: The constructed client. + """ + credentials = service_account.Credentials.from_service_account_info(info) + kwargs["credentials"] = credentials + return cls(*args, **kwargs) + + @classmethod + def from_service_account_file(cls, filename: str, *args, **kwargs): + """Creates an instance of this client using the provided credentials + file. + + Args: + filename (str): The path to the service account private key json + file. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + TestCasesClient: The constructed client. + """ + credentials = service_account.Credentials.from_service_account_file(filename) + kwargs["credentials"] = credentials + return cls(*args, **kwargs) + + from_service_account_json = from_service_account_file + + @property + def transport(self) -> TestCasesTransport: + """Return the transport used by the client instance. + + Returns: + TestCasesTransport: The transport used by the client instance. + """ + return self._transport + + @staticmethod + def agent_path(project: str, location: str, agent: str,) -> str: + """Return a fully-qualified agent string.""" + return "projects/{project}/locations/{location}/agents/{agent}".format( + project=project, location=location, agent=agent, + ) + + @staticmethod + def parse_agent_path(path: str) -> Dict[str, str]: + """Parse a agent path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/locations/(?P.+?)/agents/(?P.+?)$", + path, + ) + return m.groupdict() if m else {} + + @staticmethod + def entity_type_path( + project: str, location: str, agent: str, entity_type: str, + ) -> str: + """Return a fully-qualified entity_type string.""" + return "projects/{project}/locations/{location}/agents/{agent}/entityTypes/{entity_type}".format( + project=project, location=location, agent=agent, entity_type=entity_type, + ) + + @staticmethod + def parse_entity_type_path(path: str) -> Dict[str, str]: + """Parse a entity_type path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/locations/(?P.+?)/agents/(?P.+?)/entityTypes/(?P.+?)$", + path, + ) + return m.groupdict() if m else {} + + @staticmethod + def environment_path( + project: str, location: str, agent: str, environment: str, + ) -> str: + """Return a fully-qualified environment string.""" + return "projects/{project}/locations/{location}/agents/{agent}/environments/{environment}".format( + project=project, location=location, agent=agent, environment=environment, + ) + + @staticmethod + def parse_environment_path(path: str) -> Dict[str, str]: + """Parse a environment path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/locations/(?P.+?)/agents/(?P.+?)/environments/(?P.+?)$", + path, + ) + return m.groupdict() if m else {} + + @staticmethod + def flow_path(project: str, location: str, agent: str, flow: str,) -> str: + """Return a fully-qualified flow string.""" + return "projects/{project}/locations/{location}/agents/{agent}/flows/{flow}".format( + project=project, location=location, agent=agent, flow=flow, + ) + + @staticmethod + def parse_flow_path(path: str) -> Dict[str, str]: + """Parse a flow path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/locations/(?P.+?)/agents/(?P.+?)/flows/(?P.+?)$", + path, + ) + return m.groupdict() if m else {} + + @staticmethod + def intent_path(project: str, location: str, agent: str, intent: str,) -> str: + """Return a fully-qualified intent string.""" + return "projects/{project}/locations/{location}/agents/{agent}/intents/{intent}".format( + project=project, location=location, agent=agent, intent=intent, + ) + + @staticmethod + def parse_intent_path(path: str) -> Dict[str, str]: + """Parse a intent path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/locations/(?P.+?)/agents/(?P.+?)/intents/(?P.+?)$", + path, + ) + return m.groupdict() if m else {} + + @staticmethod + def page_path( + project: str, location: str, agent: str, flow: str, page: str, + ) -> str: + """Return a fully-qualified page string.""" + return "projects/{project}/locations/{location}/agents/{agent}/flows/{flow}/pages/{page}".format( + project=project, location=location, agent=agent, flow=flow, page=page, + ) + + @staticmethod + def parse_page_path(path: str) -> Dict[str, str]: + """Parse a page path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/locations/(?P.+?)/agents/(?P.+?)/flows/(?P.+?)/pages/(?P.+?)$", + path, + ) + return m.groupdict() if m else {} + + @staticmethod + def test_case_path(project: str, location: str, agent: str, test_case: str,) -> str: + """Return a fully-qualified test_case string.""" + return "projects/{project}/locations/{location}/agents/{agent}/testCases/{test_case}".format( + project=project, location=location, agent=agent, test_case=test_case, + ) + + @staticmethod + def parse_test_case_path(path: str) -> Dict[str, str]: + """Parse a test_case path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/locations/(?P.+?)/agents/(?P.+?)/testCases/(?P.+?)$", + path, + ) + return m.groupdict() if m else {} + + @staticmethod + def test_case_result_path( + project: str, location: str, agent: str, test_case: str, result: str, + ) -> str: + """Return a fully-qualified test_case_result string.""" + return "projects/{project}/locations/{location}/agents/{agent}/testCases/{test_case}/results/{result}".format( + project=project, + location=location, + agent=agent, + test_case=test_case, + result=result, + ) + + @staticmethod + def parse_test_case_result_path(path: str) -> Dict[str, str]: + """Parse a test_case_result path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/locations/(?P.+?)/agents/(?P.+?)/testCases/(?P.+?)/results/(?P.+?)$", + path, + ) + return m.groupdict() if m else {} + + @staticmethod + def transition_route_group_path( + project: str, location: str, agent: str, flow: str, transition_route_group: str, + ) -> str: + """Return a fully-qualified transition_route_group string.""" + return "projects/{project}/locations/{location}/agents/{agent}/flows/{flow}/transitionRouteGroups/{transition_route_group}".format( + project=project, + location=location, + agent=agent, + flow=flow, + transition_route_group=transition_route_group, + ) + + @staticmethod + def parse_transition_route_group_path(path: str) -> Dict[str, str]: + """Parse a transition_route_group path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/locations/(?P.+?)/agents/(?P.+?)/flows/(?P.+?)/transitionRouteGroups/(?P.+?)$", + path, + ) + return m.groupdict() if m else {} + + @staticmethod + def webhook_path(project: str, location: str, agent: str, webhook: str,) -> str: + """Return a fully-qualified webhook string.""" + return "projects/{project}/locations/{location}/agents/{agent}/webhooks/{webhook}".format( + project=project, location=location, agent=agent, webhook=webhook, + ) + + @staticmethod + def parse_webhook_path(path: str) -> Dict[str, str]: + """Parse a webhook path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/locations/(?P.+?)/agents/(?P.+?)/webhooks/(?P.+?)$", + path, + ) + return m.groupdict() if m else {} + + @staticmethod + def common_billing_account_path(billing_account: str,) -> str: + """Return a fully-qualified billing_account string.""" + return "billingAccounts/{billing_account}".format( + billing_account=billing_account, + ) + + @staticmethod + def parse_common_billing_account_path(path: str) -> Dict[str, str]: + """Parse a billing_account path into its component segments.""" + m = re.match(r"^billingAccounts/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_folder_path(folder: str,) -> str: + """Return a fully-qualified folder string.""" + return "folders/{folder}".format(folder=folder,) + + @staticmethod + def parse_common_folder_path(path: str) -> Dict[str, str]: + """Parse a folder path into its component segments.""" + m = re.match(r"^folders/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_organization_path(organization: str,) -> str: + """Return a fully-qualified organization string.""" + return "organizations/{organization}".format(organization=organization,) + + @staticmethod + def parse_common_organization_path(path: str) -> Dict[str, str]: + """Parse a organization path into its component segments.""" + m = re.match(r"^organizations/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_project_path(project: str,) -> str: + """Return a fully-qualified project string.""" + return "projects/{project}".format(project=project,) + + @staticmethod + def parse_common_project_path(path: str) -> Dict[str, str]: + """Parse a project path into its component segments.""" + m = re.match(r"^projects/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_location_path(project: str, location: str,) -> str: + """Return a fully-qualified location string.""" + return "projects/{project}/locations/{location}".format( + project=project, location=location, + ) + + @staticmethod + def parse_common_location_path(path: str) -> Dict[str, str]: + """Parse a location path into its component segments.""" + m = re.match(r"^projects/(?P.+?)/locations/(?P.+?)$", path) + return m.groupdict() if m else {} + + def __init__( + self, + *, + credentials: Optional[credentials.Credentials] = None, + transport: Union[str, TestCasesTransport, None] = None, + client_options: Optional[client_options_lib.ClientOptions] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + ) -> None: + """Instantiate the test cases client. + + Args: + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + transport (Union[str, TestCasesTransport]): The + transport to use. If set to None, a transport is chosen + automatically. + client_options (google.api_core.client_options.ClientOptions): Custom options for the + client. It won't take effect if a ``transport`` instance is provided. + (1) The ``api_endpoint`` property can be used to override the + default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT + environment variable can also be used to override the endpoint: + "always" (always use the default mTLS endpoint), "never" (always + use the default regular endpoint) and "auto" (auto switch to the + default mTLS endpoint if client certificate is present, this is + the default value). However, the ``api_endpoint`` property takes + precedence if provided. + (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable + is "true", then the ``client_cert_source`` property can be used + to provide client certificate for mutual TLS transport. If + not provided, the default SSL client certificate will be used if + present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not + set, no client certificate will be used. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport + creation failed for any reason. + """ + if isinstance(client_options, dict): + client_options = client_options_lib.from_dict(client_options) + if client_options is None: + client_options = client_options_lib.ClientOptions() + + # Create SSL credentials for mutual TLS if needed. + use_client_cert = bool( + util.strtobool(os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false")) + ) + + client_cert_source_func = None + is_mtls = False + if use_client_cert: + if client_options.client_cert_source: + is_mtls = True + client_cert_source_func = client_options.client_cert_source + else: + 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: + api_endpoint = client_options.api_endpoint + else: + use_mtls_env = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto") + if use_mtls_env == "never": + api_endpoint = self.DEFAULT_ENDPOINT + elif use_mtls_env == "always": + api_endpoint = self.DEFAULT_MTLS_ENDPOINT + elif use_mtls_env == "auto": + api_endpoint = ( + self.DEFAULT_MTLS_ENDPOINT if is_mtls else self.DEFAULT_ENDPOINT + ) + else: + raise MutualTLSChannelError( + "Unsupported GOOGLE_API_USE_MTLS_ENDPOINT value. Accepted values: never, auto, always" + ) + + # Save or instantiate the transport. + # Ordinarily, we provide the transport, but allowing a custom transport + # instance provides an extensibility point for unusual situations. + if isinstance(transport, TestCasesTransport): + # transport is a TestCasesTransport instance. + if credentials or client_options.credentials_file: + raise ValueError( + "When providing a transport instance, " + "provide its credentials directly." + ) + if client_options.scopes: + raise ValueError( + "When providing a transport instance, " + "provide its scopes directly." + ) + self._transport = transport + else: + Transport = type(self).get_transport_class(transport) + self._transport = Transport( + credentials=credentials, + credentials_file=client_options.credentials_file, + host=api_endpoint, + scopes=client_options.scopes, + client_cert_source_for_mtls=client_cert_source_func, + quota_project_id=client_options.quota_project_id, + client_info=client_info, + ) + + def list_test_cases( + self, + request: test_case.ListTestCasesRequest = None, + *, + parent: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListTestCasesPager: + r"""Fetches a list of test cases for a given agent. + + Args: + request (google.cloud.dialogflowcx_v3beta1.types.ListTestCasesRequest): + The request object. The request message for + [TestCases.ListTestCases][google.cloud.dialogflow.cx.v3beta1.TestCases.ListTestCases]. + parent (str): + Required. The agent to list all pages for. Format: + ``projects//locations//agents/``. + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.dialogflowcx_v3beta1.services.test_cases.pagers.ListTestCasesPager: + The response message for + [TestCases.ListTestCases][google.cloud.dialogflow.cx.v3beta1.TestCases.ListTestCases]. + + Iterating over this object will yield results and + resolve additional pages automatically. + + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([parent]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a test_case.ListTestCasesRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, test_case.ListTestCasesRequest): + request = test_case.ListTestCasesRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + + if parent is not None: + request.parent = parent + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.list_test_cases] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # This method is paged; wrap the response in a pager, which provides + # an `__iter__` convenience method. + response = pagers.ListTestCasesPager( + method=rpc, request=request, response=response, metadata=metadata, + ) + + # Done; return the response. + return response + + def batch_delete_test_cases( + self, + request: test_case.BatchDeleteTestCasesRequest = None, + *, + parent: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + r"""Batch deletes test cases. + + Args: + request (google.cloud.dialogflowcx_v3beta1.types.BatchDeleteTestCasesRequest): + The request object. The request message for + [TestCases.BatchDeleteTestCases][google.cloud.dialogflow.cx.v3beta1.TestCases.BatchDeleteTestCases]. + parent (str): + Required. The agent to delete test cases from. Format: + ``projects//locations//agents/``. + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([parent]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a test_case.BatchDeleteTestCasesRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, test_case.BatchDeleteTestCasesRequest): + request = test_case.BatchDeleteTestCasesRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + + if parent is not None: + request.parent = parent + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.batch_delete_test_cases] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + rpc( + request, retry=retry, timeout=timeout, metadata=metadata, + ) + + def get_test_case( + self, + request: test_case.GetTestCaseRequest = None, + *, + name: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> test_case.TestCase: + r"""Gets a test case. + + Args: + request (google.cloud.dialogflowcx_v3beta1.types.GetTestCaseRequest): + The request object. The request message for + [TestCases.GetTestCase][google.cloud.dialogflow.cx.v3beta1.TestCases.GetTestCase]. + name (str): + Required. The name of the testcase. Format: + ``projects//locations//agents//testCases/``. + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.dialogflowcx_v3beta1.types.TestCase: + Represents a test case. + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a test_case.GetTestCaseRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, test_case.GetTestCaseRequest): + request = test_case.GetTestCaseRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.get_test_case] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + + def create_test_case( + self, + request: gcdc_test_case.CreateTestCaseRequest = None, + *, + parent: str = None, + test_case: gcdc_test_case.TestCase = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_test_case.TestCase: + r"""Creates a test case for the given agent. + + Args: + request (google.cloud.dialogflowcx_v3beta1.types.CreateTestCaseRequest): + The request object. The request message for + [TestCases.CreateTestCase][google.cloud.dialogflow.cx.v3beta1.TestCases.CreateTestCase]. + parent (str): + Required. The agent to create the test case for. Format: + ``projects//locations//agents/``. + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + test_case (google.cloud.dialogflowcx_v3beta1.types.TestCase): + Required. The test case to create. + This corresponds to the ``test_case`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.dialogflowcx_v3beta1.types.TestCase: + Represents a test case. + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([parent, test_case]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a gcdc_test_case.CreateTestCaseRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, gcdc_test_case.CreateTestCaseRequest): + request = gcdc_test_case.CreateTestCaseRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + + if parent is not None: + request.parent = parent + if test_case is not None: + request.test_case = test_case + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.create_test_case] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + + def update_test_case( + self, + request: gcdc_test_case.UpdateTestCaseRequest = None, + *, + test_case: gcdc_test_case.TestCase = None, + update_mask: field_mask.FieldMask = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gcdc_test_case.TestCase: + r"""Updates the specified test case. + + Args: + request (google.cloud.dialogflowcx_v3beta1.types.UpdateTestCaseRequest): + The request object. The request message for + [TestCases.UpdateTestCase][google.cloud.dialogflow.cx.v3beta1.TestCases.UpdateTestCase]. + test_case (google.cloud.dialogflowcx_v3beta1.types.TestCase): + Required. The test case to update. + This corresponds to the ``test_case`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + update_mask (google.protobuf.field_mask_pb2.FieldMask): + Required. The mask to specify which fields should be + updated. The + [``creationTime``][google.cloud.dialogflow.cx.v3beta1.TestCase.creation_time] + and + [``lastTestResult``][google.cloud.dialogflow.cx.v3beta1.TestCase.last_test_result] + cannot be updated. + + This corresponds to the ``update_mask`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.dialogflowcx_v3beta1.types.TestCase: + Represents a test case. + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([test_case, update_mask]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a gcdc_test_case.UpdateTestCaseRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, gcdc_test_case.UpdateTestCaseRequest): + request = gcdc_test_case.UpdateTestCaseRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + + if test_case is not None: + request.test_case = test_case + if update_mask is not None: + request.update_mask = update_mask + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.update_test_case] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("test_case.name", request.test_case.name),) + ), + ) + + # Send the request. + response = rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + + def run_test_case( + self, + request: test_case.RunTestCaseRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operation.Operation: + r"""Kicks off a test case run. + + Args: + request (google.cloud.dialogflowcx_v3beta1.types.RunTestCaseRequest): + The request object. The request message for + [TestCases.RunTestCase][google.cloud.dialogflow.cx.v3beta1.TestCases.RunTestCase]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.api_core.operation.Operation: + An object representing a long-running operation. + + The result type for the operation will be + :class:`google.cloud.dialogflowcx_v3beta1.types.RunTestCaseResponse` + The response message for + [TestCases.RunTestCase][google.cloud.dialogflow.cx.v3beta1.TestCases.RunTestCase]. + + """ + # Create or coerce a protobuf request object. + + # Minor optimization to avoid making a copy if the user passes + # in a test_case.RunTestCaseRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, test_case.RunTestCaseRequest): + request = test_case.RunTestCaseRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.run_test_case] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Wrap the response in an operation future. + response = operation.from_gapic( + response, + self._transport.operations_client, + test_case.RunTestCaseResponse, + metadata_type=test_case.RunTestCaseMetadata, + ) + + # Done; return the response. + return response + + def batch_run_test_cases( + self, + request: test_case.BatchRunTestCasesRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operation.Operation: + r"""Kicks off a batch run of test cases. + + Args: + request (google.cloud.dialogflowcx_v3beta1.types.BatchRunTestCasesRequest): + The request object. The request message for + [TestCases.BatchRunTestCases][google.cloud.dialogflow.cx.v3beta1.TestCases.BatchRunTestCases]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.api_core.operation.Operation: + An object representing a long-running operation. + + The result type for the operation will be + :class:`google.cloud.dialogflowcx_v3beta1.types.BatchRunTestCasesResponse` + The response message for + [TestCases.BatchRunTestCases][google.cloud.dialogflow.cx.v3beta1.TestCases.BatchRunTestCases]. + + """ + # Create or coerce a protobuf request object. + + # Minor optimization to avoid making a copy if the user passes + # in a test_case.BatchRunTestCasesRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, test_case.BatchRunTestCasesRequest): + request = test_case.BatchRunTestCasesRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.batch_run_test_cases] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Wrap the response in an operation future. + response = operation.from_gapic( + response, + self._transport.operations_client, + test_case.BatchRunTestCasesResponse, + metadata_type=test_case.BatchRunTestCasesMetadata, + ) + + # Done; return the response. + return response + + def calculate_coverage( + self, + request: test_case.CalculateCoverageRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> test_case.CalculateCoverageResponse: + r"""Calculates the test coverage for an agent. + + Args: + request (google.cloud.dialogflowcx_v3beta1.types.CalculateCoverageRequest): + The request object. The request message for + [TestCases.CalculateCoverage][google.cloud.dialogflow.cx.v3beta1.TestCases.CalculateCoverage]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.dialogflowcx_v3beta1.types.CalculateCoverageResponse: + The response message for + [TestCases.CalculateCoverage][google.cloud.dialogflow.cx.v3beta1.TestCases.CalculateCoverage]. + + """ + # Create or coerce a protobuf request object. + + # Minor optimization to avoid making a copy if the user passes + # in a test_case.CalculateCoverageRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, test_case.CalculateCoverageRequest): + request = test_case.CalculateCoverageRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.calculate_coverage] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("agent", request.agent),)), + ) + + # Send the request. + response = rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Done; return the response. + return response + + def import_test_cases( + self, + request: test_case.ImportTestCasesRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operation.Operation: + r"""Imports the test cases from a Cloud Storage bucket or + a local file. It always creates new test cases and won't + overwite any existing ones. The provided ID in the + imported test case is neglected. + + Args: + request (google.cloud.dialogflowcx_v3beta1.types.ImportTestCasesRequest): + The request object. The request message for + [TestCases.ImportTestCases][google.cloud.dialogflow.cx.v3beta1.TestCases.ImportTestCases]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.api_core.operation.Operation: + An object representing a long-running operation. + + The result type for the operation will be + :class:`google.cloud.dialogflowcx_v3beta1.types.ImportTestCasesResponse` + The response message for + [TestCases.ImportTestCases][google.cloud.dialogflow.cx.v3beta1.TestCases.ImportTestCases]. + + """ + # Create or coerce a protobuf request object. + + # Minor optimization to avoid making a copy if the user passes + # in a test_case.ImportTestCasesRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, test_case.ImportTestCasesRequest): + request = test_case.ImportTestCasesRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.import_test_cases] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Wrap the response in an operation future. + response = operation.from_gapic( + response, + self._transport.operations_client, + test_case.ImportTestCasesResponse, + metadata_type=test_case.ImportTestCasesMetadata, + ) + + # Done; return the response. + return response + + def export_test_cases( + self, + request: test_case.ExportTestCasesRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operation.Operation: + r"""Exports the test cases under the agent to a Cloud + Storage bucket or a local file. Filter can be applied to + export a subset of test cases. + + Args: + request (google.cloud.dialogflowcx_v3beta1.types.ExportTestCasesRequest): + The request object. The request message for + [TestCases.ExportTestCases][google.cloud.dialogflow.cx.v3beta1.TestCases.ExportTestCases]. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.api_core.operation.Operation: + An object representing a long-running operation. + + The result type for the operation will be + :class:`google.cloud.dialogflowcx_v3beta1.types.ExportTestCasesResponse` + The response message for + [TestCases.ExportTestCases][google.cloud.dialogflow.cx.v3beta1.TestCases.ExportTestCases]. + + """ + # Create or coerce a protobuf request object. + + # Minor optimization to avoid making a copy if the user passes + # in a test_case.ExportTestCasesRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, test_case.ExportTestCasesRequest): + request = test_case.ExportTestCasesRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.export_test_cases] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # Wrap the response in an operation future. + response = operation.from_gapic( + response, + self._transport.operations_client, + test_case.ExportTestCasesResponse, + metadata_type=test_case.ExportTestCasesMetadata, + ) + + # Done; return the response. + return response + + def list_test_case_results( + self, + request: test_case.ListTestCaseResultsRequest = None, + *, + parent: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListTestCaseResultsPager: + r"""Fetches a list of results for a given test case. + + Args: + request (google.cloud.dialogflowcx_v3beta1.types.ListTestCaseResultsRequest): + The request object. The request message for + [TestCases.ListTestCaseResults][google.cloud.dialogflow.cx.v3beta1.TestCases.ListTestCaseResults]. + parent (str): + Required. The test case to list results for. Format: + ``projects//locations//agents// testCases/``. + Specify a ``-`` as a wildcard for TestCase ID to list + results across multiple test cases. + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.dialogflowcx_v3beta1.services.test_cases.pagers.ListTestCaseResultsPager: + The response message for + [TestCases.ListTestCaseResults][google.cloud.dialogflow.cx.v3beta1.TestCases.ListTestCaseResults]. + + Iterating over this object will yield results and + resolve additional pages automatically. + + """ + # Create or coerce a protobuf request object. + # Sanity check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([parent]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a test_case.ListTestCaseResultsRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, test_case.ListTestCaseResultsRequest): + request = test_case.ListTestCaseResultsRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + + if parent is not None: + request.parent = parent + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.list_test_case_results] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = rpc(request, retry=retry, timeout=timeout, metadata=metadata,) + + # This method is paged; wrap the response in a pager, which provides + # an `__iter__` convenience method. + response = pagers.ListTestCaseResultsPager( + method=rpc, request=request, response=response, metadata=metadata, + ) + + # Done; return the response. + return response + + +try: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=pkg_resources.get_distribution( + "google-cloud-dialogflowcx", + ).version, + ) +except pkg_resources.DistributionNotFound: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() + + +__all__ = ("TestCasesClient",) diff --git a/google/cloud/dialogflowcx_v3beta1/services/test_cases/pagers.py b/google/cloud/dialogflowcx_v3beta1/services/test_cases/pagers.py new file mode 100644 index 00000000..e16aa200 --- /dev/null +++ b/google/cloud/dialogflowcx_v3beta1/services/test_cases/pagers.py @@ -0,0 +1,285 @@ +# -*- 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. +# + +from typing import ( + Any, + AsyncIterable, + Awaitable, + Callable, + Iterable, + Sequence, + Tuple, + Optional, +) + +from google.cloud.dialogflowcx_v3beta1.types import test_case + + +class ListTestCasesPager: + """A pager for iterating through ``list_test_cases`` requests. + + This class thinly wraps an initial + :class:`google.cloud.dialogflowcx_v3beta1.types.ListTestCasesResponse` object, and + provides an ``__iter__`` method to iterate through its + ``test_cases`` field. + + If there are more pages, the ``__iter__`` method will make additional + ``ListTestCases`` requests and continue to iterate + through the ``test_cases`` field on the + corresponding responses. + + All the usual :class:`google.cloud.dialogflowcx_v3beta1.types.ListTestCasesResponse` + attributes are available on the pager. If multiple requests are made, only + the most recent response is retained, and thus used for attribute lookup. + """ + + def __init__( + self, + method: Callable[..., test_case.ListTestCasesResponse], + request: test_case.ListTestCasesRequest, + response: test_case.ListTestCasesResponse, + *, + metadata: Sequence[Tuple[str, str]] = () + ): + """Instantiate the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.cloud.dialogflowcx_v3beta1.types.ListTestCasesRequest): + The initial request object. + response (google.cloud.dialogflowcx_v3beta1.types.ListTestCasesResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = test_case.ListTestCasesRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + def pages(self) -> Iterable[test_case.ListTestCasesResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = self._method(self._request, metadata=self._metadata) + yield self._response + + def __iter__(self) -> Iterable[test_case.TestCase]: + for page in self.pages: + yield from page.test_cases + + def __repr__(self) -> str: + return "{0}<{1!r}>".format(self.__class__.__name__, self._response) + + +class ListTestCasesAsyncPager: + """A pager for iterating through ``list_test_cases`` requests. + + This class thinly wraps an initial + :class:`google.cloud.dialogflowcx_v3beta1.types.ListTestCasesResponse` object, and + provides an ``__aiter__`` method to iterate through its + ``test_cases`` field. + + If there are more pages, the ``__aiter__`` method will make additional + ``ListTestCases`` requests and continue to iterate + through the ``test_cases`` field on the + corresponding responses. + + All the usual :class:`google.cloud.dialogflowcx_v3beta1.types.ListTestCasesResponse` + attributes are available on the pager. If multiple requests are made, only + the most recent response is retained, and thus used for attribute lookup. + """ + + def __init__( + self, + method: Callable[..., Awaitable[test_case.ListTestCasesResponse]], + request: test_case.ListTestCasesRequest, + response: test_case.ListTestCasesResponse, + *, + metadata: Sequence[Tuple[str, str]] = () + ): + """Instantiate the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.cloud.dialogflowcx_v3beta1.types.ListTestCasesRequest): + The initial request object. + response (google.cloud.dialogflowcx_v3beta1.types.ListTestCasesResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = test_case.ListTestCasesRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + async def pages(self) -> AsyncIterable[test_case.ListTestCasesResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = await self._method(self._request, metadata=self._metadata) + yield self._response + + def __aiter__(self) -> AsyncIterable[test_case.TestCase]: + async def async_generator(): + async for page in self.pages: + for response in page.test_cases: + yield response + + return async_generator() + + def __repr__(self) -> str: + return "{0}<{1!r}>".format(self.__class__.__name__, self._response) + + +class ListTestCaseResultsPager: + """A pager for iterating through ``list_test_case_results`` requests. + + This class thinly wraps an initial + :class:`google.cloud.dialogflowcx_v3beta1.types.ListTestCaseResultsResponse` object, and + provides an ``__iter__`` method to iterate through its + ``test_case_results`` field. + + If there are more pages, the ``__iter__`` method will make additional + ``ListTestCaseResults`` requests and continue to iterate + through the ``test_case_results`` field on the + corresponding responses. + + All the usual :class:`google.cloud.dialogflowcx_v3beta1.types.ListTestCaseResultsResponse` + attributes are available on the pager. If multiple requests are made, only + the most recent response is retained, and thus used for attribute lookup. + """ + + def __init__( + self, + method: Callable[..., test_case.ListTestCaseResultsResponse], + request: test_case.ListTestCaseResultsRequest, + response: test_case.ListTestCaseResultsResponse, + *, + metadata: Sequence[Tuple[str, str]] = () + ): + """Instantiate the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.cloud.dialogflowcx_v3beta1.types.ListTestCaseResultsRequest): + The initial request object. + response (google.cloud.dialogflowcx_v3beta1.types.ListTestCaseResultsResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = test_case.ListTestCaseResultsRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + def pages(self) -> Iterable[test_case.ListTestCaseResultsResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = self._method(self._request, metadata=self._metadata) + yield self._response + + def __iter__(self) -> Iterable[test_case.TestCaseResult]: + for page in self.pages: + yield from page.test_case_results + + def __repr__(self) -> str: + return "{0}<{1!r}>".format(self.__class__.__name__, self._response) + + +class ListTestCaseResultsAsyncPager: + """A pager for iterating through ``list_test_case_results`` requests. + + This class thinly wraps an initial + :class:`google.cloud.dialogflowcx_v3beta1.types.ListTestCaseResultsResponse` object, and + provides an ``__aiter__`` method to iterate through its + ``test_case_results`` field. + + If there are more pages, the ``__aiter__`` method will make additional + ``ListTestCaseResults`` requests and continue to iterate + through the ``test_case_results`` field on the + corresponding responses. + + All the usual :class:`google.cloud.dialogflowcx_v3beta1.types.ListTestCaseResultsResponse` + attributes are available on the pager. If multiple requests are made, only + the most recent response is retained, and thus used for attribute lookup. + """ + + def __init__( + self, + method: Callable[..., Awaitable[test_case.ListTestCaseResultsResponse]], + request: test_case.ListTestCaseResultsRequest, + response: test_case.ListTestCaseResultsResponse, + *, + metadata: Sequence[Tuple[str, str]] = () + ): + """Instantiate the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.cloud.dialogflowcx_v3beta1.types.ListTestCaseResultsRequest): + The initial request object. + response (google.cloud.dialogflowcx_v3beta1.types.ListTestCaseResultsResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = test_case.ListTestCaseResultsRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + async def pages(self) -> AsyncIterable[test_case.ListTestCaseResultsResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = await self._method(self._request, metadata=self._metadata) + yield self._response + + def __aiter__(self) -> AsyncIterable[test_case.TestCaseResult]: + async def async_generator(): + async for page in self.pages: + for response in page.test_case_results: + yield response + + return async_generator() + + def __repr__(self) -> str: + return "{0}<{1!r}>".format(self.__class__.__name__, self._response) diff --git a/google/cloud/dialogflowcx_v3beta1/services/test_cases/transports/__init__.py b/google/cloud/dialogflowcx_v3beta1/services/test_cases/transports/__init__.py new file mode 100644 index 00000000..0c356952 --- /dev/null +++ b/google/cloud/dialogflowcx_v3beta1/services/test_cases/transports/__init__.py @@ -0,0 +1,35 @@ +# -*- 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. +# + +from collections import OrderedDict +from typing import Dict, Type + +from .base import TestCasesTransport +from .grpc import TestCasesGrpcTransport +from .grpc_asyncio import TestCasesGrpcAsyncIOTransport + + +# Compile a registry of transports. +_transport_registry = OrderedDict() # type: Dict[str, Type[TestCasesTransport]] +_transport_registry["grpc"] = TestCasesGrpcTransport +_transport_registry["grpc_asyncio"] = TestCasesGrpcAsyncIOTransport + +__all__ = ( + "TestCasesTransport", + "TestCasesGrpcTransport", + "TestCasesGrpcAsyncIOTransport", +) diff --git a/google/cloud/dialogflowcx_v3beta1/services/test_cases/transports/base.py b/google/cloud/dialogflowcx_v3beta1/services/test_cases/transports/base.py new file mode 100644 index 00000000..3628c659 --- /dev/null +++ b/google/cloud/dialogflowcx_v3beta1/services/test_cases/transports/base.py @@ -0,0 +1,275 @@ +# -*- 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. +# + +import abc +import typing +import pkg_resources + +from google import auth # type: ignore +from google.api_core import exceptions # type: ignore +from google.api_core import gapic_v1 # type: ignore +from google.api_core import retry as retries # type: ignore +from google.api_core import operations_v1 # type: ignore +from google.auth import credentials # type: ignore + +from google.cloud.dialogflowcx_v3beta1.types import test_case +from google.cloud.dialogflowcx_v3beta1.types import test_case as gcdc_test_case +from google.longrunning import operations_pb2 as operations # type: ignore +from google.protobuf import empty_pb2 as empty # type: ignore + + +try: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=pkg_resources.get_distribution( + "google-cloud-dialogflowcx", + ).version, + ) +except pkg_resources.DistributionNotFound: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() + + +class TestCasesTransport(abc.ABC): + """Abstract transport class for TestCases.""" + + AUTH_SCOPES = ( + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/dialogflow", + ) + + def __init__( + self, + *, + host: str = "dialogflow.googleapis.com", + credentials: credentials.Credentials = None, + credentials_file: typing.Optional[str] = None, + scopes: typing.Optional[typing.Sequence[str]] = AUTH_SCOPES, + quota_project_id: typing.Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + **kwargs, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is mutually exclusive with credentials. + 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 + your own client library. + """ + # Save the hostname. Default to port 443 (HTTPS) if none is specified. + if ":" not in host: + host += ":443" + self._host = host + + # If no credentials are provided, then determine the appropriate + # defaults. + if credentials and credentials_file: + raise exceptions.DuplicateCredentialArgs( + "'credentials_file' and 'credentials' are mutually exclusive" + ) + + if credentials_file is not None: + credentials, _ = auth.load_credentials_from_file( + credentials_file, scopes=scopes, quota_project_id=quota_project_id + ) + + elif credentials is None: + credentials, _ = auth.default( + scopes=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 = { + self.list_test_cases: gapic_v1.method.wrap_method( + self.list_test_cases, default_timeout=None, client_info=client_info, + ), + self.batch_delete_test_cases: gapic_v1.method.wrap_method( + self.batch_delete_test_cases, + default_timeout=None, + client_info=client_info, + ), + self.get_test_case: gapic_v1.method.wrap_method( + self.get_test_case, default_timeout=None, client_info=client_info, + ), + self.create_test_case: gapic_v1.method.wrap_method( + self.create_test_case, default_timeout=None, client_info=client_info, + ), + self.update_test_case: gapic_v1.method.wrap_method( + self.update_test_case, default_timeout=None, client_info=client_info, + ), + self.run_test_case: gapic_v1.method.wrap_method( + self.run_test_case, default_timeout=None, client_info=client_info, + ), + self.batch_run_test_cases: gapic_v1.method.wrap_method( + self.batch_run_test_cases, + default_timeout=None, + client_info=client_info, + ), + self.calculate_coverage: gapic_v1.method.wrap_method( + self.calculate_coverage, default_timeout=None, client_info=client_info, + ), + self.import_test_cases: gapic_v1.method.wrap_method( + self.import_test_cases, default_timeout=None, client_info=client_info, + ), + self.export_test_cases: gapic_v1.method.wrap_method( + self.export_test_cases, default_timeout=None, client_info=client_info, + ), + self.list_test_case_results: gapic_v1.method.wrap_method( + self.list_test_case_results, + default_timeout=None, + client_info=client_info, + ), + } + + @property + def operations_client(self) -> operations_v1.OperationsClient: + """Return the client designed to process long-running operations.""" + raise NotImplementedError() + + @property + def list_test_cases( + self, + ) -> typing.Callable[ + [test_case.ListTestCasesRequest], + typing.Union[ + test_case.ListTestCasesResponse, + typing.Awaitable[test_case.ListTestCasesResponse], + ], + ]: + raise NotImplementedError() + + @property + def batch_delete_test_cases( + self, + ) -> typing.Callable[ + [test_case.BatchDeleteTestCasesRequest], + typing.Union[empty.Empty, typing.Awaitable[empty.Empty]], + ]: + raise NotImplementedError() + + @property + def get_test_case( + self, + ) -> typing.Callable[ + [test_case.GetTestCaseRequest], + typing.Union[test_case.TestCase, typing.Awaitable[test_case.TestCase]], + ]: + raise NotImplementedError() + + @property + def create_test_case( + self, + ) -> typing.Callable[ + [gcdc_test_case.CreateTestCaseRequest], + typing.Union[ + gcdc_test_case.TestCase, typing.Awaitable[gcdc_test_case.TestCase] + ], + ]: + raise NotImplementedError() + + @property + def update_test_case( + self, + ) -> typing.Callable[ + [gcdc_test_case.UpdateTestCaseRequest], + typing.Union[ + gcdc_test_case.TestCase, typing.Awaitable[gcdc_test_case.TestCase] + ], + ]: + raise NotImplementedError() + + @property + def run_test_case( + self, + ) -> typing.Callable[ + [test_case.RunTestCaseRequest], + typing.Union[operations.Operation, typing.Awaitable[operations.Operation]], + ]: + raise NotImplementedError() + + @property + def batch_run_test_cases( + self, + ) -> typing.Callable[ + [test_case.BatchRunTestCasesRequest], + typing.Union[operations.Operation, typing.Awaitable[operations.Operation]], + ]: + raise NotImplementedError() + + @property + def calculate_coverage( + self, + ) -> typing.Callable[ + [test_case.CalculateCoverageRequest], + typing.Union[ + test_case.CalculateCoverageResponse, + typing.Awaitable[test_case.CalculateCoverageResponse], + ], + ]: + raise NotImplementedError() + + @property + def import_test_cases( + self, + ) -> typing.Callable[ + [test_case.ImportTestCasesRequest], + typing.Union[operations.Operation, typing.Awaitable[operations.Operation]], + ]: + raise NotImplementedError() + + @property + def export_test_cases( + self, + ) -> typing.Callable[ + [test_case.ExportTestCasesRequest], + typing.Union[operations.Operation, typing.Awaitable[operations.Operation]], + ]: + raise NotImplementedError() + + @property + def list_test_case_results( + self, + ) -> typing.Callable[ + [test_case.ListTestCaseResultsRequest], + typing.Union[ + test_case.ListTestCaseResultsResponse, + typing.Awaitable[test_case.ListTestCaseResultsResponse], + ], + ]: + raise NotImplementedError() + + +__all__ = ("TestCasesTransport",) diff --git a/google/cloud/dialogflowcx_v3beta1/services/test_cases/transports/grpc.py b/google/cloud/dialogflowcx_v3beta1/services/test_cases/transports/grpc.py new file mode 100644 index 00000000..0a25b5ad --- /dev/null +++ b/google/cloud/dialogflowcx_v3beta1/services/test_cases/transports/grpc.py @@ -0,0 +1,568 @@ +# -*- 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. +# + +import warnings +from typing import Callable, Dict, Optional, Sequence, Tuple + +from google.api_core import grpc_helpers # type: ignore +from google.api_core import operations_v1 # type: ignore +from google.api_core import gapic_v1 # type: ignore +from google import auth # type: ignore +from google.auth import credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore + +import grpc # type: ignore + +from google.cloud.dialogflowcx_v3beta1.types import test_case +from google.cloud.dialogflowcx_v3beta1.types import test_case as gcdc_test_case +from google.longrunning import operations_pb2 as operations # type: ignore +from google.protobuf import empty_pb2 as empty # type: ignore + +from .base import TestCasesTransport, DEFAULT_CLIENT_INFO + + +class TestCasesGrpcTransport(TestCasesTransport): + """gRPC backend transport for TestCases. + + Service for managing [Test + Cases][google.cloud.dialogflow.cx.v3beta1.TestCase] and [Test Case + Results][google.cloud.dialogflow.cx.v3beta1.TestCaseResult]. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends protocol buffers over the wire using gRPC (which is built on + top of HTTP/2); the ``grpcio`` package must be installed. + """ + + _stubs: Dict[str, Callable] + + def __init__( + self, + *, + host: str = "dialogflow.googleapis.com", + credentials: credentials.Credentials = None, + credentials_file: str = None, + scopes: Sequence[str] = None, + channel: grpc.Channel = None, + api_mtls_endpoint: str = None, + client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, + ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + This argument is ignored if ``channel`` is provided. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + channel (Optional[grpc.Channel]): A ``Channel`` instance through + which to make calls. + api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. + If provided, it overrides the ``host`` argument and tries to create + a mutual TLS channel with client SSL credentials from + ``client_cert_source`` or applicatin default SSL credentials. + client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): + Deprecated. A callback to provide client SSL certificate bytes and + private key bytes, both in PEM format. It is ignored if + ``api_mtls_endpoint`` is None. + ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials + for 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 + your own client library. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport + creation failed for any reason. + google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` + and ``credentials_file`` are passed. + """ + self._ssl_channel_credentials = ssl_channel_credentials + + 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. + credentials = False + + # If a channel was explicitly provided, set it. + self._grpc_channel = channel + self._ssl_channel_credentials = None + elif api_mtls_endpoint: + 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 + ) + + # 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 credentials is None: + credentials, _ = auth.default( + scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id + ) + + 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=self._ssl_channel_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._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, + ) + + @classmethod + def create_channel( + cls, + host: str = "dialogflow.googleapis.com", + credentials: credentials.Credentials = None, + credentials_file: str = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, + **kwargs, + ) -> grpc.Channel: + """Create and return a gRPC channel object. + Args: + address (Optional[str]): The host for the channel to use. + credentials (Optional[~.Credentials]): The + authorization credentials to attach to requests. These + credentials identify this application to the service. If + none are specified, the client will attempt to ascertain + the credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is mutually exclusive with credentials. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + kwargs (Optional[dict]): Keyword arguments, which are passed to the + channel creation. + Returns: + grpc.Channel: A gRPC channel object. + + Raises: + google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` + and ``credentials_file`` are passed. + """ + scopes = scopes or cls.AUTH_SCOPES + return grpc_helpers.create_channel( + host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + **kwargs, + ) + + @property + def grpc_channel(self) -> grpc.Channel: + """Return the channel designed to connect to this service. + """ + return self._grpc_channel + + @property + def operations_client(self) -> operations_v1.OperationsClient: + """Create the client designed to process long-running operations. + + This property caches on the instance; repeated calls return the same + client. + """ + # Sanity check: Only create a new client if we do not already have one. + if self._operations_client is None: + self._operations_client = operations_v1.OperationsClient(self.grpc_channel) + + # Return the client from cache. + return self._operations_client + + @property + def list_test_cases( + self, + ) -> Callable[[test_case.ListTestCasesRequest], test_case.ListTestCasesResponse]: + r"""Return a callable for the list test cases method over gRPC. + + Fetches a list of test cases for a given agent. + + Returns: + Callable[[~.ListTestCasesRequest], + ~.ListTestCasesResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_test_cases" not in self._stubs: + self._stubs["list_test_cases"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3beta1.TestCases/ListTestCases", + request_serializer=test_case.ListTestCasesRequest.serialize, + response_deserializer=test_case.ListTestCasesResponse.deserialize, + ) + return self._stubs["list_test_cases"] + + @property + def batch_delete_test_cases( + self, + ) -> Callable[[test_case.BatchDeleteTestCasesRequest], empty.Empty]: + r"""Return a callable for the batch delete test cases method over gRPC. + + Batch deletes test cases. + + Returns: + Callable[[~.BatchDeleteTestCasesRequest], + ~.Empty]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "batch_delete_test_cases" not in self._stubs: + self._stubs["batch_delete_test_cases"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3beta1.TestCases/BatchDeleteTestCases", + request_serializer=test_case.BatchDeleteTestCasesRequest.serialize, + response_deserializer=empty.Empty.FromString, + ) + return self._stubs["batch_delete_test_cases"] + + @property + def get_test_case( + self, + ) -> Callable[[test_case.GetTestCaseRequest], test_case.TestCase]: + r"""Return a callable for the get test case method over gRPC. + + Gets a test case. + + Returns: + Callable[[~.GetTestCaseRequest], + ~.TestCase]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_test_case" not in self._stubs: + self._stubs["get_test_case"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3beta1.TestCases/GetTestCase", + request_serializer=test_case.GetTestCaseRequest.serialize, + response_deserializer=test_case.TestCase.deserialize, + ) + return self._stubs["get_test_case"] + + @property + def create_test_case( + self, + ) -> Callable[[gcdc_test_case.CreateTestCaseRequest], gcdc_test_case.TestCase]: + r"""Return a callable for the create test case method over gRPC. + + Creates a test case for the given agent. + + Returns: + Callable[[~.CreateTestCaseRequest], + ~.TestCase]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "create_test_case" not in self._stubs: + self._stubs["create_test_case"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3beta1.TestCases/CreateTestCase", + request_serializer=gcdc_test_case.CreateTestCaseRequest.serialize, + response_deserializer=gcdc_test_case.TestCase.deserialize, + ) + return self._stubs["create_test_case"] + + @property + def update_test_case( + self, + ) -> Callable[[gcdc_test_case.UpdateTestCaseRequest], gcdc_test_case.TestCase]: + r"""Return a callable for the update test case method over gRPC. + + Updates the specified test case. + + Returns: + Callable[[~.UpdateTestCaseRequest], + ~.TestCase]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "update_test_case" not in self._stubs: + self._stubs["update_test_case"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3beta1.TestCases/UpdateTestCase", + request_serializer=gcdc_test_case.UpdateTestCaseRequest.serialize, + response_deserializer=gcdc_test_case.TestCase.deserialize, + ) + return self._stubs["update_test_case"] + + @property + def run_test_case( + self, + ) -> Callable[[test_case.RunTestCaseRequest], operations.Operation]: + r"""Return a callable for the run test case method over gRPC. + + Kicks off a test case run. + + Returns: + Callable[[~.RunTestCaseRequest], + ~.Operation]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "run_test_case" not in self._stubs: + self._stubs["run_test_case"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3beta1.TestCases/RunTestCase", + request_serializer=test_case.RunTestCaseRequest.serialize, + response_deserializer=operations.Operation.FromString, + ) + return self._stubs["run_test_case"] + + @property + def batch_run_test_cases( + self, + ) -> Callable[[test_case.BatchRunTestCasesRequest], operations.Operation]: + r"""Return a callable for the batch run test cases method over gRPC. + + Kicks off a batch run of test cases. + + Returns: + Callable[[~.BatchRunTestCasesRequest], + ~.Operation]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "batch_run_test_cases" not in self._stubs: + self._stubs["batch_run_test_cases"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3beta1.TestCases/BatchRunTestCases", + request_serializer=test_case.BatchRunTestCasesRequest.serialize, + response_deserializer=operations.Operation.FromString, + ) + return self._stubs["batch_run_test_cases"] + + @property + def calculate_coverage( + self, + ) -> Callable[ + [test_case.CalculateCoverageRequest], test_case.CalculateCoverageResponse + ]: + r"""Return a callable for the calculate coverage method over gRPC. + + Calculates the test coverage for an agent. + + Returns: + Callable[[~.CalculateCoverageRequest], + ~.CalculateCoverageResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "calculate_coverage" not in self._stubs: + self._stubs["calculate_coverage"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3beta1.TestCases/CalculateCoverage", + request_serializer=test_case.CalculateCoverageRequest.serialize, + response_deserializer=test_case.CalculateCoverageResponse.deserialize, + ) + return self._stubs["calculate_coverage"] + + @property + def import_test_cases( + self, + ) -> Callable[[test_case.ImportTestCasesRequest], operations.Operation]: + r"""Return a callable for the import test cases method over gRPC. + + Imports the test cases from a Cloud Storage bucket or + a local file. It always creates new test cases and won't + overwite any existing ones. The provided ID in the + imported test case is neglected. + + Returns: + Callable[[~.ImportTestCasesRequest], + ~.Operation]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "import_test_cases" not in self._stubs: + self._stubs["import_test_cases"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3beta1.TestCases/ImportTestCases", + request_serializer=test_case.ImportTestCasesRequest.serialize, + response_deserializer=operations.Operation.FromString, + ) + return self._stubs["import_test_cases"] + + @property + def export_test_cases( + self, + ) -> Callable[[test_case.ExportTestCasesRequest], operations.Operation]: + r"""Return a callable for the export test cases method over gRPC. + + Exports the test cases under the agent to a Cloud + Storage bucket or a local file. Filter can be applied to + export a subset of test cases. + + Returns: + Callable[[~.ExportTestCasesRequest], + ~.Operation]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "export_test_cases" not in self._stubs: + self._stubs["export_test_cases"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3beta1.TestCases/ExportTestCases", + request_serializer=test_case.ExportTestCasesRequest.serialize, + response_deserializer=operations.Operation.FromString, + ) + return self._stubs["export_test_cases"] + + @property + def list_test_case_results( + self, + ) -> Callable[ + [test_case.ListTestCaseResultsRequest], test_case.ListTestCaseResultsResponse + ]: + r"""Return a callable for the list test case results method over gRPC. + + Fetches a list of results for a given test case. + + Returns: + Callable[[~.ListTestCaseResultsRequest], + ~.ListTestCaseResultsResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_test_case_results" not in self._stubs: + self._stubs["list_test_case_results"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3beta1.TestCases/ListTestCaseResults", + request_serializer=test_case.ListTestCaseResultsRequest.serialize, + response_deserializer=test_case.ListTestCaseResultsResponse.deserialize, + ) + return self._stubs["list_test_case_results"] + + +__all__ = ("TestCasesGrpcTransport",) diff --git a/google/cloud/dialogflowcx_v3beta1/services/test_cases/transports/grpc_asyncio.py b/google/cloud/dialogflowcx_v3beta1/services/test_cases/transports/grpc_asyncio.py new file mode 100644 index 00000000..2b33fcea --- /dev/null +++ b/google/cloud/dialogflowcx_v3beta1/services/test_cases/transports/grpc_asyncio.py @@ -0,0 +1,584 @@ +# -*- 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. +# + +import warnings +from typing import Awaitable, Callable, Dict, Optional, Sequence, Tuple + +from google.api_core import gapic_v1 # type: ignore +from google.api_core import grpc_helpers_async # type: ignore +from google.api_core import operations_v1 # type: ignore +from google import auth # type: ignore +from google.auth import credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore + +import grpc # type: ignore +from grpc.experimental import aio # type: ignore + +from google.cloud.dialogflowcx_v3beta1.types import test_case +from google.cloud.dialogflowcx_v3beta1.types import test_case as gcdc_test_case +from google.longrunning import operations_pb2 as operations # type: ignore +from google.protobuf import empty_pb2 as empty # type: ignore + +from .base import TestCasesTransport, DEFAULT_CLIENT_INFO +from .grpc import TestCasesGrpcTransport + + +class TestCasesGrpcAsyncIOTransport(TestCasesTransport): + """gRPC AsyncIO backend transport for TestCases. + + Service for managing [Test + Cases][google.cloud.dialogflow.cx.v3beta1.TestCase] and [Test Case + Results][google.cloud.dialogflow.cx.v3beta1.TestCaseResult]. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends protocol buffers over the wire using gRPC (which is built on + top of HTTP/2); the ``grpcio`` package must be installed. + """ + + _grpc_channel: aio.Channel + _stubs: Dict[str, Callable] = {} + + @classmethod + def create_channel( + cls, + host: str = "dialogflow.googleapis.com", + credentials: credentials.Credentials = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, + **kwargs, + ) -> aio.Channel: + """Create and return a gRPC AsyncIO channel object. + Args: + address (Optional[str]): The host for the channel to use. + credentials (Optional[~.Credentials]): The + authorization credentials to attach to requests. These + credentials identify this application to the service. If + none are specified, the client will attempt to ascertain + the credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + kwargs (Optional[dict]): Keyword arguments, which are passed to the + channel creation. + Returns: + aio.Channel: A gRPC AsyncIO channel object. + """ + scopes = scopes or cls.AUTH_SCOPES + return grpc_helpers_async.create_channel( + host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + **kwargs, + ) + + def __init__( + self, + *, + host: str = "dialogflow.googleapis.com", + credentials: credentials.Credentials = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + channel: aio.Channel = None, + api_mtls_endpoint: str = None, + client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, + ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, + quota_project_id=None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + This argument is ignored if ``channel`` is provided. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + channel (Optional[aio.Channel]): A ``Channel`` instance through + which to make calls. + api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. + If provided, it overrides the ``host`` argument and tries to create + a mutual TLS channel with client SSL credentials from + ``client_cert_source`` or applicatin default SSL credentials. + client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): + Deprecated. A callback to provide client SSL certificate bytes and + private key bytes, both in PEM format. It is ignored if + ``api_mtls_endpoint`` is None. + ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials + for 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 + your own client library. + + Raises: + google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport + creation failed for any reason. + google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` + and ``credentials_file`` are passed. + """ + self._ssl_channel_credentials = ssl_channel_credentials + + 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. + credentials = False + + # If a channel was explicitly provided, set it. + self._grpc_channel = channel + self._ssl_channel_credentials = None + elif api_mtls_endpoint: + 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 + ) + + # 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 credentials is None: + credentials, _ = auth.default( + scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id + ) + + 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=self._ssl_channel_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), + ], + ) + + # 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 + + @property + def grpc_channel(self) -> aio.Channel: + """Create the channel designed to connect to this service. + + This property caches on the instance; repeated calls return + the same channel. + """ + # Return the channel from cache. + return self._grpc_channel + + @property + def operations_client(self) -> operations_v1.OperationsAsyncClient: + """Create the client designed to process long-running operations. + + This property caches on the instance; repeated calls return the same + client. + """ + # Sanity check: Only create a new client if we do not already have one. + if self._operations_client is None: + self._operations_client = operations_v1.OperationsAsyncClient( + self.grpc_channel + ) + + # Return the client from cache. + return self._operations_client + + @property + def list_test_cases( + self, + ) -> Callable[ + [test_case.ListTestCasesRequest], Awaitable[test_case.ListTestCasesResponse] + ]: + r"""Return a callable for the list test cases method over gRPC. + + Fetches a list of test cases for a given agent. + + Returns: + Callable[[~.ListTestCasesRequest], + Awaitable[~.ListTestCasesResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_test_cases" not in self._stubs: + self._stubs["list_test_cases"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3beta1.TestCases/ListTestCases", + request_serializer=test_case.ListTestCasesRequest.serialize, + response_deserializer=test_case.ListTestCasesResponse.deserialize, + ) + return self._stubs["list_test_cases"] + + @property + def batch_delete_test_cases( + self, + ) -> Callable[[test_case.BatchDeleteTestCasesRequest], Awaitable[empty.Empty]]: + r"""Return a callable for the batch delete test cases method over gRPC. + + Batch deletes test cases. + + Returns: + Callable[[~.BatchDeleteTestCasesRequest], + Awaitable[~.Empty]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "batch_delete_test_cases" not in self._stubs: + self._stubs["batch_delete_test_cases"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3beta1.TestCases/BatchDeleteTestCases", + request_serializer=test_case.BatchDeleteTestCasesRequest.serialize, + response_deserializer=empty.Empty.FromString, + ) + return self._stubs["batch_delete_test_cases"] + + @property + def get_test_case( + self, + ) -> Callable[[test_case.GetTestCaseRequest], Awaitable[test_case.TestCase]]: + r"""Return a callable for the get test case method over gRPC. + + Gets a test case. + + Returns: + Callable[[~.GetTestCaseRequest], + Awaitable[~.TestCase]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_test_case" not in self._stubs: + self._stubs["get_test_case"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3beta1.TestCases/GetTestCase", + request_serializer=test_case.GetTestCaseRequest.serialize, + response_deserializer=test_case.TestCase.deserialize, + ) + return self._stubs["get_test_case"] + + @property + def create_test_case( + self, + ) -> Callable[ + [gcdc_test_case.CreateTestCaseRequest], Awaitable[gcdc_test_case.TestCase] + ]: + r"""Return a callable for the create test case method over gRPC. + + Creates a test case for the given agent. + + Returns: + Callable[[~.CreateTestCaseRequest], + Awaitable[~.TestCase]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "create_test_case" not in self._stubs: + self._stubs["create_test_case"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3beta1.TestCases/CreateTestCase", + request_serializer=gcdc_test_case.CreateTestCaseRequest.serialize, + response_deserializer=gcdc_test_case.TestCase.deserialize, + ) + return self._stubs["create_test_case"] + + @property + def update_test_case( + self, + ) -> Callable[ + [gcdc_test_case.UpdateTestCaseRequest], Awaitable[gcdc_test_case.TestCase] + ]: + r"""Return a callable for the update test case method over gRPC. + + Updates the specified test case. + + Returns: + Callable[[~.UpdateTestCaseRequest], + Awaitable[~.TestCase]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "update_test_case" not in self._stubs: + self._stubs["update_test_case"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3beta1.TestCases/UpdateTestCase", + request_serializer=gcdc_test_case.UpdateTestCaseRequest.serialize, + response_deserializer=gcdc_test_case.TestCase.deserialize, + ) + return self._stubs["update_test_case"] + + @property + def run_test_case( + self, + ) -> Callable[[test_case.RunTestCaseRequest], Awaitable[operations.Operation]]: + r"""Return a callable for the run test case method over gRPC. + + Kicks off a test case run. + + Returns: + Callable[[~.RunTestCaseRequest], + Awaitable[~.Operation]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "run_test_case" not in self._stubs: + self._stubs["run_test_case"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3beta1.TestCases/RunTestCase", + request_serializer=test_case.RunTestCaseRequest.serialize, + response_deserializer=operations.Operation.FromString, + ) + return self._stubs["run_test_case"] + + @property + def batch_run_test_cases( + self, + ) -> Callable[ + [test_case.BatchRunTestCasesRequest], Awaitable[operations.Operation] + ]: + r"""Return a callable for the batch run test cases method over gRPC. + + Kicks off a batch run of test cases. + + Returns: + Callable[[~.BatchRunTestCasesRequest], + Awaitable[~.Operation]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "batch_run_test_cases" not in self._stubs: + self._stubs["batch_run_test_cases"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3beta1.TestCases/BatchRunTestCases", + request_serializer=test_case.BatchRunTestCasesRequest.serialize, + response_deserializer=operations.Operation.FromString, + ) + return self._stubs["batch_run_test_cases"] + + @property + def calculate_coverage( + self, + ) -> Callable[ + [test_case.CalculateCoverageRequest], + Awaitable[test_case.CalculateCoverageResponse], + ]: + r"""Return a callable for the calculate coverage method over gRPC. + + Calculates the test coverage for an agent. + + Returns: + Callable[[~.CalculateCoverageRequest], + Awaitable[~.CalculateCoverageResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "calculate_coverage" not in self._stubs: + self._stubs["calculate_coverage"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3beta1.TestCases/CalculateCoverage", + request_serializer=test_case.CalculateCoverageRequest.serialize, + response_deserializer=test_case.CalculateCoverageResponse.deserialize, + ) + return self._stubs["calculate_coverage"] + + @property + def import_test_cases( + self, + ) -> Callable[[test_case.ImportTestCasesRequest], Awaitable[operations.Operation]]: + r"""Return a callable for the import test cases method over gRPC. + + Imports the test cases from a Cloud Storage bucket or + a local file. It always creates new test cases and won't + overwite any existing ones. The provided ID in the + imported test case is neglected. + + Returns: + Callable[[~.ImportTestCasesRequest], + Awaitable[~.Operation]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "import_test_cases" not in self._stubs: + self._stubs["import_test_cases"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3beta1.TestCases/ImportTestCases", + request_serializer=test_case.ImportTestCasesRequest.serialize, + response_deserializer=operations.Operation.FromString, + ) + return self._stubs["import_test_cases"] + + @property + def export_test_cases( + self, + ) -> Callable[[test_case.ExportTestCasesRequest], Awaitable[operations.Operation]]: + r"""Return a callable for the export test cases method over gRPC. + + Exports the test cases under the agent to a Cloud + Storage bucket or a local file. Filter can be applied to + export a subset of test cases. + + Returns: + Callable[[~.ExportTestCasesRequest], + Awaitable[~.Operation]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "export_test_cases" not in self._stubs: + self._stubs["export_test_cases"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3beta1.TestCases/ExportTestCases", + request_serializer=test_case.ExportTestCasesRequest.serialize, + response_deserializer=operations.Operation.FromString, + ) + return self._stubs["export_test_cases"] + + @property + def list_test_case_results( + self, + ) -> Callable[ + [test_case.ListTestCaseResultsRequest], + Awaitable[test_case.ListTestCaseResultsResponse], + ]: + r"""Return a callable for the list test case results method over gRPC. + + Fetches a list of results for a given test case. + + Returns: + Callable[[~.ListTestCaseResultsRequest], + Awaitable[~.ListTestCaseResultsResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_test_case_results" not in self._stubs: + self._stubs["list_test_case_results"] = self.grpc_channel.unary_unary( + "/google.cloud.dialogflow.cx.v3beta1.TestCases/ListTestCaseResults", + request_serializer=test_case.ListTestCaseResultsRequest.serialize, + response_deserializer=test_case.ListTestCaseResultsResponse.deserialize, + ) + return self._stubs["list_test_case_results"] + + +__all__ = ("TestCasesGrpcAsyncIOTransport",) diff --git a/google/cloud/dialogflowcx_v3beta1/services/transition_route_groups/async_client.py b/google/cloud/dialogflowcx_v3beta1/services/transition_route_groups/async_client.py index ff955432..a10bed56 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/transition_route_groups/async_client.py +++ b/google/cloud/dialogflowcx_v3beta1/services/transition_route_groups/async_client.py @@ -97,7 +97,36 @@ class TransitionRouteGroupsAsyncClient: TransitionRouteGroupsClient.parse_common_location_path ) - from_service_account_file = TransitionRouteGroupsClient.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: + TransitionRouteGroupsAsyncClient: The constructed client. + """ + return TransitionRouteGroupsClient.from_service_account_info.__func__(TransitionRouteGroupsAsyncClient, 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: + TransitionRouteGroupsAsyncClient: The constructed client. + """ + return TransitionRouteGroupsClient.from_service_account_file.__func__(TransitionRouteGroupsAsyncClient, filename, *args, **kwargs) # type: ignore + from_service_account_json = from_service_account_file @property @@ -175,13 +204,14 @@ async def list_transition_route_groups( the specified flow. Args: - request (:class:`~.transition_route_group.ListTransitionRouteGroupsRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.ListTransitionRouteGroupsRequest`): The request object. The request message for [TransitionRouteGroups.ListTransitionRouteGroups][google.cloud.dialogflow.cx.v3beta1.TransitionRouteGroups.ListTransitionRouteGroups]. parent (:class:`str`): Required. The flow to list all transition route groups for. Format: ``projects//locations//agents//flows/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -193,7 +223,7 @@ async def list_transition_route_groups( sent along with the request as metadata. Returns: - ~.pagers.ListTransitionRouteGroupsAsyncPager: + google.cloud.dialogflowcx_v3beta1.services.transition_route_groups.pagers.ListTransitionRouteGroupsAsyncPager: The response message for [TransitionRouteGroups.ListTransitionRouteGroups][google.cloud.dialogflow.cx.v3beta1.TransitionRouteGroups.ListTransitionRouteGroups]. @@ -258,7 +288,7 @@ async def get_transition_route_group( [TransitionRouteGroup][google.cloud.dialogflow.cx.v3beta1.TransitionRouteGroup]. Args: - request (:class:`~.transition_route_group.GetTransitionRouteGroupRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.GetTransitionRouteGroupRequest`): The request object. The request message for [TransitionRouteGroups.GetTransitionRouteGroup][google.cloud.dialogflow.cx.v3beta1.TransitionRouteGroups.GetTransitionRouteGroup]. name (:class:`str`): @@ -266,6 +296,7 @@ async def get_transition_route_group( [TransitionRouteGroup][google.cloud.dialogflow.cx.v3beta1.TransitionRouteGroup]. Format: ``projects//locations//agents//flows//transitionRouteGroups/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -277,11 +308,11 @@ async def get_transition_route_group( sent along with the request as metadata. Returns: - ~.transition_route_group.TransitionRouteGroup: + google.cloud.dialogflowcx_v3beta1.types.TransitionRouteGroup: An TransitionRouteGroup represents a group of - [``TransitionRoutes``][google.cloud.dialogflow.cx.v3beta1.TransitionRoute] - to be used by a - [Page][google.cloud.dialogflow.cx.v3beta1.Page]. + [TransitionRoutes][google.cloud.dialogflow.cx.v3beta1.TransitionRoute] + to be used by a + [Page][google.cloud.dialogflow.cx.v3beta1.Page]. """ # Create or coerce a protobuf request object. @@ -337,7 +368,7 @@ async def create_transition_route_group( in the specified flow. Args: - request (:class:`~.gcdc_transition_route_group.CreateTransitionRouteGroupRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.CreateTransitionRouteGroupRequest`): The request object. The request message for [TransitionRouteGroups.CreateTransitionRouteGroup][google.cloud.dialogflow.cx.v3beta1.TransitionRouteGroups.CreateTransitionRouteGroup]. parent (:class:`str`): @@ -345,12 +376,14 @@ async def create_transition_route_group( [TransitionRouteGroup][google.cloud.dialogflow.cx.v3beta1.TransitionRouteGroup] for. Format: ``projects//locations//agents//flows/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - transition_route_group (:class:`~.gcdc_transition_route_group.TransitionRouteGroup`): + transition_route_group (:class:`google.cloud.dialogflowcx_v3beta1.types.TransitionRouteGroup`): Required. The transition route group to create. + This corresponds to the ``transition_route_group`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -362,11 +395,11 @@ async def create_transition_route_group( sent along with the request as metadata. Returns: - ~.gcdc_transition_route_group.TransitionRouteGroup: + google.cloud.dialogflowcx_v3beta1.types.TransitionRouteGroup: An TransitionRouteGroup represents a group of - [``TransitionRoutes``][google.cloud.dialogflow.cx.v3beta1.TransitionRoute] - to be used by a - [Page][google.cloud.dialogflow.cx.v3beta1.Page]. + [TransitionRoutes][google.cloud.dialogflow.cx.v3beta1.TransitionRoute] + to be used by a + [Page][google.cloud.dialogflow.cx.v3beta1.Page]. """ # Create or coerce a protobuf request object. @@ -423,18 +456,20 @@ async def update_transition_route_group( [TransitionRouteGroup][google.cloud.dialogflow.cx.v3beta1.TransitionRouteGroup]. Args: - request (:class:`~.gcdc_transition_route_group.UpdateTransitionRouteGroupRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.UpdateTransitionRouteGroupRequest`): The request object. The request message for [TransitionRouteGroups.UpdateTransitionRouteGroup][google.cloud.dialogflow.cx.v3beta1.TransitionRouteGroups.UpdateTransitionRouteGroup]. - transition_route_group (:class:`~.gcdc_transition_route_group.TransitionRouteGroup`): + transition_route_group (:class:`google.cloud.dialogflowcx_v3beta1.types.TransitionRouteGroup`): Required. The transition route group to update. + This corresponds to the ``transition_route_group`` 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`): The mask to control which fields get updated. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -446,11 +481,11 @@ async def update_transition_route_group( sent along with the request as metadata. Returns: - ~.gcdc_transition_route_group.TransitionRouteGroup: + google.cloud.dialogflowcx_v3beta1.types.TransitionRouteGroup: An TransitionRouteGroup represents a group of - [``TransitionRoutes``][google.cloud.dialogflow.cx.v3beta1.TransitionRoute] - to be used by a - [Page][google.cloud.dialogflow.cx.v3beta1.Page]. + [TransitionRoutes][google.cloud.dialogflow.cx.v3beta1.TransitionRoute] + to be used by a + [Page][google.cloud.dialogflow.cx.v3beta1.Page]. """ # Create or coerce a protobuf request object. @@ -508,7 +543,7 @@ async def delete_transition_route_group( [TransitionRouteGroup][google.cloud.dialogflow.cx.v3beta1.TransitionRouteGroup]. Args: - request (:class:`~.transition_route_group.DeleteTransitionRouteGroupRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.DeleteTransitionRouteGroupRequest`): The request object. The request message for [TransitionRouteGroups.DeleteTransitionRouteGroup][google.cloud.dialogflow.cx.v3beta1.TransitionRouteGroups.DeleteTransitionRouteGroup]. name (:class:`str`): @@ -516,6 +551,7 @@ async def delete_transition_route_group( [TransitionRouteGroup][google.cloud.dialogflow.cx.v3beta1.TransitionRouteGroup] to delete. Format: ``projects//locations//agents//flows//transitionRouteGroups/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. diff --git a/google/cloud/dialogflowcx_v3beta1/services/transition_route_groups/client.py b/google/cloud/dialogflowcx_v3beta1/services/transition_route_groups/client.py index 6594b050..ea13b5eb 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/transition_route_groups/client.py +++ b/google/cloud/dialogflowcx_v3beta1/services/transition_route_groups/client.py @@ -119,6 +119,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: + TransitionRouteGroupsClient: 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 @@ -131,7 +147,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. + TransitionRouteGroupsClient: The constructed client. """ credentials = service_account.Credentials.from_service_account_file(filename) kwargs["credentials"] = credentials @@ -311,10 +327,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, ~.TransitionRouteGroupsTransport]): The + transport (Union[str, TransitionRouteGroupsTransport]): 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 @@ -350,21 +366,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: @@ -407,7 +419,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, ) @@ -425,13 +437,14 @@ def list_transition_route_groups( the specified flow. Args: - request (:class:`~.transition_route_group.ListTransitionRouteGroupsRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.ListTransitionRouteGroupsRequest): The request object. The request message for [TransitionRouteGroups.ListTransitionRouteGroups][google.cloud.dialogflow.cx.v3beta1.TransitionRouteGroups.ListTransitionRouteGroups]. - parent (:class:`str`): + parent (str): Required. The flow to list all transition route groups for. Format: ``projects//locations//agents//flows/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -443,7 +456,7 @@ def list_transition_route_groups( sent along with the request as metadata. Returns: - ~.pagers.ListTransitionRouteGroupsPager: + google.cloud.dialogflowcx_v3beta1.services.transition_route_groups.pagers.ListTransitionRouteGroupsPager: The response message for [TransitionRouteGroups.ListTransitionRouteGroups][google.cloud.dialogflow.cx.v3beta1.TransitionRouteGroups.ListTransitionRouteGroups]. @@ -513,14 +526,15 @@ def get_transition_route_group( [TransitionRouteGroup][google.cloud.dialogflow.cx.v3beta1.TransitionRouteGroup]. Args: - request (:class:`~.transition_route_group.GetTransitionRouteGroupRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.GetTransitionRouteGroupRequest): The request object. The request message for [TransitionRouteGroups.GetTransitionRouteGroup][google.cloud.dialogflow.cx.v3beta1.TransitionRouteGroups.GetTransitionRouteGroup]. - name (:class:`str`): + name (str): Required. The name of the [TransitionRouteGroup][google.cloud.dialogflow.cx.v3beta1.TransitionRouteGroup]. Format: ``projects//locations//agents//flows//transitionRouteGroups/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -532,11 +546,11 @@ def get_transition_route_group( sent along with the request as metadata. Returns: - ~.transition_route_group.TransitionRouteGroup: + google.cloud.dialogflowcx_v3beta1.types.TransitionRouteGroup: An TransitionRouteGroup represents a group of - [``TransitionRoutes``][google.cloud.dialogflow.cx.v3beta1.TransitionRoute] - to be used by a - [Page][google.cloud.dialogflow.cx.v3beta1.Page]. + [TransitionRoutes][google.cloud.dialogflow.cx.v3beta1.TransitionRoute] + to be used by a + [Page][google.cloud.dialogflow.cx.v3beta1.Page]. """ # Create or coerce a protobuf request object. @@ -597,20 +611,22 @@ def create_transition_route_group( in the specified flow. Args: - request (:class:`~.gcdc_transition_route_group.CreateTransitionRouteGroupRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.CreateTransitionRouteGroupRequest): The request object. The request message for [TransitionRouteGroups.CreateTransitionRouteGroup][google.cloud.dialogflow.cx.v3beta1.TransitionRouteGroups.CreateTransitionRouteGroup]. - parent (:class:`str`): + parent (str): Required. The flow to create an [TransitionRouteGroup][google.cloud.dialogflow.cx.v3beta1.TransitionRouteGroup] for. Format: ``projects//locations//agents//flows/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - transition_route_group (:class:`~.gcdc_transition_route_group.TransitionRouteGroup`): + transition_route_group (google.cloud.dialogflowcx_v3beta1.types.TransitionRouteGroup): Required. The transition route group to create. + This corresponds to the ``transition_route_group`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -622,11 +638,11 @@ def create_transition_route_group( sent along with the request as metadata. Returns: - ~.gcdc_transition_route_group.TransitionRouteGroup: + google.cloud.dialogflowcx_v3beta1.types.TransitionRouteGroup: An TransitionRouteGroup represents a group of - [``TransitionRoutes``][google.cloud.dialogflow.cx.v3beta1.TransitionRoute] - to be used by a - [Page][google.cloud.dialogflow.cx.v3beta1.Page]. + [TransitionRoutes][google.cloud.dialogflow.cx.v3beta1.TransitionRoute] + to be used by a + [Page][google.cloud.dialogflow.cx.v3beta1.Page]. """ # Create or coerce a protobuf request object. @@ -690,18 +706,20 @@ def update_transition_route_group( [TransitionRouteGroup][google.cloud.dialogflow.cx.v3beta1.TransitionRouteGroup]. Args: - request (:class:`~.gcdc_transition_route_group.UpdateTransitionRouteGroupRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.UpdateTransitionRouteGroupRequest): The request object. The request message for [TransitionRouteGroups.UpdateTransitionRouteGroup][google.cloud.dialogflow.cx.v3beta1.TransitionRouteGroups.UpdateTransitionRouteGroup]. - transition_route_group (:class:`~.gcdc_transition_route_group.TransitionRouteGroup`): + transition_route_group (google.cloud.dialogflowcx_v3beta1.types.TransitionRouteGroup): Required. The transition route group to update. + This corresponds to the ``transition_route_group`` 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): The mask to control which fields get updated. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -713,11 +731,11 @@ def update_transition_route_group( sent along with the request as metadata. Returns: - ~.gcdc_transition_route_group.TransitionRouteGroup: + google.cloud.dialogflowcx_v3beta1.types.TransitionRouteGroup: An TransitionRouteGroup represents a group of - [``TransitionRoutes``][google.cloud.dialogflow.cx.v3beta1.TransitionRoute] - to be used by a - [Page][google.cloud.dialogflow.cx.v3beta1.Page]. + [TransitionRoutes][google.cloud.dialogflow.cx.v3beta1.TransitionRoute] + to be used by a + [Page][google.cloud.dialogflow.cx.v3beta1.Page]. """ # Create or coerce a protobuf request object. @@ -782,14 +800,15 @@ def delete_transition_route_group( [TransitionRouteGroup][google.cloud.dialogflow.cx.v3beta1.TransitionRouteGroup]. Args: - request (:class:`~.transition_route_group.DeleteTransitionRouteGroupRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.DeleteTransitionRouteGroupRequest): The request object. The request message for [TransitionRouteGroups.DeleteTransitionRouteGroup][google.cloud.dialogflow.cx.v3beta1.TransitionRouteGroups.DeleteTransitionRouteGroup]. - name (:class:`str`): + name (str): Required. The name of the [TransitionRouteGroup][google.cloud.dialogflow.cx.v3beta1.TransitionRouteGroup] to delete. Format: ``projects//locations//agents//flows//transitionRouteGroups/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. diff --git a/google/cloud/dialogflowcx_v3beta1/services/transition_route_groups/pagers.py b/google/cloud/dialogflowcx_v3beta1/services/transition_route_groups/pagers.py index b1911afc..384b0fab 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/transition_route_groups/pagers.py +++ b/google/cloud/dialogflowcx_v3beta1/services/transition_route_groups/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.dialogflowcx_v3beta1.types import transition_route_group @@ -24,7 +33,7 @@ class ListTransitionRouteGroupsPager: """A pager for iterating through ``list_transition_route_groups`` requests. This class thinly wraps an initial - :class:`~.transition_route_group.ListTransitionRouteGroupsResponse` object, and + :class:`google.cloud.dialogflowcx_v3beta1.types.ListTransitionRouteGroupsResponse` object, and provides an ``__iter__`` method to iterate through its ``transition_route_groups`` field. @@ -33,7 +42,7 @@ class ListTransitionRouteGroupsPager: through the ``transition_route_groups`` field on the corresponding responses. - All the usual :class:`~.transition_route_group.ListTransitionRouteGroupsResponse` + All the usual :class:`google.cloud.dialogflowcx_v3beta1.types.ListTransitionRouteGroupsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -51,9 +60,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.transition_route_group.ListTransitionRouteGroupsRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.ListTransitionRouteGroupsRequest): The initial request object. - response (:class:`~.transition_route_group.ListTransitionRouteGroupsResponse`): + response (google.cloud.dialogflowcx_v3beta1.types.ListTransitionRouteGroupsResponse): 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 ListTransitionRouteGroupsAsyncPager: """A pager for iterating through ``list_transition_route_groups`` requests. This class thinly wraps an initial - :class:`~.transition_route_group.ListTransitionRouteGroupsResponse` object, and + :class:`google.cloud.dialogflowcx_v3beta1.types.ListTransitionRouteGroupsResponse` object, and provides an ``__aiter__`` method to iterate through its ``transition_route_groups`` field. @@ -97,7 +106,7 @@ class ListTransitionRouteGroupsAsyncPager: through the ``transition_route_groups`` field on the corresponding responses. - All the usual :class:`~.transition_route_group.ListTransitionRouteGroupsResponse` + All the usual :class:`google.cloud.dialogflowcx_v3beta1.types.ListTransitionRouteGroupsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -117,9 +126,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.transition_route_group.ListTransitionRouteGroupsRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.ListTransitionRouteGroupsRequest): The initial request object. - response (:class:`~.transition_route_group.ListTransitionRouteGroupsResponse`): + response (google.cloud.dialogflowcx_v3beta1.types.ListTransitionRouteGroupsResponse): 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/dialogflowcx_v3beta1/services/transition_route_groups/transports/grpc.py b/google/cloud/dialogflowcx_v3beta1/services/transition_route_groups/transports/grpc.py index 3002b73c..baf9063f 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/transition_route_groups/transports/grpc.py +++ b/google/cloud/dialogflowcx_v3beta1/services/transition_route_groups/transports/grpc.py @@ -62,6 +62,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: @@ -92,6 +93,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): @@ -108,6 +113,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -117,11 +127,6 @@ def __init__( 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 @@ -165,12 +170,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ diff --git a/google/cloud/dialogflowcx_v3beta1/services/transition_route_groups/transports/grpc_asyncio.py b/google/cloud/dialogflowcx_v3beta1/services/transition_route_groups/transports/grpc_asyncio.py index 66167298..cdf8347f 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/transition_route_groups/transports/grpc_asyncio.py +++ b/google/cloud/dialogflowcx_v3beta1/services/transition_route_groups/transports/grpc_asyncio.py @@ -106,6 +106,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: @@ -137,6 +138,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): @@ -153,6 +158,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -162,11 +172,6 @@ def __init__( 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 @@ -210,12 +215,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ diff --git a/google/cloud/dialogflowcx_v3beta1/services/versions/async_client.py b/google/cloud/dialogflowcx_v3beta1/services/versions/async_client.py index 3fdb50ef..757c682d 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/versions/async_client.py +++ b/google/cloud/dialogflowcx_v3beta1/services/versions/async_client.py @@ -78,7 +78,36 @@ class VersionsAsyncClient: common_location_path = staticmethod(VersionsClient.common_location_path) parse_common_location_path = staticmethod(VersionsClient.parse_common_location_path) - from_service_account_file = VersionsClient.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: + VersionsAsyncClient: The constructed client. + """ + return VersionsClient.from_service_account_info.__func__(VersionsAsyncClient, 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: + VersionsAsyncClient: The constructed client. + """ + return VersionsClient.from_service_account_file.__func__(VersionsAsyncClient, filename, *args, **kwargs) # type: ignore + from_service_account_json = from_service_account_file @property @@ -155,7 +184,7 @@ async def list_versions( [Flow][google.cloud.dialogflow.cx.v3beta1.Flow]. Args: - request (:class:`~.version.ListVersionsRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.ListVersionsRequest`): The request object. The request message for [Versions.ListVersions][google.cloud.dialogflow.cx.v3beta1.Versions.ListVersions]. parent (:class:`str`): @@ -163,6 +192,7 @@ async def list_versions( [Flow][google.cloud.dialogflow.cx.v3beta1.Flow] to list all versions for. Format: ``projects//locations//agents//flows/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -174,7 +204,7 @@ async def list_versions( sent along with the request as metadata. Returns: - ~.pagers.ListVersionsAsyncPager: + google.cloud.dialogflowcx_v3beta1.services.versions.pagers.ListVersionsAsyncPager: The response message for [Versions.ListVersions][google.cloud.dialogflow.cx.v3beta1.Versions.ListVersions]. @@ -239,7 +269,7 @@ async def get_version( [Version][google.cloud.dialogflow.cx.v3beta1.Version]. Args: - request (:class:`~.version.GetVersionRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.GetVersionRequest`): The request object. The request message for [Versions.GetVersion][google.cloud.dialogflow.cx.v3beta1.Versions.GetVersion]. name (:class:`str`): @@ -247,6 +277,7 @@ async def get_version( [Version][google.cloud.dialogflow.cx.v3beta1.Version]. Format: ``projects//locations//agents//flows//versions/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -258,7 +289,7 @@ async def get_version( sent along with the request as metadata. Returns: - ~.version.Version: + google.cloud.dialogflowcx_v3beta1.types.Version: Represents a version of a flow. """ # Create or coerce a protobuf request object. @@ -314,7 +345,7 @@ async def create_version( [Flow][google.cloud.dialogflow.cx.v3beta1.Flow]. Args: - request (:class:`~.gcdc_version.CreateVersionRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.CreateVersionRequest`): The request object. The request message for [Versions.CreateVersion][google.cloud.dialogflow.cx.v3beta1.Versions.CreateVersion]. parent (:class:`str`): @@ -324,10 +355,11 @@ async def create_version( [Version][google.cloud.dialogflow.cx.v3beta1.Version] for. Format: ``projects//locations//agents//flows/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - version (:class:`~.gcdc_version.Version`): + version (:class:`google.cloud.dialogflowcx_v3beta1.types.Version`): Required. The version to create. This corresponds to the ``version`` field on the ``request`` instance; if ``request`` is provided, this @@ -340,12 +372,12 @@ async def create_version( 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:``~.gcdc_version.Version``: Represents a version - of a flow. + :class:`google.cloud.dialogflowcx_v3beta1.types.Version` + Represents a version of a flow. """ # Create or coerce a protobuf request object. @@ -410,18 +442,19 @@ async def update_version( [Version][google.cloud.dialogflow.cx.v3beta1.Version]. Args: - request (:class:`~.gcdc_version.UpdateVersionRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.UpdateVersionRequest`): The request object. The request message for [Versions.UpdateVersion][google.cloud.dialogflow.cx.v3beta1.Versions.UpdateVersion]. - version (:class:`~.gcdc_version.Version`): + version (:class:`google.cloud.dialogflowcx_v3beta1.types.Version`): Required. The version to update. This corresponds to the ``version`` 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`): Required. The mask to control which fields get updated. Currently only ``description`` and ``display_name`` can be updated. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -433,7 +466,7 @@ async def update_version( sent along with the request as metadata. Returns: - ~.gcdc_version.Version: + google.cloud.dialogflowcx_v3beta1.types.Version: Represents a version of a flow. """ # Create or coerce a protobuf request object. @@ -491,7 +524,7 @@ async def delete_version( [Version][google.cloud.dialogflow.cx.v3beta1.Version]. Args: - request (:class:`~.version.DeleteVersionRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.DeleteVersionRequest`): The request object. The request message for [Versions.DeleteVersion][google.cloud.dialogflow.cx.v3beta1.Versions.DeleteVersion]. name (:class:`str`): @@ -499,6 +532,7 @@ async def delete_version( [Version][google.cloud.dialogflow.cx.v3beta1.Version] to delete. Format: ``projects//locations//agents//flows//versions/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -558,7 +592,7 @@ async def load_version( r"""Loads a specified version to draft version. Args: - request (:class:`~.version.LoadVersionRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.LoadVersionRequest`): The request object. The request message for [Versions.LoadVersion][google.cloud.dialogflow.cx.v3beta1.Versions.LoadVersion]. name (:class:`str`): @@ -566,6 +600,7 @@ async def load_version( [Version][google.cloud.dialogflow.cx.v3beta1.Version] to be loaded to draft version. Format: ``projects//locations//agents//flows//versions/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -577,24 +612,22 @@ async def load_version( 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:``~.empty.Empty``: A generic empty message that - you can re-use to avoid defining duplicated empty - messages in your APIs. A typical example is to use it as - the request or the response type of an API method. For - instance: + The result type for the operation will be :class:`google.protobuf.empty_pb2.Empty` A generic empty message that you can re-use to avoid defining duplicated + empty messages in your APIs. A typical example is to + use it as the request or the response type of an API + method. For instance: - :: + service Foo { + rpc Bar(google.protobuf.Empty) returns + (google.protobuf.Empty); - service Foo { - rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty); - } + } - The JSON representation for ``Empty`` is empty JSON - object ``{}``. + The JSON representation for Empty is empty JSON + object {}. """ # Create or coerce a protobuf request object. diff --git a/google/cloud/dialogflowcx_v3beta1/services/versions/client.py b/google/cloud/dialogflowcx_v3beta1/services/versions/client.py index 92c5145a..3628b96f 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/versions/client.py +++ b/google/cloud/dialogflowcx_v3beta1/services/versions/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: + VersionsClient: 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. + VersionsClient: The constructed client. """ credentials = service_account.Credentials.from_service_account_file(filename) kwargs["credentials"] = credentials @@ -240,10 +256,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, ~.VersionsTransport]): The + transport (Union[str, VersionsTransport]): 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 @@ -279,21 +295,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: @@ -336,7 +348,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, ) @@ -354,14 +366,15 @@ def list_versions( [Flow][google.cloud.dialogflow.cx.v3beta1.Flow]. Args: - request (:class:`~.version.ListVersionsRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.ListVersionsRequest): The request object. The request message for [Versions.ListVersions][google.cloud.dialogflow.cx.v3beta1.Versions.ListVersions]. - parent (:class:`str`): + parent (str): Required. The [Flow][google.cloud.dialogflow.cx.v3beta1.Flow] to list all versions for. Format: ``projects//locations//agents//flows/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -373,7 +386,7 @@ def list_versions( sent along with the request as metadata. Returns: - ~.pagers.ListVersionsPager: + google.cloud.dialogflowcx_v3beta1.services.versions.pagers.ListVersionsPager: The response message for [Versions.ListVersions][google.cloud.dialogflow.cx.v3beta1.Versions.ListVersions]. @@ -439,14 +452,15 @@ def get_version( [Version][google.cloud.dialogflow.cx.v3beta1.Version]. Args: - request (:class:`~.version.GetVersionRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.GetVersionRequest): The request object. The request message for [Versions.GetVersion][google.cloud.dialogflow.cx.v3beta1.Versions.GetVersion]. - name (:class:`str`): + name (str): Required. The name of the [Version][google.cloud.dialogflow.cx.v3beta1.Version]. Format: ``projects//locations//agents//flows//versions/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -458,7 +472,7 @@ def get_version( sent along with the request as metadata. Returns: - ~.version.Version: + google.cloud.dialogflowcx_v3beta1.types.Version: Represents a version of a flow. """ # Create or coerce a protobuf request object. @@ -515,20 +529,21 @@ def create_version( [Flow][google.cloud.dialogflow.cx.v3beta1.Flow]. Args: - request (:class:`~.gcdc_version.CreateVersionRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.CreateVersionRequest): The request object. The request message for [Versions.CreateVersion][google.cloud.dialogflow.cx.v3beta1.Versions.CreateVersion]. - parent (:class:`str`): + parent (str): Required. The [Flow][google.cloud.dialogflow.cx.v3beta1.Flow] to create an [Version][google.cloud.dialogflow.cx.v3beta1.Version] for. Format: ``projects//locations//agents//flows/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - version (:class:`~.gcdc_version.Version`): + version (google.cloud.dialogflowcx_v3beta1.types.Version): Required. The version to create. This corresponds to the ``version`` field on the ``request`` instance; if ``request`` is provided, this @@ -541,12 +556,12 @@ def create_version( 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:``~.gcdc_version.Version``: Represents a version - of a flow. + :class:`google.cloud.dialogflowcx_v3beta1.types.Version` + Represents a version of a flow. """ # Create or coerce a protobuf request object. @@ -612,18 +627,19 @@ def update_version( [Version][google.cloud.dialogflow.cx.v3beta1.Version]. Args: - request (:class:`~.gcdc_version.UpdateVersionRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.UpdateVersionRequest): The request object. The request message for [Versions.UpdateVersion][google.cloud.dialogflow.cx.v3beta1.Versions.UpdateVersion]. - version (:class:`~.gcdc_version.Version`): + version (google.cloud.dialogflowcx_v3beta1.types.Version): Required. The version to update. This corresponds to the ``version`` 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): Required. The mask to control which fields get updated. Currently only ``description`` and ``display_name`` can be updated. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -635,7 +651,7 @@ def update_version( sent along with the request as metadata. Returns: - ~.gcdc_version.Version: + google.cloud.dialogflowcx_v3beta1.types.Version: Represents a version of a flow. """ # Create or coerce a protobuf request object. @@ -694,14 +710,15 @@ def delete_version( [Version][google.cloud.dialogflow.cx.v3beta1.Version]. Args: - request (:class:`~.version.DeleteVersionRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.DeleteVersionRequest): The request object. The request message for [Versions.DeleteVersion][google.cloud.dialogflow.cx.v3beta1.Versions.DeleteVersion]. - name (:class:`str`): + name (str): Required. The name of the [Version][google.cloud.dialogflow.cx.v3beta1.Version] to delete. Format: ``projects//locations//agents//flows//versions/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -762,14 +779,15 @@ def load_version( r"""Loads a specified version to draft version. Args: - request (:class:`~.version.LoadVersionRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.LoadVersionRequest): The request object. The request message for [Versions.LoadVersion][google.cloud.dialogflow.cx.v3beta1.Versions.LoadVersion]. - name (:class:`str`): + name (str): Required. The [Version][google.cloud.dialogflow.cx.v3beta1.Version] to be loaded to draft version. Format: ``projects//locations//agents//flows//versions/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -781,24 +799,22 @@ def load_version( 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:``~.empty.Empty``: A generic empty message that - you can re-use to avoid defining duplicated empty - messages in your APIs. A typical example is to use it as - the request or the response type of an API method. For - instance: + The result type for the operation will be :class:`google.protobuf.empty_pb2.Empty` A generic empty message that you can re-use to avoid defining duplicated + empty messages in your APIs. A typical example is to + use it as the request or the response type of an API + method. For instance: - :: + service Foo { + rpc Bar(google.protobuf.Empty) returns + (google.protobuf.Empty); - service Foo { - rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty); - } + } - The JSON representation for ``Empty`` is empty JSON - object ``{}``. + The JSON representation for Empty is empty JSON + object {}. """ # Create or coerce a protobuf request object. diff --git a/google/cloud/dialogflowcx_v3beta1/services/versions/pagers.py b/google/cloud/dialogflowcx_v3beta1/services/versions/pagers.py index c6793e05..f12a3a14 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/versions/pagers.py +++ b/google/cloud/dialogflowcx_v3beta1/services/versions/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.dialogflowcx_v3beta1.types import version @@ -24,7 +33,7 @@ class ListVersionsPager: """A pager for iterating through ``list_versions`` requests. This class thinly wraps an initial - :class:`~.version.ListVersionsResponse` object, and + :class:`google.cloud.dialogflowcx_v3beta1.types.ListVersionsResponse` object, and provides an ``__iter__`` method to iterate through its ``versions`` field. @@ -33,7 +42,7 @@ class ListVersionsPager: through the ``versions`` field on the corresponding responses. - All the usual :class:`~.version.ListVersionsResponse` + All the usual :class:`google.cloud.dialogflowcx_v3beta1.types.ListVersionsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -51,9 +60,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.version.ListVersionsRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.ListVersionsRequest): The initial request object. - response (:class:`~.version.ListVersionsResponse`): + response (google.cloud.dialogflowcx_v3beta1.types.ListVersionsResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -86,7 +95,7 @@ class ListVersionsAsyncPager: """A pager for iterating through ``list_versions`` requests. This class thinly wraps an initial - :class:`~.version.ListVersionsResponse` object, and + :class:`google.cloud.dialogflowcx_v3beta1.types.ListVersionsResponse` object, and provides an ``__aiter__`` method to iterate through its ``versions`` field. @@ -95,7 +104,7 @@ class ListVersionsAsyncPager: through the ``versions`` field on the corresponding responses. - All the usual :class:`~.version.ListVersionsResponse` + All the usual :class:`google.cloud.dialogflowcx_v3beta1.types.ListVersionsResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -113,9 +122,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.version.ListVersionsRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.ListVersionsRequest): The initial request object. - response (:class:`~.version.ListVersionsResponse`): + response (google.cloud.dialogflowcx_v3beta1.types.ListVersionsResponse): 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/dialogflowcx_v3beta1/services/versions/transports/grpc.py b/google/cloud/dialogflowcx_v3beta1/services/versions/transports/grpc.py index 226cd5f1..7d5ba95d 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/versions/transports/grpc.py +++ b/google/cloud/dialogflowcx_v3beta1/services/versions/transports/grpc.py @@ -62,6 +62,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: @@ -92,6 +93,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): @@ -108,6 +113,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -117,11 +127,6 @@ def __init__( 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 @@ -165,12 +170,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ diff --git a/google/cloud/dialogflowcx_v3beta1/services/versions/transports/grpc_asyncio.py b/google/cloud/dialogflowcx_v3beta1/services/versions/transports/grpc_asyncio.py index 72ab543e..14c0f00c 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/versions/transports/grpc_asyncio.py +++ b/google/cloud/dialogflowcx_v3beta1/services/versions/transports/grpc_asyncio.py @@ -106,6 +106,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: @@ -137,6 +138,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): @@ -153,6 +158,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -162,11 +172,6 @@ def __init__( 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 @@ -210,12 +215,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ diff --git a/google/cloud/dialogflowcx_v3beta1/services/webhooks/async_client.py b/google/cloud/dialogflowcx_v3beta1/services/webhooks/async_client.py index bb18f096..8c4dee0a 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/webhooks/async_client.py +++ b/google/cloud/dialogflowcx_v3beta1/services/webhooks/async_client.py @@ -73,7 +73,36 @@ class WebhooksAsyncClient: common_location_path = staticmethod(WebhooksClient.common_location_path) parse_common_location_path = staticmethod(WebhooksClient.parse_common_location_path) - from_service_account_file = WebhooksClient.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: + WebhooksAsyncClient: The constructed client. + """ + return WebhooksClient.from_service_account_info.__func__(WebhooksAsyncClient, 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: + WebhooksAsyncClient: The constructed client. + """ + return WebhooksClient.from_service_account_file.__func__(WebhooksAsyncClient, filename, *args, **kwargs) # type: ignore + from_service_account_json = from_service_account_file @property @@ -150,12 +179,13 @@ async def list_webhooks( agent. Args: - request (:class:`~.webhook.ListWebhooksRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.ListWebhooksRequest`): The request object. The request message for [Webhooks.ListWebhooks][google.cloud.dialogflow.cx.v3beta1.Webhooks.ListWebhooks]. parent (:class:`str`): Required. The agent to list all webhooks for. Format: ``projects//locations//agents/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -167,7 +197,7 @@ async def list_webhooks( sent along with the request as metadata. Returns: - ~.pagers.ListWebhooksAsyncPager: + google.cloud.dialogflowcx_v3beta1.services.webhooks.pagers.ListWebhooksAsyncPager: The response message for [Webhooks.ListWebhooks][google.cloud.dialogflow.cx.v3beta1.Webhooks.ListWebhooks]. @@ -231,12 +261,13 @@ async def get_webhook( r"""Retrieves the specified webhook. Args: - request (:class:`~.webhook.GetWebhookRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.GetWebhookRequest`): The request object. The request message for [Webhooks.GetWebhook][google.cloud.dialogflow.cx.v3beta1.Webhooks.GetWebhook]. name (:class:`str`): Required. The name of the webhook. Format: ``projects//locations//agents//webhooks/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -248,7 +279,7 @@ async def get_webhook( sent along with the request as metadata. Returns: - ~.webhook.Webhook: + google.cloud.dialogflowcx_v3beta1.types.Webhook: Webhooks host the developer's business logic. During a session, webhooks allow the developer to use the @@ -309,16 +340,17 @@ async def create_webhook( r"""Creates a webhook in the specified agent. Args: - request (:class:`~.gcdc_webhook.CreateWebhookRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.CreateWebhookRequest`): The request object. The request message for [Webhooks.CreateWebhook][google.cloud.dialogflow.cx.v3beta1.Webhooks.CreateWebhook]. parent (:class:`str`): Required. The agent to create a webhook for. Format: ``projects//locations//agents/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - webhook (:class:`~.gcdc_webhook.Webhook`): + webhook (:class:`google.cloud.dialogflowcx_v3beta1.types.Webhook`): Required. The webhook to create. This corresponds to the ``webhook`` field on the ``request`` instance; if ``request`` is provided, this @@ -331,7 +363,7 @@ async def create_webhook( sent along with the request as metadata. Returns: - ~.gcdc_webhook.Webhook: + google.cloud.dialogflowcx_v3beta1.types.Webhook: Webhooks host the developer's business logic. During a session, webhooks allow the developer to use the @@ -394,18 +426,19 @@ async def update_webhook( r"""Updates the specified webhook. Args: - request (:class:`~.gcdc_webhook.UpdateWebhookRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.UpdateWebhookRequest`): The request object. The request message for [Webhooks.UpdateWebhook][google.cloud.dialogflow.cx.v3beta1.Webhooks.UpdateWebhook]. - webhook (:class:`~.gcdc_webhook.Webhook`): + webhook (:class:`google.cloud.dialogflowcx_v3beta1.types.Webhook`): Required. The webhook to update. This corresponds to the ``webhook`` 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`): The mask to control which fields get updated. If the mask is not present, all fields will be updated. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -417,7 +450,7 @@ async def update_webhook( sent along with the request as metadata. Returns: - ~.gcdc_webhook.Webhook: + google.cloud.dialogflowcx_v3beta1.types.Webhook: Webhooks host the developer's business logic. During a session, webhooks allow the developer to use the @@ -481,12 +514,13 @@ async def delete_webhook( r"""Deletes the specified webhook. Args: - request (:class:`~.webhook.DeleteWebhookRequest`): + request (:class:`google.cloud.dialogflowcx_v3beta1.types.DeleteWebhookRequest`): The request object. The request message for [Webhooks.DeleteWebhook][google.cloud.dialogflow.cx.v3beta1.Webhooks.DeleteWebhook]. name (:class:`str`): Required. The name of the webhook to delete. Format: ``projects//locations//agents//webhooks/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. diff --git a/google/cloud/dialogflowcx_v3beta1/services/webhooks/client.py b/google/cloud/dialogflowcx_v3beta1/services/webhooks/client.py index 96720000..b12a948a 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/webhooks/client.py +++ b/google/cloud/dialogflowcx_v3beta1/services/webhooks/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: + WebhooksClient: 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. + WebhooksClient: The constructed client. """ credentials = service_account.Credentials.from_service_account_file(filename) kwargs["credentials"] = credentials @@ -233,10 +249,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, ~.WebhooksTransport]): The + transport (Union[str, WebhooksTransport]): 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 @@ -272,21 +288,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: @@ -329,7 +341,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, ) @@ -347,12 +359,13 @@ def list_webhooks( agent. Args: - request (:class:`~.webhook.ListWebhooksRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.ListWebhooksRequest): The request object. The request message for [Webhooks.ListWebhooks][google.cloud.dialogflow.cx.v3beta1.Webhooks.ListWebhooks]. - parent (:class:`str`): + parent (str): Required. The agent to list all webhooks for. Format: ``projects//locations//agents/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -364,7 +377,7 @@ def list_webhooks( sent along with the request as metadata. Returns: - ~.pagers.ListWebhooksPager: + google.cloud.dialogflowcx_v3beta1.services.webhooks.pagers.ListWebhooksPager: The response message for [Webhooks.ListWebhooks][google.cloud.dialogflow.cx.v3beta1.Webhooks.ListWebhooks]. @@ -429,12 +442,13 @@ def get_webhook( r"""Retrieves the specified webhook. Args: - request (:class:`~.webhook.GetWebhookRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.GetWebhookRequest): The request object. The request message for [Webhooks.GetWebhook][google.cloud.dialogflow.cx.v3beta1.Webhooks.GetWebhook]. - name (:class:`str`): + name (str): Required. The name of the webhook. Format: ``projects//locations//agents//webhooks/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -446,7 +460,7 @@ def get_webhook( sent along with the request as metadata. Returns: - ~.webhook.Webhook: + google.cloud.dialogflowcx_v3beta1.types.Webhook: Webhooks host the developer's business logic. During a session, webhooks allow the developer to use the @@ -508,16 +522,17 @@ def create_webhook( r"""Creates a webhook in the specified agent. Args: - request (:class:`~.gcdc_webhook.CreateWebhookRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.CreateWebhookRequest): The request object. The request message for [Webhooks.CreateWebhook][google.cloud.dialogflow.cx.v3beta1.Webhooks.CreateWebhook]. - parent (:class:`str`): + parent (str): Required. The agent to create a webhook for. Format: ``projects//locations//agents/``. + This corresponds to the ``parent`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - webhook (:class:`~.gcdc_webhook.Webhook`): + webhook (google.cloud.dialogflowcx_v3beta1.types.Webhook): Required. The webhook to create. This corresponds to the ``webhook`` field on the ``request`` instance; if ``request`` is provided, this @@ -530,7 +545,7 @@ def create_webhook( sent along with the request as metadata. Returns: - ~.gcdc_webhook.Webhook: + google.cloud.dialogflowcx_v3beta1.types.Webhook: Webhooks host the developer's business logic. During a session, webhooks allow the developer to use the @@ -594,18 +609,19 @@ def update_webhook( r"""Updates the specified webhook. Args: - request (:class:`~.gcdc_webhook.UpdateWebhookRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.UpdateWebhookRequest): The request object. The request message for [Webhooks.UpdateWebhook][google.cloud.dialogflow.cx.v3beta1.Webhooks.UpdateWebhook]. - webhook (:class:`~.gcdc_webhook.Webhook`): + webhook (google.cloud.dialogflowcx_v3beta1.types.Webhook): Required. The webhook to update. This corresponds to the ``webhook`` 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): The mask to control which fields get updated. If the mask is not present, all fields will be updated. + This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -617,7 +633,7 @@ def update_webhook( sent along with the request as metadata. Returns: - ~.gcdc_webhook.Webhook: + google.cloud.dialogflowcx_v3beta1.types.Webhook: Webhooks host the developer's business logic. During a session, webhooks allow the developer to use the @@ -682,12 +698,13 @@ def delete_webhook( r"""Deletes the specified webhook. Args: - request (:class:`~.webhook.DeleteWebhookRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.DeleteWebhookRequest): The request object. The request message for [Webhooks.DeleteWebhook][google.cloud.dialogflow.cx.v3beta1.Webhooks.DeleteWebhook]. - name (:class:`str`): + name (str): Required. The name of the webhook to delete. Format: ``projects//locations//agents//webhooks/``. + This corresponds to the ``name`` field on the ``request`` instance; if ``request`` is provided, this should not be set. diff --git a/google/cloud/dialogflowcx_v3beta1/services/webhooks/pagers.py b/google/cloud/dialogflowcx_v3beta1/services/webhooks/pagers.py index 91677e47..4dec3eb1 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/webhooks/pagers.py +++ b/google/cloud/dialogflowcx_v3beta1/services/webhooks/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.dialogflowcx_v3beta1.types import webhook @@ -24,7 +33,7 @@ class ListWebhooksPager: """A pager for iterating through ``list_webhooks`` requests. This class thinly wraps an initial - :class:`~.webhook.ListWebhooksResponse` object, and + :class:`google.cloud.dialogflowcx_v3beta1.types.ListWebhooksResponse` object, and provides an ``__iter__`` method to iterate through its ``webhooks`` field. @@ -33,7 +42,7 @@ class ListWebhooksPager: through the ``webhooks`` field on the corresponding responses. - All the usual :class:`~.webhook.ListWebhooksResponse` + All the usual :class:`google.cloud.dialogflowcx_v3beta1.types.ListWebhooksResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -51,9 +60,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.webhook.ListWebhooksRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.ListWebhooksRequest): The initial request object. - response (:class:`~.webhook.ListWebhooksResponse`): + response (google.cloud.dialogflowcx_v3beta1.types.ListWebhooksResponse): The initial response object. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. @@ -86,7 +95,7 @@ class ListWebhooksAsyncPager: """A pager for iterating through ``list_webhooks`` requests. This class thinly wraps an initial - :class:`~.webhook.ListWebhooksResponse` object, and + :class:`google.cloud.dialogflowcx_v3beta1.types.ListWebhooksResponse` object, and provides an ``__aiter__`` method to iterate through its ``webhooks`` field. @@ -95,7 +104,7 @@ class ListWebhooksAsyncPager: through the ``webhooks`` field on the corresponding responses. - All the usual :class:`~.webhook.ListWebhooksResponse` + All the usual :class:`google.cloud.dialogflowcx_v3beta1.types.ListWebhooksResponse` attributes are available on the pager. If multiple requests are made, only the most recent response is retained, and thus used for attribute lookup. """ @@ -113,9 +122,9 @@ def __init__( Args: method (Callable): The method that was originally called, and which instantiated this pager. - request (:class:`~.webhook.ListWebhooksRequest`): + request (google.cloud.dialogflowcx_v3beta1.types.ListWebhooksRequest): The initial request object. - response (:class:`~.webhook.ListWebhooksResponse`): + response (google.cloud.dialogflowcx_v3beta1.types.ListWebhooksResponse): 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/dialogflowcx_v3beta1/services/webhooks/transports/grpc.py b/google/cloud/dialogflowcx_v3beta1/services/webhooks/transports/grpc.py index 0506a703..e661ac29 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/webhooks/transports/grpc.py +++ b/google/cloud/dialogflowcx_v3beta1/services/webhooks/transports/grpc.py @@ -60,6 +60,7 @@ def __init__( api_mtls_endpoint: str = None, client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, quota_project_id: Optional[str] = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: @@ -90,6 +91,10 @@ def __init__( ``api_mtls_endpoint`` is None. ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials for grpc channel. It is ignored if ``channel`` is provided. + client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]): + A callback to provide client certificate bytes and private key bytes, + both in PEM format. It is used to configure mutual TLS channel. It is + ignored if ``channel`` or ``ssl_channel_credentials`` is provided. quota_project_id (Optional[str]): An optional project to use for billing and quota. client_info (google.api_core.gapic_v1.client_info.ClientInfo): @@ -106,6 +111,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -115,11 +125,6 @@ def __init__( 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 @@ -163,12 +168,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ diff --git a/google/cloud/dialogflowcx_v3beta1/services/webhooks/transports/grpc_asyncio.py b/google/cloud/dialogflowcx_v3beta1/services/webhooks/transports/grpc_asyncio.py index b781c7d5..75b7905f 100644 --- a/google/cloud/dialogflowcx_v3beta1/services/webhooks/transports/grpc_asyncio.py +++ b/google/cloud/dialogflowcx_v3beta1/services/webhooks/transports/grpc_asyncio.py @@ -104,6 +104,7 @@ def __init__( api_mtls_endpoint: str = None, client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, quota_project_id=None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: @@ -135,6 +136,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): @@ -151,6 +156,11 @@ def __init__( """ self._ssl_channel_credentials = ssl_channel_credentials + 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. @@ -160,11 +170,6 @@ def __init__( 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 @@ -208,12 +213,18 @@ def __init__( scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id ) + 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_channel_credentials, + ssl_credentials=self._ssl_channel_credentials, scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, options=[ diff --git a/google/cloud/dialogflowcx_v3beta1/types/__init__.py b/google/cloud/dialogflowcx_v3beta1/types/__init__.py index 248e71eb..e7498fa4 100644 --- a/google/cloud/dialogflowcx_v3beta1/types/__init__.py +++ b/google/cloud/dialogflowcx_v3beta1/types/__init__.py @@ -29,6 +29,10 @@ UpdatePageRequest, DeletePageRequest, ) +from .validation_message import ( + ValidationMessage, + ResourceName, +) from .flow import ( NluSettings, Flow, @@ -39,6 +43,9 @@ GetFlowRequest, UpdateFlowRequest, TrainFlowRequest, + ValidateFlowRequest, + GetFlowValidationResultRequest, + FlowValidationResult, ) from .security_settings import ( GetSecuritySettingsRequest, @@ -61,6 +68,9 @@ ExportAgentRequest, ExportAgentResponse, RestoreAgentRequest, + ValidateAgentRequest, + GetAgentValidationResultRequest, + AgentValidationResult, ) from .audio_config import ( SpeechWordInfo, @@ -155,6 +165,41 @@ UpdateTransitionRouteGroupRequest, DeleteTransitionRouteGroupRequest, ) +from .test_case import ( + TestCase, + TestCaseResult, + TestConfig, + ConversationTurn, + TestRunDifference, + TransitionCoverage, + TransitionRouteGroupCoverage, + IntentCoverage, + CalculateCoverageRequest, + CalculateCoverageResponse, + ListTestCasesRequest, + ListTestCasesResponse, + BatchDeleteTestCasesRequest, + CreateTestCaseRequest, + UpdateTestCaseRequest, + GetTestCaseRequest, + RunTestCaseRequest, + RunTestCaseResponse, + RunTestCaseMetadata, + BatchRunTestCasesRequest, + BatchRunTestCasesResponse, + BatchRunTestCasesMetadata, + TestError, + ImportTestCasesRequest, + ImportTestCasesResponse, + ImportTestCasesMetadata, + TestCaseError, + ExportTestCasesRequest, + ExportTestCasesResponse, + ExportTestCasesMetadata, + ListTestCaseResultsRequest, + ListTestCaseResultsResponse, + TestResult, +) from .version import ( CreateVersionOperationMetadata, Version, @@ -193,6 +238,8 @@ "CreatePageRequest", "UpdatePageRequest", "DeletePageRequest", + "ValidationMessage", + "ResourceName", "NluSettings", "Flow", "CreateFlowRequest", @@ -202,6 +249,9 @@ "GetFlowRequest", "UpdateFlowRequest", "TrainFlowRequest", + "ValidateFlowRequest", + "GetFlowValidationResultRequest", + "FlowValidationResult", "GetSecuritySettingsRequest", "UpdateSecuritySettingsRequest", "ListSecuritySettingsRequest", @@ -220,6 +270,9 @@ "ExportAgentRequest", "ExportAgentResponse", "RestoreAgentRequest", + "ValidateAgentRequest", + "GetAgentValidationResultRequest", + "AgentValidationResult", "SpeechWordInfo", "InputAudioConfig", "VoiceSelectionParams", @@ -297,6 +350,39 @@ "CreateTransitionRouteGroupRequest", "UpdateTransitionRouteGroupRequest", "DeleteTransitionRouteGroupRequest", + "TestCase", + "TestCaseResult", + "TestConfig", + "ConversationTurn", + "TestRunDifference", + "TransitionCoverage", + "TransitionRouteGroupCoverage", + "IntentCoverage", + "CalculateCoverageRequest", + "CalculateCoverageResponse", + "ListTestCasesRequest", + "ListTestCasesResponse", + "BatchDeleteTestCasesRequest", + "CreateTestCaseRequest", + "UpdateTestCaseRequest", + "GetTestCaseRequest", + "RunTestCaseRequest", + "RunTestCaseResponse", + "RunTestCaseMetadata", + "BatchRunTestCasesRequest", + "BatchRunTestCasesResponse", + "BatchRunTestCasesMetadata", + "TestError", + "ImportTestCasesRequest", + "ImportTestCasesResponse", + "ImportTestCasesMetadata", + "TestCaseError", + "ExportTestCasesRequest", + "ExportTestCasesResponse", + "ExportTestCasesMetadata", + "ListTestCaseResultsRequest", + "ListTestCaseResultsResponse", + "TestResult", "CreateVersionOperationMetadata", "Version", "ListVersionsRequest", diff --git a/google/cloud/dialogflowcx_v3beta1/types/agent.py b/google/cloud/dialogflowcx_v3beta1/types/agent.py index ac3025af..174eace2 100644 --- a/google/cloud/dialogflowcx_v3beta1/types/agent.py +++ b/google/cloud/dialogflowcx_v3beta1/types/agent.py @@ -18,6 +18,7 @@ import proto # type: ignore +from google.cloud.dialogflowcx_v3beta1.types import flow from google.protobuf import field_mask_pb2 as field_mask # type: ignore @@ -35,6 +36,9 @@ "ExportAgentRequest", "ExportAgentResponse", "RestoreAgentRequest", + "ValidateAgentRequest", + "GetAgentValidationResultRequest", + "AgentValidationResult", }, ) @@ -79,7 +83,7 @@ class Agent(proto.Message): default_language_code (str): Immutable. The default language of the agent as a language tag. See `Language - Support `__ + Support `__ for a list of the currently supported language codes. This field cannot be set by the [Agents.UpdateAgent][google.cloud.dialogflow.cx.v3beta1.Agents.UpdateAgent] @@ -97,7 +101,7 @@ class Agent(proto.Message): the Dialogflow console and in the self-hosted `Web Demo `__ integration. - speech_to_text_settings (~.gcdc_agent.SpeechToTextSettings): + speech_to_text_settings (google.cloud.dialogflowcx_v3beta1.types.SpeechToTextSettings): Speech recognition related settings. start_flow (str): Immutable. Name of the start flow in this agent. A start @@ -105,6 +109,11 @@ class Agent(proto.Message): created, and can only be deleted by deleting the agent. Format: ``projects//locations//agents//flows/``. + security_settings (str): + Name of the + [SecuritySettings][google.cloud.dialogflow.cx.v3beta1.SecuritySettings] + reference for the agent. Format: + ``projects//locations//securitySettings/``. enable_stackdriver_logging (bool): Indicates if stackdriver logging is enabled for the agent. @@ -131,6 +140,8 @@ class Agent(proto.Message): start_flow = proto.Field(proto.STRING, number=16) + security_settings = proto.Field(proto.STRING, number=17) + enable_stackdriver_logging = proto.Field(proto.BOOL, number=18) enable_spell_correction = proto.Field(proto.BOOL, number=20) @@ -164,7 +175,7 @@ class ListAgentsResponse(proto.Message): [Agents.ListAgents][google.cloud.dialogflow.cx.v3beta1.Agents.ListAgents]. Attributes: - agents (Sequence[~.gcdc_agent.Agent]): + agents (Sequence[google.cloud.dialogflowcx_v3beta1.types.Agent]): The list of agents. There will be a maximum number of items returned based on the page_size field in the request. next_page_token (str): @@ -203,7 +214,7 @@ class CreateAgentRequest(proto.Message): parent (str): Required. The location to create a agent for. Format: ``projects//locations/``. - agent (~.gcdc_agent.Agent): + agent (google.cloud.dialogflowcx_v3beta1.types.Agent): Required. The agent to create. """ @@ -217,9 +228,9 @@ class UpdateAgentRequest(proto.Message): [Agents.UpdateAgent][google.cloud.dialogflow.cx.v3beta1.Agents.UpdateAgent]. Attributes: - agent (~.gcdc_agent.Agent): + agent (google.cloud.dialogflowcx_v3beta1.types.Agent): Required. The agent to update. - update_mask (~.field_mask.FieldMask): + update_mask (google.protobuf.field_mask_pb2.FieldMask): The mask to control which fields get updated. If the mask is not present, all fields will be updated. @@ -306,4 +317,60 @@ class RestoreAgentRequest(proto.Message): agent_content = proto.Field(proto.BYTES, number=3, oneof="agent") +class ValidateAgentRequest(proto.Message): + r"""The request message for + [Agents.ValidateAgent][google.cloud.dialogflow.cx.v3beta1.Agents.ValidateAgent]. + + Attributes: + name (str): + Required. The agent to validate. Format: + ``projects//locations//agents/``. + language_code (str): + If not specified, the agent's default + language is used. + """ + + name = proto.Field(proto.STRING, number=1) + + language_code = proto.Field(proto.STRING, number=2) + + +class GetAgentValidationResultRequest(proto.Message): + r"""The request message for + [Agents.GetAgentValidationResult][google.cloud.dialogflow.cx.v3beta1.Agents.GetAgentValidationResult]. + + Attributes: + name (str): + Required. The agent name. Format: + ``projects//locations//agents//validationResult``. + language_code (str): + If not specified, the agent's default + language is used. + """ + + name = proto.Field(proto.STRING, number=1) + + language_code = proto.Field(proto.STRING, number=2) + + +class AgentValidationResult(proto.Message): + r"""The response message for + [Agents.GetAgentValidationResult][google.cloud.dialogflow.cx.v3beta1.Agents.GetAgentValidationResult]. + + Attributes: + name (str): + The unique identifier of the agent validation result. + Format: + ``projects//locations//agents//validationResult``. + flow_validation_results (Sequence[google.cloud.dialogflowcx_v3beta1.types.FlowValidationResult]): + Contains all flow validation results. + """ + + name = proto.Field(proto.STRING, number=1) + + flow_validation_results = proto.RepeatedField( + proto.MESSAGE, number=2, message=flow.FlowValidationResult, + ) + + __all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/google/cloud/dialogflowcx_v3beta1/types/audio_config.py b/google/cloud/dialogflowcx_v3beta1/types/audio_config.py index 844c3edb..df0a464f 100644 --- a/google/cloud/dialogflowcx_v3beta1/types/audio_config.py +++ b/google/cloud/dialogflowcx_v3beta1/types/audio_config.py @@ -97,12 +97,12 @@ class SpeechWordInfo(proto.Message): Attributes: word (str): The word this info is for. - start_offset (~.duration.Duration): + start_offset (google.protobuf.duration_pb2.Duration): Time offset relative to the beginning of the audio that corresponds to the start of the spoken word. This is an experimental feature and the accuracy of the time offset can vary. - end_offset (~.duration.Duration): + end_offset (google.protobuf.duration_pb2.Duration): Time offset relative to the beginning of the audio that corresponds to the end of the spoken word. This is an experimental feature and the @@ -134,7 +134,7 @@ class InputAudioConfig(proto.Message): content. Attributes: - audio_encoding (~.audio_config.AudioEncoding): + audio_encoding (google.cloud.dialogflowcx_v3beta1.types.AudioEncoding): Required. Audio encoding of the audio content to process. sample_rate_hertz (int): @@ -170,7 +170,7 @@ class InputAudioConfig(proto.Message): `Cloud Speech API documentation `__ for more details. - model_variant (~.audio_config.SpeechModelVariant): + model_variant (google.cloud.dialogflowcx_v3beta1.types.SpeechModelVariant): Optional. Which variant of the [Speech model][google.cloud.dialogflow.cx.v3beta1.InputAudioConfig.model] to use. @@ -209,7 +209,11 @@ class VoiceSelectionParams(proto.Message): will choose a voice based on the other parameters such as language_code and [ssml_gender][google.cloud.dialogflow.cx.v3beta1.VoiceSelectionParams.ssml_gender]. - ssml_gender (~.audio_config.SsmlVoiceGender): + + For the list of available voices, please refer to `Supported + voices and + languages `__. + ssml_gender (google.cloud.dialogflowcx_v3beta1.types.SsmlVoiceGender): Optional. The preferred gender of the voice. If not set, the service will choose a voice based on the other parameters such as language_code and @@ -256,7 +260,7 @@ class SynthesizeSpeechConfig(proto.Message): synthesized) text to speech. Effects are applied on top of each other in the order they are given. - voice (~.audio_config.VoiceSelectionParams): + voice (google.cloud.dialogflowcx_v3beta1.types.VoiceSelectionParams): Optional. The desired voice of the synthesized audio. """ @@ -277,7 +281,7 @@ class OutputAudioConfig(proto.Message): audio content. Attributes: - audio_encoding (~.audio_config.OutputAudioEncoding): + audio_encoding (google.cloud.dialogflowcx_v3beta1.types.OutputAudioEncoding): Required. Audio encoding of the synthesized audio content. sample_rate_hertz (int): @@ -289,7 +293,7 @@ class OutputAudioConfig(proto.Message): then the synthesizer will honor this request by converting to the desired sample rate (which might result in worse audio quality). - synthesize_speech_config (~.audio_config.SynthesizeSpeechConfig): + synthesize_speech_config (google.cloud.dialogflowcx_v3beta1.types.SynthesizeSpeechConfig): Optional. Configuration of how speech should be synthesized. """ diff --git a/google/cloud/dialogflowcx_v3beta1/types/entity_type.py b/google/cloud/dialogflowcx_v3beta1/types/entity_type.py index ca80a8a8..7a940f3c 100644 --- a/google/cloud/dialogflowcx_v3beta1/types/entity_type.py +++ b/google/cloud/dialogflowcx_v3beta1/types/entity_type.py @@ -77,15 +77,15 @@ class EntityType(proto.Message): display_name (str): Required. The human-readable name of the entity type, unique within the agent. - kind (~.gcdc_entity_type.EntityType.Kind): + kind (google.cloud.dialogflowcx_v3beta1.types.EntityType.Kind): Required. Indicates the kind of entity type. - auto_expansion_mode (~.gcdc_entity_type.EntityType.AutoExpansionMode): + auto_expansion_mode (google.cloud.dialogflowcx_v3beta1.types.EntityType.AutoExpansionMode): Indicates whether the entity type can be automatically expanded. - entities (Sequence[~.gcdc_entity_type.EntityType.Entity]): + entities (Sequence[google.cloud.dialogflowcx_v3beta1.types.EntityType.Entity]): The collection of entity entries associated with the entity type. - excluded_phrases (Sequence[~.gcdc_entity_type.EntityType.ExcludedPhrase]): + excluded_phrases (Sequence[google.cloud.dialogflowcx_v3beta1.types.EntityType.ExcludedPhrase]): Collection of exceptional words and phrases that shouldn't be matched. For example, if you have a size entity type with entry ``giant``\ (an adjective), you might consider adding @@ -95,6 +95,12 @@ class EntityType(proto.Message): enable_fuzzy_extraction (bool): Enables fuzzy entity extraction during classification. + redact (bool): + Indicates whether parameters of the entity + type should be redacted in log. If redaction is + enabled, page parameters and intent parameters + referring to the entity type will be replaced by + parameter name during logging. """ class Kind(proto.Enum): @@ -114,7 +120,7 @@ class AutoExpansionMode(proto.Enum): AUTO_EXPANSION_MODE_DEFAULT = 1 class Entity(proto.Message): - r"""An **entity entry** for an associated entity type. Next Id = 8 + r"""An **entity entry** for an associated entity type. Attributes: value (str): @@ -171,6 +177,8 @@ class ExcludedPhrase(proto.Message): enable_fuzzy_extraction = proto.Field(proto.BOOL, number=7) + redact = proto.Field(proto.BOOL, number=9) + class ListEntityTypesRequest(proto.Message): r"""The request message for @@ -190,7 +198,7 @@ class ListEntityTypesRequest(proto.Message): If not specified, the agent's default language is used. `Many - languages `__ + languages `__ are supported. Note: languages must be enabled in the agent before they can be used. page_size (int): @@ -215,7 +223,7 @@ class ListEntityTypesResponse(proto.Message): [EntityTypes.ListEntityTypes][google.cloud.dialogflow.cx.v3beta1.EntityTypes.ListEntityTypes]. Attributes: - entity_types (Sequence[~.gcdc_entity_type.EntityType]): + entity_types (Sequence[google.cloud.dialogflowcx_v3beta1.types.EntityType]): The list of entity types. There will be a maximum number of items returned based on the page_size field in the request. next_page_token (str): @@ -251,7 +259,7 @@ class GetEntityTypeRequest(proto.Message): If not specified, the agent's default language is used. `Many - languages `__ + languages `__ are supported. Note: languages must be enabled in the agent before they can be used. """ @@ -269,7 +277,7 @@ class CreateEntityTypeRequest(proto.Message): parent (str): Required. The agent to create a entity type for. Format: ``projects//locations//agents/``. - entity_type (~.gcdc_entity_type.EntityType): + entity_type (google.cloud.dialogflowcx_v3beta1.types.EntityType): Required. The entity type to create. language_code (str): The language of the following fields in ``entity_type``: @@ -280,7 +288,7 @@ class CreateEntityTypeRequest(proto.Message): If not specified, the agent's default language is used. `Many - languages `__ + languages `__ are supported. Note: languages must be enabled in the agent before they can be used. """ @@ -297,7 +305,7 @@ class UpdateEntityTypeRequest(proto.Message): [EntityTypes.UpdateEntityType][google.cloud.dialogflow.cx.v3beta1.EntityTypes.UpdateEntityType]. Attributes: - entity_type (~.gcdc_entity_type.EntityType): + entity_type (google.cloud.dialogflowcx_v3beta1.types.EntityType): Required. The entity type to update. language_code (str): The language of the following fields in ``entity_type``: @@ -308,10 +316,10 @@ class UpdateEntityTypeRequest(proto.Message): If not specified, the agent's default language is used. `Many - languages `__ + languages `__ are supported. Note: languages must be enabled in the agent before they can be used. - update_mask (~.field_mask.FieldMask): + update_mask (google.protobuf.field_mask_pb2.FieldMask): The mask to control which fields get updated. """ diff --git a/google/cloud/dialogflowcx_v3beta1/types/environment.py b/google/cloud/dialogflowcx_v3beta1/types/environment.py index 9d6426c3..60988fc9 100644 --- a/google/cloud/dialogflowcx_v3beta1/types/environment.py +++ b/google/cloud/dialogflowcx_v3beta1/types/environment.py @@ -62,12 +62,12 @@ class Environment(proto.Message): environment. The maximum length is 500 characters. If exceeded, the request is rejected. - version_configs (Sequence[~.gcdc_environment.Environment.VersionConfig]): + version_configs (Sequence[google.cloud.dialogflowcx_v3beta1.types.Environment.VersionConfig]): Required. A list of configurations for flow versions. You should include version configs for all flows that are reachable from [``Start Flow``][Agent.start_flow] in the agent. Otherwise, an error will be returned. - update_time (~.timestamp.Timestamp): + update_time (google.protobuf.timestamp_pb2.Timestamp): Output only. Update time of this environment. """ @@ -126,7 +126,7 @@ class ListEnvironmentsResponse(proto.Message): [Environments.ListEnvironments][google.cloud.dialogflow.cx.v3beta1.Environments.ListEnvironments]. Attributes: - environments (Sequence[~.gcdc_environment.Environment]): + environments (Sequence[google.cloud.dialogflowcx_v3beta1.types.Environment]): The list of environments. There will be a maximum number of items returned based on the page_size field in the request. The list may in some cases be empty or contain fewer entries @@ -173,7 +173,7 @@ class CreateEnvironmentRequest(proto.Message): [Environment][google.cloud.dialogflow.cx.v3beta1.Environment] for. Format: ``projects//locations//agents/``. - environment (~.gcdc_environment.Environment): + environment (google.cloud.dialogflowcx_v3beta1.types.Environment): Required. The environment to create. """ @@ -187,9 +187,9 @@ class UpdateEnvironmentRequest(proto.Message): [Environments.UpdateEnvironment][google.cloud.dialogflow.cx.v3beta1.Environments.UpdateEnvironment]. Attributes: - environment (~.gcdc_environment.Environment): + environment (google.cloud.dialogflowcx_v3beta1.types.Environment): Required. The environment to update. - update_mask (~.field_mask.FieldMask): + update_mask (google.protobuf.field_mask_pb2.FieldMask): Required. The mask to control which fields get updated. """ @@ -243,7 +243,7 @@ class LookupEnvironmentHistoryResponse(proto.Message): [Environments.LookupEnvironmentHistory][google.cloud.dialogflow.cx.v3beta1.Environments.LookupEnvironmentHistory]. Attributes: - environments (Sequence[~.gcdc_environment.Environment]): + environments (Sequence[google.cloud.dialogflowcx_v3beta1.types.Environment]): Represents a list of snapshots for an environment. Time of the snapshots is stored in [``update_time``][google.cloud.dialogflow.cx.v3beta1.Environment.update_time]. diff --git a/google/cloud/dialogflowcx_v3beta1/types/experiment.py b/google/cloud/dialogflowcx_v3beta1/types/experiment.py index 3e1e0e6f..17d0d3b4 100644 --- a/google/cloud/dialogflowcx_v3beta1/types/experiment.py +++ b/google/cloud/dialogflowcx_v3beta1/types/experiment.py @@ -43,7 +43,6 @@ class Experiment(proto.Message): r"""Represents an experiment in an environment. - Next ID: 13 Attributes: name (str): @@ -59,28 +58,28 @@ class Experiment(proto.Message): description (str): The human-readable description of the experiment. - state (~.gcdc_experiment.Experiment.State): + state (google.cloud.dialogflowcx_v3beta1.types.Experiment.State): The current state of the experiment. Transition triggered by Expriments.StartExperiment: PENDING->RUNNING. Transition triggered by Expriments.CancelExperiment: PENDING->CANCELLED or RUNNING->CANCELLED. - definition (~.gcdc_experiment.Experiment.Definition): + definition (google.cloud.dialogflowcx_v3beta1.types.Experiment.Definition): The definition of the experiment. - result (~.gcdc_experiment.Experiment.Result): + result (google.cloud.dialogflowcx_v3beta1.types.Experiment.Result): Inference result of the experiment. - create_time (~.timestamp.Timestamp): + create_time (google.protobuf.timestamp_pb2.Timestamp): Creation time of this experiment. - start_time (~.timestamp.Timestamp): + start_time (google.protobuf.timestamp_pb2.Timestamp): Start time of this experiment. - end_time (~.timestamp.Timestamp): + end_time (google.protobuf.timestamp_pb2.Timestamp): End time of this experiment. - last_update_time (~.timestamp.Timestamp): + last_update_time (google.protobuf.timestamp_pb2.Timestamp): Last update time of this experiment. - experiment_length (~.duration.Duration): + experiment_length (google.protobuf.duration_pb2.Duration): Maximum number of days to run the experiment. - variants_history (Sequence[~.gcdc_experiment.VariantsHistory]): + variants_history (Sequence[google.cloud.dialogflowcx_v3beta1.types.VariantsHistory]): The history of updates to the experiment variants. """ @@ -94,7 +93,6 @@ class State(proto.Enum): class Definition(proto.Message): r"""Definition of the experiment. - Next ID: 3 Attributes: condition (str): @@ -103,7 +101,7 @@ class Definition(proto.Message): eligible. E.g. "query_input.language_code=en" See the `conditions reference `__. - version_variants (~.gcdc_experiment.VersionVariants): + version_variants (google.cloud.dialogflowcx_v3beta1.types.VersionVariants): The flow versions as the variants of this experiment. """ @@ -119,16 +117,16 @@ class Result(proto.Message): optimize and the confidence interval. Attributes: - version_metrics (Sequence[~.gcdc_experiment.Experiment.Result.VersionMetrics]): + version_metrics (Sequence[google.cloud.dialogflowcx_v3beta1.types.Experiment.Result.VersionMetrics]): Version variants and metrics. - last_update_time (~.timestamp.Timestamp): + last_update_time (google.protobuf.timestamp_pb2.Timestamp): The last time the experiment's stats data was updated. Will have default value if stats have never been computed for this experiment. """ class MetricType(proto.Enum): - r"""Types of metric for Dialogflow experiment.""" + r"""Types of ratio-based metric for Dialogflow experiment.""" METRIC_UNSPECIFIED = 0 CONTAINED_SESSION_NO_CALLBACK_RATE = 1 LIVE_AGENT_HANDOFF_RATE = 2 @@ -136,6 +134,13 @@ class MetricType(proto.Enum): ABANDONED_SESSION_RATE = 4 SESSION_END_RATE = 5 + class CountType(proto.Enum): + r"""types of count-based metric for Dialogflow experiment.""" + COUNT_TYPE_UNSPECIFIED = 0 + TOTAL_NO_MATCH_COUNT = 1 + TOTAL_TURN_COUNT = 2 + AVERAGE_TURN_COUNT = 3 + class ConfidenceInterval(proto.Message): r"""A confidence interval is a range of possible values for the experiment objective you are trying to measure. @@ -166,11 +171,17 @@ class Metric(proto.Message): r"""Metric and corresponding confidence intervals. Attributes: - type_ (~.gcdc_experiment.Experiment.Result.MetricType): - The type of the metric. + type_ (google.cloud.dialogflowcx_v3beta1.types.Experiment.Result.MetricType): + Ratio-based metric type. Only one of type or count_type is + specified in each Metric. + count_type (google.cloud.dialogflowcx_v3beta1.types.Experiment.Result.CountType): + Count-based metric type. Only one of type or count_type is + specified in each Metric. ratio (float): Ratio value of a metric. - confidence_interval (~.gcdc_experiment.Experiment.Result.ConfidenceInterval): + count (float): + Count value of a metric. + confidence_interval (google.cloud.dialogflowcx_v3beta1.types.Experiment.Result.ConfidenceInterval): The probability that the treatment is better than all other treatments in the experiment """ @@ -179,8 +190,14 @@ class Metric(proto.Message): proto.ENUM, number=1, enum="Experiment.Result.MetricType", ) + count_type = proto.Field( + proto.ENUM, number=5, enum="Experiment.Result.CountType", + ) + ratio = proto.Field(proto.DOUBLE, number=2, oneof="value") + count = proto.Field(proto.DOUBLE, number=4, oneof="value") + confidence_interval = proto.Field( proto.MESSAGE, number=3, message="Experiment.Result.ConfidenceInterval", ) @@ -194,7 +211,7 @@ class VersionMetrics(proto.Message): [Version][google.cloud.dialogflow.cx.v3beta1.Version]. Format: ``projects//locations//agents//flows//versions/``. - metrics (Sequence[~.gcdc_experiment.Experiment.Result.Metric]): + metrics (Sequence[google.cloud.dialogflowcx_v3beta1.types.Experiment.Result.Metric]): The metrics and corresponding confidence intervals in the inference result. session_count (int): @@ -253,7 +270,7 @@ class VersionVariants(proto.Message): r"""A list of flow version variants. Attributes: - variants (Sequence[~.gcdc_experiment.VersionVariants.Variant]): + variants (Sequence[google.cloud.dialogflowcx_v3beta1.types.VersionVariants.Variant]): A list of flow version variants. """ @@ -285,9 +302,9 @@ class VariantsHistory(proto.Message): r"""The history of variants update. Attributes: - version_variants (~.gcdc_experiment.VersionVariants): + version_variants (google.cloud.dialogflowcx_v3beta1.types.VersionVariants): The flow versions as the variants. - update_time (~.timestamp.Timestamp): + update_time (google.protobuf.timestamp_pb2.Timestamp): Update time of the variants. """ @@ -328,7 +345,7 @@ class ListExperimentsResponse(proto.Message): [Experiments.ListExperiments][google.cloud.dialogflow.cx.v3beta1.Experiments.ListExperiments]. Attributes: - experiments (Sequence[~.gcdc_experiment.Experiment]): + experiments (Sequence[google.cloud.dialogflowcx_v3beta1.types.Experiment]): The list of experiments. There will be a maximum number of items returned based on the page_size field in the request. The list may in some cases be empty or contain fewer entries @@ -375,7 +392,7 @@ class CreateExperimentRequest(proto.Message): [Environment][google.cloud.dialogflow.cx.v3beta1.Environment] for. Format: ``projects//locations//agents//environments/``. - experiment (~.gcdc_experiment.Experiment): + experiment (google.cloud.dialogflowcx_v3beta1.types.Experiment): Required. The experiment to create. """ @@ -389,9 +406,9 @@ class UpdateExperimentRequest(proto.Message): [Experiments.UpdateExperiment][google.cloud.dialogflow.cx.v3beta1.Experiments.UpdateExperiment]. Attributes: - experiment (~.gcdc_experiment.Experiment): + experiment (google.cloud.dialogflowcx_v3beta1.types.Experiment): Required. The experiment to update. - update_mask (~.field_mask.FieldMask): + update_mask (google.protobuf.field_mask_pb2.FieldMask): Required. The mask to control which fields get updated. """ diff --git a/google/cloud/dialogflowcx_v3beta1/types/flow.py b/google/cloud/dialogflowcx_v3beta1/types/flow.py index 7f97a338..4e11e7ac 100644 --- a/google/cloud/dialogflowcx_v3beta1/types/flow.py +++ b/google/cloud/dialogflowcx_v3beta1/types/flow.py @@ -19,7 +19,9 @@ from google.cloud.dialogflowcx_v3beta1.types import page +from google.cloud.dialogflowcx_v3beta1.types import validation_message from google.protobuf import field_mask_pb2 as field_mask # type: ignore +from google.protobuf import timestamp_pb2 as timestamp # type: ignore __protobuf__ = proto.module( @@ -34,6 +36,9 @@ "GetFlowRequest", "UpdateFlowRequest", "TrainFlowRequest", + "ValidateFlowRequest", + "GetFlowValidationResultRequest", + "FlowValidationResult", }, ) @@ -42,7 +47,7 @@ class NluSettings(proto.Message): r"""Settings related to NLU. Attributes: - model_type (~.gcdc_flow.NluSettings.ModelType): + model_type (google.cloud.dialogflowcx_v3beta1.types.NluSettings.ModelType): Indicates the type of NLU model. classification_threshold (float): To filter out false positive results and @@ -54,7 +59,7 @@ class NluSettings(proto.Message): The score values range from 0.0 (completely uncertain) to 1.0 (completely certain). If set to 0.0, the default of 0.3 is used. - model_training_mode (~.gcdc_flow.NluSettings.ModelTrainingMode): + model_training_mode (google.cloud.dialogflowcx_v3beta1.types.NluSettings.ModelTrainingMode): Indicates NLU model training mode. """ @@ -106,7 +111,7 @@ class Flow(proto.Message): The description of the flow. The maximum length is 500 characters. If exceeded, the request is rejected. - transition_routes (Sequence[~.page.TransitionRoute]): + transition_routes (Sequence[google.cloud.dialogflowcx_v3beta1.types.TransitionRoute]): A flow's transition routes serve two purposes: - They are responsible for matching the user's first @@ -125,7 +130,7 @@ class Flow(proto.Message): TransitionRoutes with intent specified are inherited by pages in the flow. - event_handlers (Sequence[~.page.EventHandler]): + event_handlers (Sequence[google.cloud.dialogflowcx_v3beta1.types.EventHandler]): A flow's event handlers serve two purposes: - They are responsible for handling events (e.g. no match, @@ -141,7 +146,7 @@ class Flow(proto.Message): these handlers are evaluated on a first-match basis. The first one that matches the event get executed, with the rest being ignored. - nlu_settings (~.gcdc_flow.NluSettings): + nlu_settings (google.cloud.dialogflowcx_v3beta1.types.NluSettings): NLU related settings of the flow. """ @@ -170,7 +175,7 @@ class CreateFlowRequest(proto.Message): parent (str): Required. The agent to create a flow for. Format: ``projects//locations//agents/``. - flow (~.gcdc_flow.Flow): + flow (google.cloud.dialogflowcx_v3beta1.types.Flow): Required. The flow to create. language_code (str): The language of the following fields in ``flow``: @@ -180,7 +185,7 @@ class CreateFlowRequest(proto.Message): If not specified, the agent's default language is used. `Many - languages `__ + languages `__ are supported. Note: languages must be enabled in the agent before they can be used. """ @@ -242,7 +247,7 @@ class ListFlowsRequest(proto.Message): If not specified, the agent's default language is used. `Many - languages `__ + languages `__ are supported. Note: languages must be enabled in the agent before they can be used. """ @@ -261,7 +266,7 @@ class ListFlowsResponse(proto.Message): [Flows.ListFlows][google.cloud.dialogflow.cx.v3beta1.Flows.ListFlows]. Attributes: - flows (Sequence[~.gcdc_flow.Flow]): + flows (Sequence[google.cloud.dialogflowcx_v3beta1.types.Flow]): The list of flows. There will be a maximum number of items returned based on the page_size field in the request. next_page_token (str): @@ -296,7 +301,7 @@ class GetFlowRequest(proto.Message): If not specified, the agent's default language is used. `Many - languages `__ + languages `__ are supported. Note: languages must be enabled in the agent before they can be used. """ @@ -311,9 +316,9 @@ class UpdateFlowRequest(proto.Message): [Flows.UpdateFlow][google.cloud.dialogflow.cx.v3beta1.Flows.UpdateFlow]. Attributes: - flow (~.gcdc_flow.Flow): + flow (google.cloud.dialogflowcx_v3beta1.types.Flow): Required. The flow to update. - update_mask (~.field_mask.FieldMask): + update_mask (google.protobuf.field_mask_pb2.FieldMask): Required. The mask to control which fields get updated. If ``update_mask`` is not specified, an error will be returned. language_code (str): @@ -324,7 +329,7 @@ class UpdateFlowRequest(proto.Message): If not specified, the agent's default language is used. `Many - languages `__ + languages `__ are supported. Note: languages must be enabled in the agent before they can be used. """ @@ -349,4 +354,63 @@ class TrainFlowRequest(proto.Message): name = proto.Field(proto.STRING, number=1) +class ValidateFlowRequest(proto.Message): + r"""The request message for + [Flows.ValidateFlow][google.cloud.dialogflow.cx.v3beta1.Flows.ValidateFlow]. + + Attributes: + name (str): + Required. The flow to validate. Format: + ``projects//locations//agents//flows/``. + language_code (str): + If not specified, the agent's default + language is used. + """ + + name = proto.Field(proto.STRING, number=1) + + language_code = proto.Field(proto.STRING, number=2) + + +class GetFlowValidationResultRequest(proto.Message): + r"""The request message for + [Flows.GetFlowValidationResult][google.cloud.dialogflow.cx.v3beta1.Flows.GetFlowValidationResult]. + + Attributes: + name (str): + Required. The flow name. Format: + ``projects//locations//agents//flows//validationResult``. + language_code (str): + If not specified, the agent's default + language is used. + """ + + name = proto.Field(proto.STRING, number=1) + + language_code = proto.Field(proto.STRING, number=2) + + +class FlowValidationResult(proto.Message): + r"""The response message for + [Flows.GetFlowValidationResult][google.cloud.dialogflow.cx.v3beta1.Flows.GetFlowValidationResult]. + + Attributes: + name (str): + The unique identifier of the flow validation result. Format: + ``projects//locations//agents//flows//validationResult``. + validation_messages (Sequence[google.cloud.dialogflowcx_v3beta1.types.ValidationMessage]): + Contains all validation messages. + update_time (google.protobuf.timestamp_pb2.Timestamp): + Last time the flow was validated. + """ + + name = proto.Field(proto.STRING, number=1) + + validation_messages = proto.RepeatedField( + proto.MESSAGE, number=2, message=validation_message.ValidationMessage, + ) + + update_time = proto.Field(proto.MESSAGE, number=3, message=timestamp.Timestamp,) + + __all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/google/cloud/dialogflowcx_v3beta1/types/fulfillment.py b/google/cloud/dialogflowcx_v3beta1/types/fulfillment.py index dc48a4d3..2f2a2323 100644 --- a/google/cloud/dialogflowcx_v3beta1/types/fulfillment.py +++ b/google/cloud/dialogflowcx_v3beta1/types/fulfillment.py @@ -49,7 +49,7 @@ class Fulfillment(proto.Message): or both. Attributes: - messages (Sequence[~.response_message.ResponseMessage]): + messages (Sequence[google.cloud.dialogflowcx_v3beta1.types.ResponseMessage]): The list of rich message responses to present to the user. webhook (str): @@ -59,10 +59,10 @@ class Fulfillment(proto.Message): The tag used by the webhook to identify which fulfillment is being called. This field is required if ``webhook`` is specified. - set_parameter_actions (Sequence[~.fulfillment.Fulfillment.SetParameterAction]): + set_parameter_actions (Sequence[google.cloud.dialogflowcx_v3beta1.types.Fulfillment.SetParameterAction]): Set parameter values before executing the webhook. - conditional_cases (Sequence[~.fulfillment.Fulfillment.ConditionalCases]): + conditional_cases (Sequence[google.cloud.dialogflowcx_v3beta1.types.Fulfillment.ConditionalCases]): Conditional cases for this fulfillment. """ @@ -72,7 +72,7 @@ class SetParameterAction(proto.Message): Attributes: parameter (str): Display name of the parameter. - value (~.struct.Value): + value (google.protobuf.struct_pb2.Value): The new value of the parameter. A null value clears the parameter. """ @@ -87,7 +87,7 @@ class ConditionalCases(proto.Message): all the rest ignored. Attributes: - cases (Sequence[~.fulfillment.Fulfillment.ConditionalCases.Case]): + cases (Sequence[google.cloud.dialogflowcx_v3beta1.types.Fulfillment.ConditionalCases.Case]): A list of cascading if-else conditions. """ @@ -105,7 +105,7 @@ class Case(proto.Message): See the `conditions reference `__. - case_content (Sequence[~.fulfillment.Fulfillment.ConditionalCases.Case.CaseContent]): + case_content (Sequence[google.cloud.dialogflowcx_v3beta1.types.Fulfillment.ConditionalCases.Case.CaseContent]): A list of case content. """ @@ -114,9 +114,9 @@ class CaseContent(proto.Message): this case. Attributes: - message (~.response_message.ResponseMessage): + message (google.cloud.dialogflowcx_v3beta1.types.ResponseMessage): Returned message. - additional_cases (~.fulfillment.Fulfillment.ConditionalCases): + additional_cases (google.cloud.dialogflowcx_v3beta1.types.Fulfillment.ConditionalCases): Additional cases to be evaluated. """ diff --git a/google/cloud/dialogflowcx_v3beta1/types/intent.py b/google/cloud/dialogflowcx_v3beta1/types/intent.py index 57175421..e68176a9 100644 --- a/google/cloud/dialogflowcx_v3beta1/types/intent.py +++ b/google/cloud/dialogflowcx_v3beta1/types/intent.py @@ -65,10 +65,10 @@ class Intent(proto.Message): display_name (str): Required. The human-readable name of the intent, unique within the agent. - training_phrases (Sequence[~.gcdc_intent.Intent.TrainingPhrase]): + training_phrases (Sequence[google.cloud.dialogflowcx_v3beta1.types.Intent.TrainingPhrase]): The collection of training phrases the agent is trained on to identify the intent. - parameters (Sequence[~.gcdc_intent.Intent.Parameter]): + parameters (Sequence[google.cloud.dialogflowcx_v3beta1.types.Intent.Parameter]): The collection of parameters associated with the intent. priority (int): @@ -90,7 +90,7 @@ class Intent(proto.Message): mistakenly matched, since training phrases assigned to fallback intents act as negative examples that triggers no-match event. - labels (Sequence[~.gcdc_intent.Intent.LabelsEntry]): + labels (Sequence[google.cloud.dialogflowcx_v3beta1.types.Intent.LabelsEntry]): Optional. The key/value metadata to label an intent. Labels can contain lowercase letters, digits and the symbols '-' and '_'. International characters are allowed, including @@ -120,7 +120,7 @@ class TrainingPhrase(proto.Message): id (str): Output only. The unique identifier of the training phrase. - parts (Sequence[~.gcdc_intent.Intent.TrainingPhrase.Part]): + parts (Sequence[google.cloud.dialogflowcx_v3beta1.types.Intent.TrainingPhrase.Part]): Required. The ordered list of training phrase parts. The parts are concatenated in order to form the training phrase. @@ -197,11 +197,13 @@ class Parameter(proto.Message): Indicates whether the parameter represents a list of values. redact (bool): - Indicates whether the parameter content is - logged in text and audio. If it is set to true, - the parameter content will be replaced to - parameter id in both request and response. The - default value is false. + Indicates whether the parameter content should be redacted + in log. If redaction is enabled, the parameter content will + be replaced by parameter name during logging. Note: the + parameter content is subject to redaction if either + parameter level redaction or [entity type level + redaction][google.cloud.dialogflow.cx.v3beta1.EntityType.redact] + is enabled. """ id = proto.Field(proto.STRING, number=1) @@ -247,10 +249,10 @@ class ListIntentsRequest(proto.Message): If not specified, the agent's default language is used. `Many - languages `__ + languages `__ are supported. Note: languages must be enabled in the agent before they can be used. - intent_view (~.gcdc_intent.IntentView): + intent_view (google.cloud.dialogflowcx_v3beta1.types.IntentView): The resource view to apply to the returned intent. page_size (int): @@ -277,7 +279,7 @@ class ListIntentsResponse(proto.Message): [Intents.ListIntents][google.cloud.dialogflow.cx.v3beta1.Intents.ListIntents]. Attributes: - intents (Sequence[~.gcdc_intent.Intent]): + intents (Sequence[google.cloud.dialogflowcx_v3beta1.types.Intent]): The list of intents. There will be a maximum number of items returned based on the page_size field in the request. next_page_token (str): @@ -311,7 +313,7 @@ class GetIntentRequest(proto.Message): If not specified, the agent's default language is used. `Many - languages `__ + languages `__ are supported. Note: languages must be enabled in the agent before they can be used. """ @@ -329,7 +331,7 @@ class CreateIntentRequest(proto.Message): parent (str): Required. The agent to create an intent for. Format: ``projects//locations//agents/``. - intent (~.gcdc_intent.Intent): + intent (google.cloud.dialogflowcx_v3beta1.types.Intent): Required. The intent to create. language_code (str): The language of the following fields in ``intent``: @@ -338,7 +340,7 @@ class CreateIntentRequest(proto.Message): If not specified, the agent's default language is used. `Many - languages `__ + languages `__ are supported. Note: languages must be enabled in the agent before they can be used. """ @@ -355,7 +357,7 @@ class UpdateIntentRequest(proto.Message): [Intents.UpdateIntent][google.cloud.dialogflow.cx.v3beta1.Intents.UpdateIntent]. Attributes: - intent (~.gcdc_intent.Intent): + intent (google.cloud.dialogflowcx_v3beta1.types.Intent): Required. The intent to update. language_code (str): The language of the following fields in ``intent``: @@ -364,10 +366,10 @@ class UpdateIntentRequest(proto.Message): If not specified, the agent's default language is used. `Many - languages `__ + languages `__ are supported. Note: languages must be enabled in the agent before they can be used. - update_mask (~.field_mask.FieldMask): + update_mask (google.protobuf.field_mask_pb2.FieldMask): The mask to control which fields get updated. If the mask is not present, all fields will be updated. diff --git a/google/cloud/dialogflowcx_v3beta1/types/page.py b/google/cloud/dialogflowcx_v3beta1/types/page.py index 857ff94f..7fb8315a 100644 --- a/google/cloud/dialogflowcx_v3beta1/types/page.py +++ b/google/cloud/dialogflowcx_v3beta1/types/page.py @@ -72,10 +72,10 @@ class Page(proto.Message): display_name (str): Required. The human-readable name of the page, unique within the agent. - entry_fulfillment (~.fulfillment.Fulfillment): + entry_fulfillment (google.cloud.dialogflowcx_v3beta1.types.Fulfillment): The fulfillment to call when the session is entering the page. - form (~.gcdc_page.Form): + form (google.cloud.dialogflowcx_v3beta1.types.Form): The form associated with the page, used for collecting parameters relevant to the page. transition_route_groups (Sequence[str]): @@ -94,7 +94,7 @@ class Page(proto.Message): takes precedence. Format:\ ``projects//locations//agents//flows//transitionRouteGroups/``. - transition_routes (Sequence[~.gcdc_page.TransitionRoute]): + transition_routes (Sequence[google.cloud.dialogflowcx_v3beta1.types.TransitionRoute]): A list of transitions for the transition rules of this page. They route the conversation to another page in the same flow, or another flow. @@ -105,11 +105,18 @@ class Page(proto.Message): - TransitionRoutes defined in the page with intent specified. - TransitionRoutes defined in the [transition route - groups][google.cloud.dialogflow.cx.v3beta1.Page.transition_route_groups]. + groups][google.cloud.dialogflow.cx.v3beta1.Page.transition_route_groups] + with intent specified. - TransitionRoutes defined in flow with intent specified. + - TransitionRoutes defined in the [transition route + groups][google.cloud.dialogflow.cx.v3beta1.Flow.transition_route_groups] + with intent specified. - TransitionRoutes defined in the page with only condition specified. - event_handlers (Sequence[~.gcdc_page.EventHandler]): + - TransitionRoutes defined in the [transition route + groups][google.cloud.dialogflow.cx.v3beta1.Page.transition_route_groups] + with only condition specified. + event_handlers (Sequence[google.cloud.dialogflowcx_v3beta1.types.EventHandler]): Handlers associated with the page to handle events such as webhook errors, no match or no input. @@ -146,7 +153,7 @@ class Form(proto.Message): [session][google.cloud.dialogflow.cx.v3beta1.SessionInfo.parameters]. Attributes: - parameters (Sequence[~.gcdc_page.Form.Parameter]): + parameters (Sequence[google.cloud.dialogflowcx_v3beta1.types.Form.Parameter]): Parameters to collect from the user. """ @@ -174,19 +181,21 @@ class Parameter(proto.Message): is_list (bool): Indicates whether the parameter represents a list of values. - fill_behavior (~.gcdc_page.Form.Parameter.FillBehavior): + fill_behavior (google.cloud.dialogflowcx_v3beta1.types.Form.Parameter.FillBehavior): Required. Defines fill behavior for the parameter. - default_value (~.struct.Value): + default_value (google.protobuf.struct_pb2.Value): The default value of an optional parameter. If the parameter is required, the default value will be ignored. redact (bool): - Indicates whether the parameter content is - logged in text and audio. If it is set to true, - the parameter content will be replaced to - parameter name in both request and response. The - default value is false. + Indicates whether the parameter content should be redacted + in log. If redaction is enabled, the parameter content will + be replaced by parameter name during logging. Note: the + parameter content is subject to redaction if either + parameter level redaction or [entity type level + redaction][google.cloud.dialogflow.cx.v3beta1.EntityType.redact] + is enabled. """ class FillBehavior(proto.Message): @@ -194,11 +203,11 @@ class FillBehavior(proto.Message): handled. Attributes: - initial_prompt_fulfillment (~.fulfillment.Fulfillment): + initial_prompt_fulfillment (google.cloud.dialogflowcx_v3beta1.types.Fulfillment): Required. The fulfillment to provide the initial prompt that the agent can present to the user in order to fill the parameter. - reprompt_event_handlers (Sequence[~.gcdc_page.EventHandler]): + reprompt_event_handlers (Sequence[google.cloud.dialogflowcx_v3beta1.types.EventHandler]): The handlers for parameter-level events, used to provide reprompt for the parameter or transition to a different page/flow. The supported events are: @@ -289,7 +298,7 @@ class EventHandler(proto.Message): event handler. event (str): Required. The name of the event to handle. - trigger_fulfillment (~.fulfillment.Fulfillment): + trigger_fulfillment (google.cloud.dialogflowcx_v3beta1.types.Fulfillment): The fulfillment to call when the event occurs. Handling webhook errors with a fulfillment enabled with webhook could cause @@ -360,7 +369,7 @@ class TransitionRoute(proto.Message): specified. When both ``intent`` and ``condition`` are specified, the transition can only happen when both are fulfilled. - trigger_fulfillment (~.fulfillment.Fulfillment): + trigger_fulfillment (google.cloud.dialogflowcx_v3beta1.types.Fulfillment): The fulfillment to call when the condition is satisfied. At least one of ``trigger_fulfillment`` and ``target`` must be specified. When both are defined, ``trigger_fulfillment`` is @@ -410,7 +419,7 @@ class ListPagesRequest(proto.Message): If not specified, the agent's default language is used. `Many - languages `__ + languages `__ are supported. Note: languages must be enabled in the agent before they can be used. page_size (int): @@ -435,7 +444,7 @@ class ListPagesResponse(proto.Message): [Pages.ListPages][google.cloud.dialogflow.cx.v3beta1.Pages.ListPages]. Attributes: - pages (Sequence[~.gcdc_page.Page]): + pages (Sequence[google.cloud.dialogflowcx_v3beta1.types.Page]): The list of pages. There will be a maximum number of items returned based on the page_size field in the request. next_page_token (str): @@ -475,7 +484,7 @@ class GetPageRequest(proto.Message): If not specified, the agent's default language is used. `Many - languages `__ + languages `__ are supported. Note: languages must be enabled in the agent before they can be used. """ @@ -493,7 +502,7 @@ class CreatePageRequest(proto.Message): parent (str): Required. The flow to create a page for. Format: ``projects//locations//agents//flows/``. - page (~.gcdc_page.Page): + page (google.cloud.dialogflowcx_v3beta1.types.Page): Required. The page to create. language_code (str): The language of the following fields in ``page``: @@ -508,7 +517,7 @@ class CreatePageRequest(proto.Message): If not specified, the agent's default language is used. `Many - languages `__ + languages `__ are supported. Note: languages must be enabled in the agent before they can be used. """ @@ -525,7 +534,7 @@ class UpdatePageRequest(proto.Message): [Pages.UpdatePage][google.cloud.dialogflow.cx.v3beta1.Pages.UpdatePage]. Attributes: - page (~.gcdc_page.Page): + page (google.cloud.dialogflowcx_v3beta1.types.Page): Required. The page to update. language_code (str): The language of the following fields in ``page``: @@ -540,10 +549,10 @@ class UpdatePageRequest(proto.Message): If not specified, the agent's default language is used. `Many - languages `__ + languages `__ are supported. Note: languages must be enabled in the agent before they can be used. - update_mask (~.field_mask.FieldMask): + update_mask (google.protobuf.field_mask_pb2.FieldMask): The mask to control which fields get updated. If the mask is not present, all fields will be updated. diff --git a/google/cloud/dialogflowcx_v3beta1/types/response_message.py b/google/cloud/dialogflowcx_v3beta1/types/response_message.py index ad0e2726..6bdc8cae 100644 --- a/google/cloud/dialogflowcx_v3beta1/types/response_message.py +++ b/google/cloud/dialogflowcx_v3beta1/types/response_message.py @@ -49,34 +49,36 @@ class ResponseMessage(proto.Message): is heard. Attributes: - text (~.response_message.ResponseMessage.Text): + text (google.cloud.dialogflowcx_v3beta1.types.ResponseMessage.Text): Returns a text response. - payload (~.struct.Struct): + payload (google.protobuf.struct_pb2.Struct): Returns a response containing a custom, platform-specific payload. - conversation_success (~.response_message.ResponseMessage.ConversationSuccess): + conversation_success (google.cloud.dialogflowcx_v3beta1.types.ResponseMessage.ConversationSuccess): Indicates that the conversation succeeded. - output_audio_text (~.response_message.ResponseMessage.OutputAudioText): + output_audio_text (google.cloud.dialogflowcx_v3beta1.types.ResponseMessage.OutputAudioText): A text or ssml response that is preferentially used for TTS output audio synthesis, as described in the comment on the ResponseMessage message. - live_agent_handoff (~.response_message.ResponseMessage.LiveAgentHandoff): + live_agent_handoff (google.cloud.dialogflowcx_v3beta1.types.ResponseMessage.LiveAgentHandoff): Hands off conversation to a human agent. - end_interaction (~.response_message.ResponseMessage.EndInteraction): + end_interaction (google.cloud.dialogflowcx_v3beta1.types.ResponseMessage.EndInteraction): Output only. A signal that indicates the interaction with the Dialogflow agent has ended. This message is generated by Dialogflow only when the conversation reaches - ``END_SESSION`` or ``END_PAGE`` page. It is not supposed to - be defined by the user. It's guaranteed that there is at - most one such message in each response. - play_audio (~.response_message.ResponseMessage.PlayAudio): + ``END_SESSION`` page. It is not supposed to be defined by + the user. + + It's guaranteed that there is at most one such message in + each response. + play_audio (google.cloud.dialogflowcx_v3beta1.types.ResponseMessage.PlayAudio): Signal that the client should play an audio clip hosted at a client-specific URI. Dialogflow uses this to construct [mixed_audio][google.cloud.dialogflow.cx.v3beta1.ResponseMessage.mixed_audio]. However, Dialogflow itself does not try to read or process the URI in any way. - mixed_audio (~.response_message.ResponseMessage.MixedAudio): + mixed_audio (google.cloud.dialogflowcx_v3beta1.types.ResponseMessage.MixedAudio): Output only. An audio response message composed of both the synthesized Dialogflow agent responses and responses defined via @@ -121,7 +123,7 @@ class LiveAgentHandoff(proto.Message): can only be handled by a human. Attributes: - metadata (~.struct.Struct): + metadata (google.protobuf.struct_pb2.Struct): Custom metadata for your handoff procedure. Dialogflow doesn't impose any structure on this. """ @@ -149,7 +151,7 @@ class ConversationSuccess(proto.Message): customer issue. Attributes: - metadata (~.struct.Struct): + metadata (google.protobuf.struct_pb2.Struct): Custom metadata. Dialogflow doesn't impose any structure on this. """ @@ -180,6 +182,32 @@ class OutputAudioText(proto.Message): allow_playback_interruption = proto.Field(proto.BOOL, number=3) + class EndInteraction(proto.Message): + r"""Indicates that interaction with the Dialogflow agent has + ended. This message is generated by Dialogflow only and not + supposed to be defined by the user. + """ + + class PlayAudio(proto.Message): + r"""Specifies an audio clip to be played by the client as part of + the response. + + Attributes: + audio_uri (str): + Required. URI of the audio clip. Dialogflow + does not impose any validation on this value. It + is specific to the client that reads it. + allow_playback_interruption (bool): + Output only. Whether the playback of this + message can be interrupted by the end user's + speech and the client can then starts the next + Dialogflow request. + """ + + audio_uri = proto.Field(proto.STRING, number=1) + + allow_playback_interruption = proto.Field(proto.BOOL, number=2) + class MixedAudio(proto.Message): r"""Represents an audio message that is composed of both segments synthesized from the Dialogflow agent prompts and ones hosted @@ -190,7 +218,7 @@ class MixedAudio(proto.Message): defined by the user. Attributes: - segments (Sequence[~.response_message.ResponseMessage.MixedAudio.Segment]): + segments (Sequence[google.cloud.dialogflowcx_v3beta1.types.ResponseMessage.MixedAudio.Segment]): Segments this audio response is composed of. """ @@ -223,32 +251,6 @@ class Segment(proto.Message): proto.MESSAGE, number=1, message="ResponseMessage.MixedAudio.Segment", ) - class EndInteraction(proto.Message): - r"""Indicates that interaction with the Dialogflow agent has - ended. This message is generated by Dialogflow only and not - supposed to be defined by the user. - """ - - class PlayAudio(proto.Message): - r"""Specifies an audio clip to be played by the client as part of - the response. - - Attributes: - audio_uri (str): - Required. URI of the audio clip. Dialogflow - does not impose any validation on this value. It - is specific to the client that reads it. - allow_playback_interruption (bool): - Output only. Whether the playback of this - message can be interrupted by the end user's - speech and the client can then starts the next - Dialogflow request. - """ - - audio_uri = proto.Field(proto.STRING, number=1) - - allow_playback_interruption = proto.Field(proto.BOOL, number=2) - text = proto.Field(proto.MESSAGE, number=1, oneof="message", message=Text,) payload = proto.Field( diff --git a/google/cloud/dialogflowcx_v3beta1/types/security_settings.py b/google/cloud/dialogflowcx_v3beta1/types/security_settings.py index 41d00dbf..2a991f64 100644 --- a/google/cloud/dialogflowcx_v3beta1/types/security_settings.py +++ b/google/cloud/dialogflowcx_v3beta1/types/security_settings.py @@ -53,10 +53,10 @@ class UpdateSecuritySettingsRequest(proto.Message): [SecuritySettingsService.UpdateSecuritySettings][google.cloud.dialogflow.cx.v3beta1.SecuritySettingsService.UpdateSecuritySettings]. Attributes: - security_settings (~.gcdc_security_settings.SecuritySettings): + security_settings (google.cloud.dialogflowcx_v3beta1.types.SecuritySettings): Required. [SecuritySettings] object that contains values for each of the fields to update. - update_mask (~.field_mask.FieldMask): + update_mask (google.protobuf.field_mask_pb2.FieldMask): Required. The mask to control which fields get updated. If the mask is not present, all fields will be updated. @@ -95,7 +95,7 @@ class ListSecuritySettingsResponse(proto.Message): r"""The response message for [SecuritySettings.ListSecuritySettings][]. Attributes: - security_settings (Sequence[~.gcdc_security_settings.SecuritySettings]): + security_settings (Sequence[google.cloud.dialogflowcx_v3beta1.types.SecuritySettings]): The list of security settings. next_page_token (str): Token to retrieve the next page of results, @@ -123,7 +123,7 @@ class CreateSecuritySettingsRequest(proto.Message): [SecuritySettings][google.cloud.dialogflow.cx.v3beta1.SecuritySettings] for. Format: ``projects//locations/``. - security_settings (~.gcdc_security_settings.SecuritySettings): + security_settings (google.cloud.dialogflowcx_v3beta1.types.SecuritySettings): Required. The security settings to create. """ @@ -161,9 +161,9 @@ class SecuritySettings(proto.Message): display_name (str): Required. The human-readable name of the security settings, unique within the location. - redaction_strategy (~.gcdc_security_settings.SecuritySettings.RedactionStrategy): + redaction_strategy (google.cloud.dialogflowcx_v3beta1.types.SecuritySettings.RedactionStrategy): Strategy that defines how we do redaction. - redaction_scope (~.gcdc_security_settings.SecuritySettings.RedactionScope): + redaction_scope (google.cloud.dialogflowcx_v3beta1.types.SecuritySettings.RedactionScope): Defines on what data we apply redaction. Note that we don't redact data to which we don't have access, e.g., Stackdriver logs. @@ -183,7 +183,7 @@ class SecuritySettings(proto.Message): higher than that has no effect. A missing value or setting to 0 also means we use Dialogflow's default TTL. - purge_data_types (Sequence[~.gcdc_security_settings.SecuritySettings.PurgeDataType]): + purge_data_types (Sequence[google.cloud.dialogflowcx_v3beta1.types.SecuritySettings.PurgeDataType]): List of types of data to remove when retention settings triggers purge. """ diff --git a/google/cloud/dialogflowcx_v3beta1/types/session.py b/google/cloud/dialogflowcx_v3beta1/types/session.py index dbb8de0c..411fe8ee 100644 --- a/google/cloud/dialogflowcx_v3beta1/types/session.py +++ b/google/cloud/dialogflowcx_v3beta1/types/session.py @@ -77,11 +77,11 @@ class DetectIntentRequest(proto.Message): Note: Always use agent versions for production traffic. See `Versions and environments `__. - query_params (~.gcdc_session.QueryParameters): + query_params (google.cloud.dialogflowcx_v3beta1.types.QueryParameters): The parameters of this query. - query_input (~.gcdc_session.QueryInput): + query_input (google.cloud.dialogflowcx_v3beta1.types.QueryInput): Required. The input specification. - output_audio_config (~.audio_config.OutputAudioConfig): + output_audio_config (google.cloud.dialogflowcx_v3beta1.types.OutputAudioConfig): Instructs the speech synthesizer how to generate the output audio. """ @@ -106,7 +106,7 @@ class DetectIntentResponse(proto.Message): response. It can be used to locate a response in the training example set or for reporting issues. - query_result (~.gcdc_session.QueryResult): + query_result (google.cloud.dialogflowcx_v3beta1.types.QueryResult): The result of the conversational query. output_audio (bytes): The audio data bytes encoded as specified in the request. @@ -121,7 +121,7 @@ class DetectIntentResponse(proto.Message): In some scenarios, multiple output audio fields may be present in the response structure. In these cases, only the top-most-level audio output has content. - output_audio_config (~.audio_config.OutputAudioConfig): + output_audio_config (google.cloud.dialogflowcx_v3beta1.types.OutputAudioConfig): The config used by the speech synthesizer to generate the output audio. """ @@ -193,11 +193,11 @@ class StreamingDetectIntentRequest(proto.Message): Note: Always use agent versions for production traffic. See `Versions and environments `__. - query_params (~.gcdc_session.QueryParameters): + query_params (google.cloud.dialogflowcx_v3beta1.types.QueryParameters): The parameters of this query. - query_input (~.gcdc_session.QueryInput): + query_input (google.cloud.dialogflowcx_v3beta1.types.QueryInput): Required. The input specification. - output_audio_config (~.audio_config.OutputAudioConfig): + output_audio_config (google.cloud.dialogflowcx_v3beta1.types.OutputAudioConfig): Instructs the speech synthesizer how to generate the output audio. """ @@ -228,9 +228,9 @@ class StreamingDetectIntentResponse(proto.Message): 2. The last message contains ``detect_intent_response``. Attributes: - recognition_result (~.gcdc_session.StreamingRecognitionResult): + recognition_result (google.cloud.dialogflowcx_v3beta1.types.StreamingRecognitionResult): The result of speech recognition. - detect_intent_response (~.gcdc_session.DetectIntentResponse): + detect_intent_response (google.cloud.dialogflowcx_v3beta1.types.DetectIntentResponse): The response from detect intent. """ @@ -277,7 +277,7 @@ class StreamingRecognitionResult(proto.Message): - for ``END_OF_SINGLE_UTTERANCE``: only ``message_type``. Attributes: - message_type (~.gcdc_session.StreamingRecognitionResult.MessageType): + message_type (google.cloud.dialogflowcx_v3beta1.types.StreamingRecognitionResult.MessageType): Type of the result message. transcript (str): Transcript text representing the words that the user spoke. @@ -309,13 +309,13 @@ class StreamingRecognitionResult(proto.Message): ``is_final = false``. - Otherwise, the value is in (0.0, 1.0] where 0.0 means completely unstable and 1.0 means completely stable. - speech_word_info (Sequence[~.audio_config.SpeechWordInfo]): + speech_word_info (Sequence[google.cloud.dialogflowcx_v3beta1.types.SpeechWordInfo]): Word-specific information for the words recognized by Speech in [transcript][google.cloud.dialogflow.cx.v3beta1.StreamingRecognitionResult.transcript]. Populated if and only if ``message_type`` = ``TRANSCRIPT`` and [InputAudioConfig.enable_word_info] is set. - speech_end_offset (~.duration.Duration): + speech_end_offset (google.protobuf.duration_pb2.Duration): Time offset of the end of this Speech recognition result relative to the beginning of the audio. Only populated for ``message_type`` = ``TRANSCRIPT``. @@ -353,19 +353,19 @@ class QueryParameters(proto.Message): zone database `__, e.g., America/New_York, Europe/Paris. If not provided, the time zone specified in the agent is used. - geo_location (~.latlng.LatLng): + geo_location (google.type.latlng_pb2.LatLng): The geo location of this conversational query. - session_entity_types (Sequence[~.session_entity_type.SessionEntityType]): + session_entity_types (Sequence[google.cloud.dialogflowcx_v3beta1.types.SessionEntityType]): Additional session entity types to replace or extend developer entity types with. The entity synonyms apply to all languages and persist for the session of this query. - payload (~.struct.Struct): + payload (google.protobuf.struct_pb2.Struct): This field can be used to pass custom data into the webhook associated with the agent. Arbitrary JSON objects are supported. - parameters (~.struct.Struct): + parameters (google.protobuf.struct_pb2.Struct): Additional parameters to be put into [session parameters][SessionInfo.parameters]. To remove a parameter from the session, clients should explicitly set the @@ -390,11 +390,14 @@ class QueryParameters(proto.Message): from composite entity property names to property values - Else: parameter value + disable_webhook (bool): + Whether to disable webhook calls for this + request. analyze_query_text_sentiment (bool): Configures whether sentiment analysis should be performed. If not provided, sentiment analysis is not performed. - webhook_headers (Sequence[~.gcdc_session.QueryParameters.WebhookHeadersEntry]): + webhook_headers (Sequence[google.cloud.dialogflowcx_v3beta1.types.QueryParameters.WebhookHeadersEntry]): This field can be used to pass HTTP headers for a webhook call. These headers will be sent to webhook along with the headers that have been @@ -421,6 +424,8 @@ class QueryParameters(proto.Message): parameters = proto.Field(proto.MESSAGE, number=5, message=struct.Struct,) + disable_webhook = proto.Field(proto.BOOL, number=7) + analyze_query_text_sentiment = proto.Field(proto.BOOL, number=8) webhook_headers = proto.MapField(proto.STRING, proto.STRING, number=10) @@ -436,20 +441,20 @@ class QueryInput(proto.Message): 4. An event to be triggered. Attributes: - text (~.gcdc_session.TextInput): + text (google.cloud.dialogflowcx_v3beta1.types.TextInput): The natural language text to be processed. - intent (~.gcdc_session.IntentInput): + intent (google.cloud.dialogflowcx_v3beta1.types.IntentInput): The intent to be triggered. - audio (~.gcdc_session.AudioInput): + audio (google.cloud.dialogflowcx_v3beta1.types.AudioInput): The natural language speech audio to be processed. - event (~.gcdc_session.EventInput): + event (google.cloud.dialogflowcx_v3beta1.types.EventInput): The event to be triggered. - dtmf (~.gcdc_session.DtmfInput): + dtmf (google.cloud.dialogflowcx_v3beta1.types.DtmfInput): The DTMF event to be handled. language_code (str): Required. The language of the input. See `Language - Support `__ + Support `__ for a list of the currently supported language codes. Note that queries in the same session do not necessarily need to specify the same language. @@ -494,9 +499,9 @@ class QueryResult(proto.Message): language_code (str): The language that was triggered during intent detection. See `Language - Support `__ + Support `__ for a list of the currently supported language codes. - parameters (~.struct.Struct): + parameters (google.protobuf.struct_pb2.Struct): The collected [session parameters][google.cloud.dialogflow.cx.v3beta1.SessionInfo.parameters]. @@ -519,25 +524,25 @@ class QueryResult(proto.Message): from composite entity property names to property values - Else: parameter value - response_messages (Sequence[~.response_message.ResponseMessage]): + response_messages (Sequence[google.cloud.dialogflowcx_v3beta1.types.ResponseMessage]): The list of rich messages returned to the client. Responses vary from simple text messages to more sophisticated, structured payloads used to drive complex logic. - webhook_statuses (Sequence[~.status.Status]): + webhook_statuses (Sequence[google.rpc.status_pb2.Status]): The list of webhook call status in the order of call sequence. - webhook_payloads (Sequence[~.struct.Struct]): + webhook_payloads (Sequence[google.protobuf.struct_pb2.Struct]): The list of webhook payload in [WebhookResponse.payload][google.cloud.dialogflow.cx.v3beta1.WebhookResponse.payload], in the order of call sequence. If some webhook call fails or doesn't return any payload, an empty ``Struct`` would be used instead. - current_page (~.page.Page): + current_page (google.cloud.dialogflowcx_v3beta1.types.Page): The current [Page][google.cloud.dialogflow.cx.v3beta1.Page]. Some, not all fields are filled in this message, including but not limited to ``name`` and ``display_name``. - intent (~.gcdc_intent.Intent): + intent (google.cloud.dialogflowcx_v3beta1.types.Intent): The [Intent][google.cloud.dialogflow.cx.v3beta1.Intent] that matched the conversational query. Some, not all fields are filled in this message, including but not limited to: @@ -555,15 +560,15 @@ class QueryResult(proto.Message): in implementation. This field is deprecated, please use [QueryResult.match][google.cloud.dialogflow.cx.v3beta1.QueryResult.match] instead. - match (~.gcdc_session.Match): + match (google.cloud.dialogflowcx_v3beta1.types.Match): Intent match result, could be an intent or an event. - diagnostic_info (~.struct.Struct): + diagnostic_info (google.protobuf.struct_pb2.Struct): The free-form diagnostic info. For example, this field could contain webhook call latency. The string keys of the Struct's fields map can change without notice. - sentiment_analysis_result (~.gcdc_session.SentimentAnalysisResult): + sentiment_analysis_result (google.cloud.dialogflowcx_v3beta1.types.SentimentAnalysisResult): The sentiment analyss result, which depends on [``analyze_query_text_sentiment``] [google.cloud.dialogflow.cx.v3beta1.QueryParameters.analyze_query_text_sentiment], @@ -639,7 +644,7 @@ class AudioInput(proto.Message): r"""Represents the natural speech audio to be processed. Attributes: - config (~.audio_config.InputAudioConfig): + config (google.cloud.dialogflowcx_v3beta1.types.InputAudioConfig): Required. Instructs the speech recognizer how to process the speech audio. audio (bytes): @@ -692,7 +697,7 @@ class Match(proto.Message): r"""Represents one match result of [MatchIntent][]. Attributes: - intent (~.gcdc_intent.Intent): + intent (google.cloud.dialogflowcx_v3beta1.types.Intent): The [Intent][google.cloud.dialogflow.cx.v3beta1.Intent] that matched the query. Some, not all fields are filled in this message, including but not limited to: ``name`` and @@ -703,7 +708,7 @@ class Match(proto.Message): The event that matched the query. Only filled for [``EVENT``][google.cloud.dialogflow.cx.v3beta1.Match.MatchType] match type. - parameters (~.struct.Struct): + parameters (google.protobuf.struct_pb2.Struct): The collection of parameters extracted from the query. Depending on your protocol or client library @@ -728,7 +733,7 @@ class Match(proto.Message): MatchIntent. This value can be different from original input sent in request because of spelling correction or other processing. - match_type (~.gcdc_session.Match.MatchType): + match_type (google.cloud.dialogflowcx_v3beta1.types.Match.MatchType): Type of this [Match][google.cloud.dialogflow.cx.v3beta1.Match]. confidence (float): @@ -784,9 +789,9 @@ class MatchIntentRequest(proto.Message): For more information, see the `sessions guide `__. - query_params (~.gcdc_session.QueryParameters): + query_params (google.cloud.dialogflowcx_v3beta1.types.QueryParameters): The parameters of this query. - query_input (~.gcdc_session.QueryInput): + query_input (google.cloud.dialogflowcx_v3beta1.types.QueryInput): Required. The input specification. """ @@ -820,11 +825,11 @@ class MatchIntentResponse(proto.Message): If an [event][google.cloud.dialogflow.cx.v3beta1.EventInput] was provided as input, this field will contain a copy of the event name. - matches (Sequence[~.gcdc_session.Match]): + matches (Sequence[google.cloud.dialogflowcx_v3beta1.types.Match]): Match results, if more than one, ordered descendingly by the confidence we have that the particular intent matches the query. - current_page (~.page.Page): + current_page (google.cloud.dialogflowcx_v3beta1.types.Page): The current [Page][google.cloud.dialogflow.cx.v3beta1.Page]. Some, not all fields are filled in this message, including but not limited to ``name`` and ``display_name``. @@ -847,12 +852,12 @@ class FulfillIntentRequest(proto.Message): r"""Request of [FulfillIntent][] Attributes: - match_intent_request (~.gcdc_session.MatchIntentRequest): + match_intent_request (google.cloud.dialogflowcx_v3beta1.types.MatchIntentRequest): Must be same as the corresponding MatchIntent request, otherwise the behavior is undefined. - match (~.gcdc_session.Match): + match (google.cloud.dialogflowcx_v3beta1.types.Match): The matched intent/event to fulfill. - output_audio_config (~.audio_config.OutputAudioConfig): + output_audio_config (google.cloud.dialogflowcx_v3beta1.types.OutputAudioConfig): Instructs the speech synthesizer how to generate output audio. """ @@ -877,7 +882,7 @@ class FulfillIntentResponse(proto.Message): response. It can be used to locate a response in the training example set or for reporting issues. - query_result (~.gcdc_session.QueryResult): + query_result (google.cloud.dialogflowcx_v3beta1.types.QueryResult): The result of the conversational query. output_audio (bytes): The audio data bytes encoded as specified in the request. @@ -892,7 +897,7 @@ class FulfillIntentResponse(proto.Message): In some scenarios, multiple output audio fields may be present in the response structure. In these cases, only the top-most-level audio output has content. - output_audio_config (~.audio_config.OutputAudioConfig): + output_audio_config (google.cloud.dialogflowcx_v3beta1.types.OutputAudioConfig): The config used by the speech synthesizer to generate the output audio. """ diff --git a/google/cloud/dialogflowcx_v3beta1/types/session_entity_type.py b/google/cloud/dialogflowcx_v3beta1/types/session_entity_type.py index b3f7da3a..479d330b 100644 --- a/google/cloud/dialogflowcx_v3beta1/types/session_entity_type.py +++ b/google/cloud/dialogflowcx_v3beta1/types/session_entity_type.py @@ -62,11 +62,11 @@ class SessionEntityType(proto.Message): ``projects//locations//agents//environments//sessions//entityTypes/``. If ``Environment ID`` is not specified, we assume default 'draft' environment. - entity_override_mode (~.gcdc_session_entity_type.SessionEntityType.EntityOverrideMode): + entity_override_mode (google.cloud.dialogflowcx_v3beta1.types.SessionEntityType.EntityOverrideMode): Required. Indicates whether the additional data should override or supplement the custom entity type definition. - entities (Sequence[~.entity_type.EntityType.Entity]): + entities (Sequence[google.cloud.dialogflowcx_v3beta1.types.EntityType.Entity]): Required. The collection of entities to override or supplement the custom entity type. """ @@ -119,7 +119,7 @@ class ListSessionEntityTypesResponse(proto.Message): [SessionEntityTypes.ListSessionEntityTypes][google.cloud.dialogflow.cx.v3beta1.SessionEntityTypes.ListSessionEntityTypes]. Attributes: - session_entity_types (Sequence[~.gcdc_session_entity_type.SessionEntityType]): + session_entity_types (Sequence[google.cloud.dialogflowcx_v3beta1.types.SessionEntityType]): The list of session entity types. There will be a maximum number of items returned based on the page_size field in the request. @@ -170,7 +170,7 @@ class CreateSessionEntityTypeRequest(proto.Message): ``projects//locations//agents//environments//sessions/``. If ``Environment ID`` is not specified, we assume default 'draft' environment. - session_entity_type (~.gcdc_session_entity_type.SessionEntityType): + session_entity_type (google.cloud.dialogflowcx_v3beta1.types.SessionEntityType): Required. The session entity type to create. """ @@ -186,14 +186,14 @@ class UpdateSessionEntityTypeRequest(proto.Message): [SessionEntityTypes.UpdateSessionEntityType][google.cloud.dialogflow.cx.v3beta1.SessionEntityTypes.UpdateSessionEntityType]. Attributes: - session_entity_type (~.gcdc_session_entity_type.SessionEntityType): + session_entity_type (google.cloud.dialogflowcx_v3beta1.types.SessionEntityType): Required. The session entity type to update. Format: ``projects//locations//agents//sessions//entityTypes/`` or ``projects//locations//agents//environments//sessions//entityTypes/``. If ``Environment ID`` is not specified, we assume default 'draft' environment. - update_mask (~.field_mask.FieldMask): + update_mask (google.protobuf.field_mask_pb2.FieldMask): The mask to control which fields get updated. """ diff --git a/google/cloud/dialogflowcx_v3beta1/types/test_case.py b/google/cloud/dialogflowcx_v3beta1/types/test_case.py new file mode 100644 index 00000000..7afdde83 --- /dev/null +++ b/google/cloud/dialogflowcx_v3beta1/types/test_case.py @@ -0,0 +1,1003 @@ +# -*- 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. +# + +import proto # type: ignore + + +from google.cloud.dialogflowcx_v3beta1.types import flow as gcdc_flow +from google.cloud.dialogflowcx_v3beta1.types import intent as gcdc_intent +from google.cloud.dialogflowcx_v3beta1.types import page as gcdc_page +from google.cloud.dialogflowcx_v3beta1.types import response_message +from google.cloud.dialogflowcx_v3beta1.types import session +from google.cloud.dialogflowcx_v3beta1.types import transition_route_group +from google.protobuf import field_mask_pb2 as field_mask # type: ignore +from google.protobuf import struct_pb2 as struct # type: ignore +from google.protobuf import timestamp_pb2 as timestamp # type: ignore +from google.rpc import status_pb2 as gr_status # type: ignore + + +__protobuf__ = proto.module( + package="google.cloud.dialogflow.cx.v3beta1", + manifest={ + "TestResult", + "TestCase", + "TestCaseResult", + "TestConfig", + "ConversationTurn", + "TestRunDifference", + "TransitionCoverage", + "TransitionRouteGroupCoverage", + "IntentCoverage", + "CalculateCoverageRequest", + "CalculateCoverageResponse", + "ListTestCasesRequest", + "ListTestCasesResponse", + "BatchDeleteTestCasesRequest", + "CreateTestCaseRequest", + "UpdateTestCaseRequest", + "GetTestCaseRequest", + "RunTestCaseRequest", + "RunTestCaseResponse", + "RunTestCaseMetadata", + "BatchRunTestCasesRequest", + "BatchRunTestCasesResponse", + "BatchRunTestCasesMetadata", + "TestError", + "ImportTestCasesRequest", + "ImportTestCasesResponse", + "ImportTestCasesMetadata", + "TestCaseError", + "ExportTestCasesRequest", + "ExportTestCasesResponse", + "ExportTestCasesMetadata", + "ListTestCaseResultsRequest", + "ListTestCaseResultsResponse", + }, +) + + +class TestResult(proto.Enum): + r"""The test result for a test case and an agent environment.""" + TEST_RESULT_UNSPECIFIED = 0 + PASSED = 1 + FAILED = 2 + + +class TestCase(proto.Message): + r"""Represents a test case. + + Attributes: + name (str): + The unique identifier of the test case. + [TestCases.CreateTestCase][google.cloud.dialogflow.cx.v3beta1.TestCases.CreateTestCase] + will populate the name automatically. Otherwise use format: + ``projects//locations//agents/ /testCases/``. + tags (Sequence[str]): + Tags are short descriptions that users may + apply to test cases for organizational and + filtering purposes. Each tag should start with + "#" and has a limit of 30 characters. + display_name (str): + Required. The human-readable name of the test + case, unique within the agent. Limit of 200 + characters. + notes (str): + Additional freeform notes about the test + case. Limit of 400 characters. + test_config (google.cloud.dialogflowcx_v3beta1.types.TestConfig): + Config for the test case. + test_case_conversation_turns (Sequence[google.cloud.dialogflowcx_v3beta1.types.ConversationTurn]): + The conversation turns uttered when the test + case was created, in chronological order. These + include the canonical set of agent utterances + that should occur when the agent is working + properly. + creation_time (google.protobuf.timestamp_pb2.Timestamp): + Output only. When the test was created. + last_test_result (google.cloud.dialogflowcx_v3beta1.types.TestCaseResult): + The latest test result. + """ + + name = proto.Field(proto.STRING, number=1) + + tags = proto.RepeatedField(proto.STRING, number=2) + + display_name = proto.Field(proto.STRING, number=3) + + notes = proto.Field(proto.STRING, number=4) + + test_config = proto.Field(proto.MESSAGE, number=13, message="TestConfig",) + + test_case_conversation_turns = proto.RepeatedField( + proto.MESSAGE, number=5, message="ConversationTurn", + ) + + creation_time = proto.Field(proto.MESSAGE, number=10, message=timestamp.Timestamp,) + + last_test_result = proto.Field(proto.MESSAGE, number=12, message="TestCaseResult",) + + +class TestCaseResult(proto.Message): + r"""Represents a result from running a test case in an agent + environment. + + Attributes: + name (str): + The resource name for the test case result. Format: + ``projects//locations//agents//testCases/ /results/``. + environment (str): + Environment where the test was run. If not + set, it indicates the draft environment. + conversation_turns (Sequence[google.cloud.dialogflowcx_v3beta1.types.ConversationTurn]): + The conversation turns uttered during the + test case replay in chronological order. + test_result (google.cloud.dialogflowcx_v3beta1.types.TestResult): + Whether the test case passed in the agent + environment. + test_time (google.protobuf.timestamp_pb2.Timestamp): + The time that the test was run. + """ + + name = proto.Field(proto.STRING, number=1) + + environment = proto.Field(proto.STRING, number=2) + + conversation_turns = proto.RepeatedField( + proto.MESSAGE, number=3, message="ConversationTurn", + ) + + test_result = proto.Field(proto.ENUM, number=4, enum="TestResult",) + + test_time = proto.Field(proto.MESSAGE, number=5, message=timestamp.Timestamp,) + + +class TestConfig(proto.Message): + r"""Represents configurations for a test case. + + Attributes: + tracking_parameters (Sequence[str]): + Session parameters to be compared when + calculating differences. + flow (str): + Flow name. If not set, default start flow is assumed. + Format: + ``projects//locations//agents//flows/``. + """ + + tracking_parameters = proto.RepeatedField(proto.STRING, number=1) + + flow = proto.Field(proto.STRING, number=2) + + +class ConversationTurn(proto.Message): + r"""One interaction between a human and virtual agent. The human + provides some input and the virtual agent provides a response. + + Attributes: + user_input (google.cloud.dialogflowcx_v3beta1.types.ConversationTurn.UserInput): + The user input. + virtual_agent_output (google.cloud.dialogflowcx_v3beta1.types.ConversationTurn.VirtualAgentOutput): + The virtual agent output. + """ + + class UserInput(proto.Message): + r"""The input from the human user. + + Attributes: + input_ (google.cloud.dialogflowcx_v3beta1.types.QueryInput): + Supports [text + input][google.cloud.dialogflow.cx.v3beta1.QueryInput.text], + [event + input][google.cloud.dialogflow.cx.v3beta1.QueryInput.event], + [dtmf + input][google.cloud.dialogflow.cx.v3beta1.QueryInput.dtmf] + in the test case. + injected_parameters (google.protobuf.struct_pb2.Struct): + Parameters that need to be injected into the + conversation during intent detection. + is_webhook_enabled (bool): + If webhooks should be allowed to trigger in + response to the user utterance. Often if + parameters are injected, webhooks should not be + enabled. + """ + + input_ = proto.Field(proto.MESSAGE, number=5, message=session.QueryInput,) + + injected_parameters = proto.Field( + proto.MESSAGE, number=2, message=struct.Struct, + ) + + is_webhook_enabled = proto.Field(proto.BOOL, number=3) + + class VirtualAgentOutput(proto.Message): + r"""The output from the virtual agent. + + Attributes: + session_parameters (google.protobuf.struct_pb2.Struct): + The session parameters available to the bot + at this point. + differences (Sequence[google.cloud.dialogflowcx_v3beta1.types.TestRunDifference]): + Output only. If this is part of a [result conversation + turn][TestCaseResult.conversation_turns], the list of + differences between the original run and the replay for this + output, if any. + diagnostic_info (google.protobuf.struct_pb2.Struct): + Required. Input only. The diagnostic + [info][Session.DetectIntentResponse.QueryResult.diagnostic_info] + output for the turn. + triggered_intent (google.cloud.dialogflowcx_v3beta1.types.Intent): + The [Intent][google.cloud.dialogflow.cx.v3beta1.Intent] that + triggered the response. Only name and displayName will be + set. + current_page (google.cloud.dialogflowcx_v3beta1.types.Page): + The [Page][google.cloud.dialogflow.cx.v3beta1.Page] on which + the utterance was spoken. Only name and displayName will be + set. + text_responses (Sequence[google.cloud.dialogflowcx_v3beta1.types.ResponseMessage.Text]): + The + [text][google.cloud.dialogflow.cx.v3beta1.ResponseMessage.Text] + responses from the agent for the turn. + status (google.rpc.status_pb2.Status): + Response error from the agent in the test + result. If set, other output is empty. + """ + + session_parameters = proto.Field( + proto.MESSAGE, number=4, message=struct.Struct, + ) + + differences = proto.RepeatedField( + proto.MESSAGE, number=5, message="TestRunDifference", + ) + + diagnostic_info = proto.Field(proto.MESSAGE, number=6, message=struct.Struct,) + + triggered_intent = proto.Field( + proto.MESSAGE, number=7, message=gcdc_intent.Intent, + ) + + current_page = proto.Field(proto.MESSAGE, number=8, message=gcdc_page.Page,) + + text_responses = proto.RepeatedField( + proto.MESSAGE, number=9, message=response_message.ResponseMessage.Text, + ) + + status = proto.Field(proto.MESSAGE, number=10, message=gr_status.Status,) + + user_input = proto.Field(proto.MESSAGE, number=1, message=UserInput,) + + virtual_agent_output = proto.Field( + proto.MESSAGE, number=2, message=VirtualAgentOutput, + ) + + +class TestRunDifference(proto.Message): + r"""The description of differences between original and replayed + agent output. + + Attributes: + type_ (google.cloud.dialogflowcx_v3beta1.types.TestRunDifference.DiffType): + The type of diff. + description (str): + A description of the diff, showing the actual + output vs expected output. + """ + + class DiffType(proto.Enum): + r"""What part of the message replay differs from the test case.""" + DIFF_TYPE_UNSPECIFIED = 0 + INTENT = 1 + PAGE = 2 + PARAMETERS = 3 + UTTERANCE = 4 + + type_ = proto.Field(proto.ENUM, number=1, enum=DiffType,) + + description = proto.Field(proto.STRING, number=2) + + +class TransitionCoverage(proto.Message): + r"""Transition coverage represents the percentage of all possible + page transitions (page-level transition routes and event + handlers, excluding transition route groups) present within any + of a parent's test cases. + + Attributes: + transitions (Sequence[google.cloud.dialogflowcx_v3beta1.types.TransitionCoverage.Transition]): + The list of Transitions present in the agent. + coverage_score (float): + The percent of transitions in the agent that + are covered. + """ + + class TransitionNode(proto.Message): + r"""The source or target of a transition. + + Attributes: + page (google.cloud.dialogflowcx_v3beta1.types.Page): + Indicates a transition to a + [Page][google.cloud.dialogflow.cx.v3beta1.Page]. Only some + fields such as name and displayname will be set. + flow (google.cloud.dialogflowcx_v3beta1.types.Flow): + Indicates a transition to a + [Flow][google.cloud.dialogflow.cx.v3beta1.Flow]. Only some + fields such as name and displayname will be set. + """ + + page = proto.Field( + proto.MESSAGE, number=1, oneof="kind", message=gcdc_page.Page, + ) + + flow = proto.Field( + proto.MESSAGE, number=2, oneof="kind", message=gcdc_flow.Flow, + ) + + class Transition(proto.Message): + r"""A transition in a page. + + Attributes: + source (google.cloud.dialogflowcx_v3beta1.types.TransitionCoverage.TransitionNode): + The start node of a transition. + index (int): + The index of a transition in the transition + list. Starting from 0. + target (google.cloud.dialogflowcx_v3beta1.types.TransitionCoverage.TransitionNode): + The end node of a transition. + covered (bool): + Whether or not the transition is covered by + at least one of the agent's test cases. + transition_route (google.cloud.dialogflowcx_v3beta1.types.TransitionRoute): + Intent route or condition route. + event_handler (google.cloud.dialogflowcx_v3beta1.types.EventHandler): + Event handler. + """ + + source = proto.Field( + proto.MESSAGE, number=1, message="TransitionCoverage.TransitionNode", + ) + + index = proto.Field(proto.INT32, number=4) + + target = proto.Field( + proto.MESSAGE, number=2, message="TransitionCoverage.TransitionNode", + ) + + covered = proto.Field(proto.BOOL, number=3) + + transition_route = proto.Field( + proto.MESSAGE, number=5, oneof="detail", message=gcdc_page.TransitionRoute, + ) + + event_handler = proto.Field( + proto.MESSAGE, number=6, oneof="detail", message=gcdc_page.EventHandler, + ) + + transitions = proto.RepeatedField(proto.MESSAGE, number=1, message=Transition,) + + coverage_score = proto.Field(proto.FLOAT, number=2) + + +class TransitionRouteGroupCoverage(proto.Message): + r"""Transition route group coverage represents the percentage of + all possible transition routes present within any of a parent's + test cases. The results are grouped by the transition route + group. + + Attributes: + coverages (Sequence[google.cloud.dialogflowcx_v3beta1.types.TransitionRouteGroupCoverage.Coverage]): + Transition route group coverages. + coverage_score (float): + The percent of transition routes in all the + transition route groups that are covered. + """ + + class Coverage(proto.Message): + r"""Coverage result message for one transition route group. + + Attributes: + route_group (google.cloud.dialogflowcx_v3beta1.types.TransitionRouteGroup): + Transition route group metadata. Only name + and displayName will be set. + transitions (Sequence[google.cloud.dialogflowcx_v3beta1.types.TransitionRouteGroupCoverage.Coverage.Transition]): + The list of transition routes and coverage in + the transition route group. + coverage_score (float): + The percent of transition routes in the + transition route group that are covered. + """ + + class Transition(proto.Message): + r"""A transition coverage in a transition route group. + + Attributes: + transition_route (google.cloud.dialogflowcx_v3beta1.types.TransitionRoute): + Intent route or condition route. + covered (bool): + Whether or not the transition route is + covered by at least one of the agent's test + cases. + """ + + transition_route = proto.Field( + proto.MESSAGE, number=1, message=gcdc_page.TransitionRoute, + ) + + covered = proto.Field(proto.BOOL, number=2) + + route_group = proto.Field( + proto.MESSAGE, + number=1, + message=transition_route_group.TransitionRouteGroup, + ) + + transitions = proto.RepeatedField( + proto.MESSAGE, + number=2, + message="TransitionRouteGroupCoverage.Coverage.Transition", + ) + + coverage_score = proto.Field(proto.FLOAT, number=3) + + coverages = proto.RepeatedField(proto.MESSAGE, number=1, message=Coverage,) + + coverage_score = proto.Field(proto.FLOAT, number=2) + + +class IntentCoverage(proto.Message): + r"""Intent coverage represents the percentage of all possible + intents in the agent that are triggered in any of a parent's + test cases. + + Attributes: + intents (Sequence[google.cloud.dialogflowcx_v3beta1.types.IntentCoverage.Intent]): + The list of Intents present in the agent + coverage_score (float): + The percent of intents in the agent that are + covered. + """ + + class Intent(proto.Message): + r"""The agent's intent. + + Attributes: + intent (str): + The intent full resource name + covered (bool): + Whether or not the intent is covered by at + least one of the agent's test cases. + """ + + intent = proto.Field(proto.STRING, number=1) + + covered = proto.Field(proto.BOOL, number=2) + + intents = proto.RepeatedField(proto.MESSAGE, number=1, message=Intent,) + + coverage_score = proto.Field(proto.FLOAT, number=2) + + +class CalculateCoverageRequest(proto.Message): + r"""The request message for + [TestCases.CalculateCoverage][google.cloud.dialogflow.cx.v3beta1.TestCases.CalculateCoverage]. + + Attributes: + agent (str): + Required. The agent to calculate coverage for. Format: + ``projects//locations//agents/``. + type_ (google.cloud.dialogflowcx_v3beta1.types.CalculateCoverageRequest.CoverageType): + Required. The type of coverage requested. + """ + + class CoverageType(proto.Enum): + r"""The type of coverage score requested.""" + COVERAGE_TYPE_UNSPECIFIED = 0 + INTENT = 1 + PAGE_TRANSITION = 2 + TRANSITION_ROUTE_GROUP = 3 + + agent = proto.Field(proto.STRING, number=3) + + type_ = proto.Field(proto.ENUM, number=2, enum=CoverageType,) + + +class CalculateCoverageResponse(proto.Message): + r"""The response message for + [TestCases.CalculateCoverage][google.cloud.dialogflow.cx.v3beta1.TestCases.CalculateCoverage]. + + Attributes: + agent (str): + The agent to calculate coverage for. Format: + ``projects//locations//agents/``. + intent_coverage (google.cloud.dialogflowcx_v3beta1.types.IntentCoverage): + Intent coverage. + transition_coverage (google.cloud.dialogflowcx_v3beta1.types.TransitionCoverage): + Transition (excluding transition route + groups) coverage. + route_group_coverage (google.cloud.dialogflowcx_v3beta1.types.TransitionRouteGroupCoverage): + Transition route group coverage. + """ + + agent = proto.Field(proto.STRING, number=5) + + intent_coverage = proto.Field( + proto.MESSAGE, number=2, oneof="coverage_type", message="IntentCoverage", + ) + + transition_coverage = proto.Field( + proto.MESSAGE, number=4, oneof="coverage_type", message="TransitionCoverage", + ) + + route_group_coverage = proto.Field( + proto.MESSAGE, + number=6, + oneof="coverage_type", + message="TransitionRouteGroupCoverage", + ) + + +class ListTestCasesRequest(proto.Message): + r"""The request message for + [TestCases.ListTestCases][google.cloud.dialogflow.cx.v3beta1.TestCases.ListTestCases]. + + Attributes: + parent (str): + Required. The agent to list all pages for. Format: + ``projects//locations//agents/``. + page_size (int): + The maximum number of items to return in a + single page. By default 20. Note that when + TestCaseView = FULL, the maximum page size + allowed is 20. When TestCaseView = BASIC, the + maximum page size allowed is 500. + page_token (str): + The next_page_token value returned from a previous list + request. + view (google.cloud.dialogflowcx_v3beta1.types.ListTestCasesRequest.TestCaseView): + Specifies whether response should include all + fields or just the metadata. + """ + + class TestCaseView(proto.Enum): + r"""Specifies how much test case information to include in the + response. + """ + TEST_CASE_VIEW_UNSPECIFIED = 0 + BASIC = 1 + FULL = 2 + + parent = proto.Field(proto.STRING, number=1) + + page_size = proto.Field(proto.INT32, number=2) + + page_token = proto.Field(proto.STRING, number=3) + + view = proto.Field(proto.ENUM, number=4, enum=TestCaseView,) + + +class ListTestCasesResponse(proto.Message): + r"""The response message for + [TestCases.ListTestCases][google.cloud.dialogflow.cx.v3beta1.TestCases.ListTestCases]. + + Attributes: + test_cases (Sequence[google.cloud.dialogflowcx_v3beta1.types.TestCase]): + The list of test cases. There will be a maximum number of + items returned based on the page_size field in the request. + next_page_token (str): + Token to retrieve the next page of results, + or empty if there are no more results in the + list. + """ + + @property + def raw_page(self): + return self + + test_cases = proto.RepeatedField(proto.MESSAGE, number=1, message="TestCase",) + + next_page_token = proto.Field(proto.STRING, number=2) + + +class BatchDeleteTestCasesRequest(proto.Message): + r"""The request message for + [TestCases.BatchDeleteTestCases][google.cloud.dialogflow.cx.v3beta1.TestCases.BatchDeleteTestCases]. + + Attributes: + parent (str): + Required. The agent to delete test cases from. Format: + ``projects//locations//agents/``. + names (Sequence[str]): + Required. Format of test case names: + ``projects//locations/ /agents//testCases/``. + """ + + parent = proto.Field(proto.STRING, number=1) + + names = proto.RepeatedField(proto.STRING, number=3) + + +class CreateTestCaseRequest(proto.Message): + r"""The request message for + [TestCases.CreateTestCase][google.cloud.dialogflow.cx.v3beta1.TestCases.CreateTestCase]. + + Attributes: + parent (str): + Required. The agent to create the test case for. Format: + ``projects//locations//agents/``. + test_case (google.cloud.dialogflowcx_v3beta1.types.TestCase): + Required. The test case to create. + """ + + parent = proto.Field(proto.STRING, number=1) + + test_case = proto.Field(proto.MESSAGE, number=2, message="TestCase",) + + +class UpdateTestCaseRequest(proto.Message): + r"""The request message for + [TestCases.UpdateTestCase][google.cloud.dialogflow.cx.v3beta1.TestCases.UpdateTestCase]. + + Attributes: + test_case (google.cloud.dialogflowcx_v3beta1.types.TestCase): + Required. The test case to update. + update_mask (google.protobuf.field_mask_pb2.FieldMask): + Required. The mask to specify which fields should be + updated. The + [``creationTime``][google.cloud.dialogflow.cx.v3beta1.TestCase.creation_time] + and + [``lastTestResult``][google.cloud.dialogflow.cx.v3beta1.TestCase.last_test_result] + cannot be updated. + """ + + test_case = proto.Field(proto.MESSAGE, number=1, message="TestCase",) + + update_mask = proto.Field(proto.MESSAGE, number=2, message=field_mask.FieldMask,) + + +class GetTestCaseRequest(proto.Message): + r"""The request message for + [TestCases.GetTestCase][google.cloud.dialogflow.cx.v3beta1.TestCases.GetTestCase]. + + Attributes: + name (str): + Required. The name of the testcase. Format: + ``projects//locations//agents//testCases/``. + """ + + name = proto.Field(proto.STRING, number=1) + + +class RunTestCaseRequest(proto.Message): + r"""The request message for + [TestCases.RunTestCase][google.cloud.dialogflow.cx.v3beta1.TestCases.RunTestCase]. + + Attributes: + name (str): + Required. Format of test case name to run: + ``projects//locations/ /agents//testCases/``. + environment (str): + Optional. Environment name. If not set, draft environment is + assumed. Format: + ``projects//locations//agents//environments/``. + """ + + name = proto.Field(proto.STRING, number=1) + + environment = proto.Field(proto.STRING, number=2) + + +class RunTestCaseResponse(proto.Message): + r"""The response message for + [TestCases.RunTestCase][google.cloud.dialogflow.cx.v3beta1.TestCases.RunTestCase]. + + Attributes: + result (google.cloud.dialogflowcx_v3beta1.types.TestCaseResult): + The result. + """ + + result = proto.Field(proto.MESSAGE, number=2, message="TestCaseResult",) + + +class RunTestCaseMetadata(proto.Message): + r"""Metadata returned for the + [TestCases.RunTestCase][google.cloud.dialogflow.cx.v3beta1.TestCases.RunTestCase] + long running operation. + """ + + +class BatchRunTestCasesRequest(proto.Message): + r"""The request message for + [TestCases.BatchRunTestCases][google.cloud.dialogflow.cx.v3beta1.TestCases.BatchRunTestCases]. + + Attributes: + parent (str): + Required. Agent name. Format: + ``projects//locations//agents/ ``. + environment (str): + Optional. If not set, draft environment is assumed. Format: + ``projects//locations//agents//environments/``. + test_cases (Sequence[str]): + Required. Format: + ``projects//locations//agents//testCases/``. + """ + + parent = proto.Field(proto.STRING, number=1) + + environment = proto.Field(proto.STRING, number=2) + + test_cases = proto.RepeatedField(proto.STRING, number=3) + + +class BatchRunTestCasesResponse(proto.Message): + r"""The response message for + [TestCases.BatchRunTestCases][google.cloud.dialogflow.cx.v3beta1.TestCases.BatchRunTestCases]. + + Attributes: + results (Sequence[google.cloud.dialogflowcx_v3beta1.types.TestCaseResult]): + The test case results. The detailed [conversation + turns][google.cloud.dialogflow.cx.v3beta1.TestCaseResult.conversation_turns] + are empty in this response. + """ + + results = proto.RepeatedField(proto.MESSAGE, number=1, message="TestCaseResult",) + + +class BatchRunTestCasesMetadata(proto.Message): + r"""Metadata returned for the + [TestCases.BatchRunTestCases][google.cloud.dialogflow.cx.v3beta1.TestCases.BatchRunTestCases] + long running operation. + + Attributes: + errors (Sequence[google.cloud.dialogflowcx_v3beta1.types.TestError]): + The test errors. + """ + + errors = proto.RepeatedField(proto.MESSAGE, number=1, message="TestError",) + + +class TestError(proto.Message): + r"""Error info for running a test. + + Attributes: + test_case (str): + The test case resource name. + status (google.rpc.status_pb2.Status): + The status associated with the test. + test_time (google.protobuf.timestamp_pb2.Timestamp): + The timestamp when the test was completed. + """ + + test_case = proto.Field(proto.STRING, number=1) + + status = proto.Field(proto.MESSAGE, number=2, message=gr_status.Status,) + + test_time = proto.Field(proto.MESSAGE, number=3, message=timestamp.Timestamp,) + + +class ImportTestCasesRequest(proto.Message): + r"""The request message for + [TestCases.ImportTestCases][google.cloud.dialogflow.cx.v3beta1.TestCases.ImportTestCases]. + + Attributes: + parent (str): + Required. The agent to import test cases to. Format: + ``projects//locations//agents/``. + gcs_uri (str): + The `Google Cloud + Storage `__ URI to + import test cases from. The format of this URI must be + ``gs:///``. + content (bytes): + Uncompressed raw byte content for test cases. + """ + + parent = proto.Field(proto.STRING, number=1) + + gcs_uri = proto.Field(proto.STRING, number=2, oneof="source") + + content = proto.Field(proto.BYTES, number=3, oneof="source") + + +class ImportTestCasesResponse(proto.Message): + r"""The response message for + [TestCases.ImportTestCases][google.cloud.dialogflow.cx.v3beta1.TestCases.ImportTestCases]. + + Attributes: + names (Sequence[str]): + The unique identifiers of the new test cases. Format: + ``projects//locations//agents//testCases/``. + """ + + names = proto.RepeatedField(proto.STRING, number=1) + + +class ImportTestCasesMetadata(proto.Message): + r"""Metadata returned for the + [TestCases.ImportTestCases][google.cloud.dialogflow.cx.v3beta1.TestCases.ImportTestCases] + long running operation. + + Attributes: + errors (Sequence[google.cloud.dialogflowcx_v3beta1.types.TestCaseError]): + Errors for failed test cases. + """ + + errors = proto.RepeatedField(proto.MESSAGE, number=1, message="TestCaseError",) + + +class TestCaseError(proto.Message): + r"""Error info for importing a test. + + Attributes: + test_case (google.cloud.dialogflowcx_v3beta1.types.TestCase): + The test case. + status (google.rpc.status_pb2.Status): + The status associated with the test case. + """ + + test_case = proto.Field(proto.MESSAGE, number=1, message="TestCase",) + + status = proto.Field(proto.MESSAGE, number=2, message=gr_status.Status,) + + +class ExportTestCasesRequest(proto.Message): + r"""The request message for + [TestCases.ExportTestCases][google.cloud.dialogflow.cx.v3beta1.TestCases.ExportTestCases]. + + Attributes: + parent (str): + Required. The agent where to export test cases from. Format: + ``projects//locations//agents/``. + gcs_uri (str): + The `Google Cloud + Storage `__ URI to + export the test cases to. The format of this URI must be + ``gs:///``. If unspecified, the + serialized test cases is returned inline. + data_format (google.cloud.dialogflowcx_v3beta1.types.ExportTestCasesRequest.DataFormat): + The data format of the exported test cases. If not + specified, ``BLOB`` is assumed. + filter (str): + The filter expression used to filter exported test cases, + see `API Filtering `__. The expression + is case insensitive and supports the following syntax: + + name = [OR name = ] ... + + For example: + + - "name = t1 OR name = t2" matches the test case with the + exact resource name "t1" or "t2". + """ + + class DataFormat(proto.Enum): + r"""Data format of the exported test cases.""" + DATA_FORMAT_UNSPECIFIED = 0 + BLOB = 1 + JSON = 2 + + parent = proto.Field(proto.STRING, number=1) + + gcs_uri = proto.Field(proto.STRING, number=2, oneof="destination") + + data_format = proto.Field(proto.ENUM, number=3, enum=DataFormat,) + + filter = proto.Field(proto.STRING, number=4) + + +class ExportTestCasesResponse(proto.Message): + r"""The response message for + [TestCases.ExportTestCases][google.cloud.dialogflow.cx.v3beta1.TestCases.ExportTestCases]. + + Attributes: + gcs_uri (str): + The URI to a file containing the exported test cases. This + field is populated only if ``gcs_uri`` is specified in + [ExportTestCasesRequest][google.cloud.dialogflow.cx.v3beta1.ExportTestCasesRequest]. + content (bytes): + Uncompressed raw byte content for test cases. + """ + + gcs_uri = proto.Field(proto.STRING, number=1, oneof="destination") + + content = proto.Field(proto.BYTES, number=2, oneof="destination") + + +class ExportTestCasesMetadata(proto.Message): + r"""Metadata returned for the + [TestCases.ExportTestCases][google.cloud.dialogflow.cx.v3beta1.TestCases.ExportTestCases] + long running operation. + """ + + +class ListTestCaseResultsRequest(proto.Message): + r"""The request message for + [TestCases.ListTestCaseResults][google.cloud.dialogflow.cx.v3beta1.TestCases.ListTestCaseResults]. + + Attributes: + parent (str): + Required. The test case to list results for. Format: + ``projects//locations//agents// testCases/``. + Specify a ``-`` as a wildcard for TestCase ID to list + results across multiple test cases. + page_size (int): + The maximum number of items to return in a + single page. By default 100 and at most 1000. + page_token (str): + The next_page_token value returned from a previous list + request. + filter (str): + The filter expression used to filter test case results. See + `API Filtering `__. + + The expression is case insensitive. Only 'AND' is supported + for logical operators. The supported syntax is listed below + in detail: + + [AND ] ... [AND latest] + + The supported fields and operators are: field operator + ``environment`` ``=``, ``IN`` (Use value ``draft`` for draft + environment) ``test_time`` ``>``, ``<`` + + ``latest`` only returns the latest test result in all + results for each test case. + + Examples: + + - "environment=draft AND latest" matches the latest test + result for each test case in the draft environment. + - "environment IN (e1,e2)" matches any test case results + with an environment resource name of either "e1" or "e2". + - "test_time > 1602540713" matches any test case results + with test time later than a unix timestamp in seconds + 1602540713. + """ + + parent = proto.Field(proto.STRING, number=1) + + page_size = proto.Field(proto.INT32, number=2) + + page_token = proto.Field(proto.STRING, number=3) + + filter = proto.Field(proto.STRING, number=4) + + +class ListTestCaseResultsResponse(proto.Message): + r"""The response message for + [TestCases.ListTestCaseResults][google.cloud.dialogflow.cx.v3beta1.TestCases.ListTestCaseResults]. + + Attributes: + test_case_results (Sequence[google.cloud.dialogflowcx_v3beta1.types.TestCaseResult]): + The list of test case results. + next_page_token (str): + Token to retrieve the next page of results, + or empty if there are no more results in the + list. + """ + + @property + def raw_page(self): + return self + + test_case_results = proto.RepeatedField( + proto.MESSAGE, number=1, message="TestCaseResult", + ) + + next_page_token = proto.Field(proto.STRING, number=2) + + +__all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/google/cloud/dialogflowcx_v3beta1/types/transition_route_group.py b/google/cloud/dialogflowcx_v3beta1/types/transition_route_group.py index ec2ab584..550bdd44 100644 --- a/google/cloud/dialogflowcx_v3beta1/types/transition_route_group.py +++ b/google/cloud/dialogflowcx_v3beta1/types/transition_route_group.py @@ -52,16 +52,9 @@ class TransitionRouteGroup(proto.Message): group, unique within the [Agent][google.cloud.dialogflow.cx.v3beta1.Agent]. The display name can be no longer than 30 characters. - transition_routes (Sequence[~.page.TransitionRoute]): + transition_routes (Sequence[google.cloud.dialogflowcx_v3beta1.types.TransitionRoute]): Transition routes associated with the [TransitionRouteGroup][google.cloud.dialogflow.cx.v3beta1.TransitionRouteGroup]. - Duplicate transition routes (i.e. using the same - [``intent``][google.cloud.dialogflow.cx.v3beta1.TransitionRoute.intent]) - are not allowed. - - Note that the - [``name``][google.cloud.dialogflow.cx.v3beta1.TransitionRoute.name] - field is not used in the transition route group scope. """ name = proto.Field(proto.STRING, number=1) @@ -97,7 +90,7 @@ class ListTransitionRouteGroupsRequest(proto.Message): If not specified, the agent's default language is used. `Many - languages `__ + languages `__ are supported. Note: languages must be enabled in the agent before they can be used. """ @@ -116,7 +109,7 @@ class ListTransitionRouteGroupsResponse(proto.Message): [TransitionRouteGroups.ListTransitionRouteGroups][google.cloud.dialogflow.cx.v3beta1.TransitionRouteGroups.ListTransitionRouteGroups]. Attributes: - transition_route_groups (Sequence[~.gcdc_transition_route_group.TransitionRouteGroup]): + transition_route_groups (Sequence[google.cloud.dialogflowcx_v3beta1.types.TransitionRouteGroup]): The list of transition route groups. There will be a maximum number of items returned based on the page_size field in the request. The list may in some cases be empty or contain @@ -158,7 +151,7 @@ class GetTransitionRouteGroupRequest(proto.Message): If not specified, the agent's default language is used. `Many - languages `__ + languages `__ are supported. Note: languages must be enabled in the agent before they can be used. """ @@ -178,7 +171,7 @@ class CreateTransitionRouteGroupRequest(proto.Message): [TransitionRouteGroup][google.cloud.dialogflow.cx.v3beta1.TransitionRouteGroup] for. Format: ``projects//locations//agents//flows/``. - transition_route_group (~.gcdc_transition_route_group.TransitionRouteGroup): + transition_route_group (google.cloud.dialogflowcx_v3beta1.types.TransitionRouteGroup): Required. The transition route group to create. language_code (str): @@ -190,7 +183,7 @@ class CreateTransitionRouteGroupRequest(proto.Message): If not specified, the agent's default language is used. `Many - languages `__ + languages `__ are supported. Note: languages must be enabled in the agent before they can be used. """ @@ -209,10 +202,10 @@ class UpdateTransitionRouteGroupRequest(proto.Message): [TransitionRouteGroups.UpdateTransitionRouteGroup][google.cloud.dialogflow.cx.v3beta1.TransitionRouteGroups.UpdateTransitionRouteGroup]. Attributes: - transition_route_group (~.gcdc_transition_route_group.TransitionRouteGroup): + transition_route_group (google.cloud.dialogflowcx_v3beta1.types.TransitionRouteGroup): Required. The transition route group to update. - update_mask (~.field_mask.FieldMask): + update_mask (google.protobuf.field_mask_pb2.FieldMask): The mask to control which fields get updated. language_code (str): The language to list transition route groups for. The field @@ -223,7 +216,7 @@ class UpdateTransitionRouteGroupRequest(proto.Message): If not specified, the agent's default language is used. `Many - languages `__ + languages `__ are supported. Note: languages must be enabled in the agent before they can be used. """ diff --git a/google/cloud/dialogflowcx_v3beta1/types/validation_message.py b/google/cloud/dialogflowcx_v3beta1/types/validation_message.py new file mode 100644 index 00000000..b49e957a --- /dev/null +++ b/google/cloud/dialogflowcx_v3beta1/types/validation_message.py @@ -0,0 +1,98 @@ +# -*- 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. +# + +import proto # type: ignore + + +__protobuf__ = proto.module( + package="google.cloud.dialogflow.cx.v3beta1", + manifest={"ValidationMessage", "ResourceName",}, +) + + +class ValidationMessage(proto.Message): + r"""Agent/flow validation message. + + Attributes: + resource_type (google.cloud.dialogflowcx_v3beta1.types.ValidationMessage.ResourceType): + The type of the resources where the message + is found. + resources (Sequence[str]): + The names of the resources where the message + is found. + resource_names (Sequence[google.cloud.dialogflowcx_v3beta1.types.ResourceName]): + The resource names of the resources where the + message is found. + severity (google.cloud.dialogflowcx_v3beta1.types.ValidationMessage.Severity): + Indicates the severity of the message. + detail (str): + The message detail. + """ + + class ResourceType(proto.Enum): + r"""Resource types.""" + RESOURCE_TYPE_UNSPECIFIED = 0 + AGENT = 1 + INTENT = 2 + INTENT_TRAINING_PHRASE = 8 + INTENT_PARAMETER = 9 + INTENTS = 10 + INTENT_TRAINING_PHRASES = 11 + ENTITY_TYPE = 3 + ENTITY_TYPES = 12 + WEBHOOK = 4 + FLOW = 5 + PAGE = 6 + PAGES = 13 + TRANSITION_ROUTE_GROUP = 7 + + class Severity(proto.Enum): + r"""Severity level.""" + SEVERITY_UNSPECIFIED = 0 + INFO = 1 + WARNING = 2 + ERROR = 3 + + resource_type = proto.Field(proto.ENUM, number=1, enum=ResourceType,) + + resources = proto.RepeatedField(proto.STRING, number=2) + + resource_names = proto.RepeatedField( + proto.MESSAGE, number=6, message="ResourceName", + ) + + severity = proto.Field(proto.ENUM, number=3, enum=Severity,) + + detail = proto.Field(proto.STRING, number=4) + + +class ResourceName(proto.Message): + r"""Resource name and display name. + + Attributes: + name (str): + Name. + display_name (str): + Display name. + """ + + name = proto.Field(proto.STRING, number=1) + + display_name = proto.Field(proto.STRING, number=2) + + +__all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/google/cloud/dialogflowcx_v3beta1/types/version.py b/google/cloud/dialogflowcx_v3beta1/types/version.py index 57c63e8e..438ab88f 100644 --- a/google/cloud/dialogflowcx_v3beta1/types/version.py +++ b/google/cloud/dialogflowcx_v3beta1/types/version.py @@ -69,12 +69,12 @@ class Version(proto.Message): The description of the version. The maximum length is 500 characters. If exceeded, the request is rejected. - nlu_settings (~.flow.NluSettings): + nlu_settings (google.cloud.dialogflowcx_v3beta1.types.NluSettings): Output only. The NLU settings of the flow at version creation. - create_time (~.timestamp.Timestamp): + create_time (google.protobuf.timestamp_pb2.Timestamp): Output only. Create time of the version. - state (~.gcdc_version.Version.State): + state (google.cloud.dialogflowcx_v3beta1.types.Version.State): Output only. The state of this version. This field is read-only and cannot be set by create and update methods. @@ -130,7 +130,7 @@ class ListVersionsResponse(proto.Message): [Versions.ListVersions][google.cloud.dialogflow.cx.v3beta1.Versions.ListVersions]. Attributes: - versions (Sequence[~.gcdc_version.Version]): + versions (Sequence[google.cloud.dialogflowcx_v3beta1.types.Version]): A list of versions. There will be a maximum number of items returned based on the page_size field in the request. The list may in some cases be empty or contain fewer entries @@ -176,7 +176,7 @@ class CreateVersionRequest(proto.Message): [Version][google.cloud.dialogflow.cx.v3beta1.Version] for. Format: ``projects//locations//agents//flows/``. - version (~.gcdc_version.Version): + version (google.cloud.dialogflowcx_v3beta1.types.Version): Required. The version to create. """ @@ -190,9 +190,9 @@ class UpdateVersionRequest(proto.Message): [Versions.UpdateVersion][google.cloud.dialogflow.cx.v3beta1.Versions.UpdateVersion]. Attributes: - version (~.gcdc_version.Version): + version (google.cloud.dialogflowcx_v3beta1.types.Version): Required. The version to update. - update_mask (~.field_mask.FieldMask): + update_mask (google.protobuf.field_mask_pb2.FieldMask): Required. The mask to control which fields get updated. Currently only ``description`` and ``display_name`` can be updated. diff --git a/google/cloud/dialogflowcx_v3beta1/types/webhook.py b/google/cloud/dialogflowcx_v3beta1/types/webhook.py index 303a6441..dfbdd085 100644 --- a/google/cloud/dialogflowcx_v3beta1/types/webhook.py +++ b/google/cloud/dialogflowcx_v3beta1/types/webhook.py @@ -60,9 +60,9 @@ class Webhook(proto.Message): display_name (str): Required. The human-readable name of the webhook, unique within the agent. - generic_web_service (~.gcdc_webhook.Webhook.GenericWebService): + generic_web_service (google.cloud.dialogflowcx_v3beta1.types.Webhook.GenericWebService): Configuration for a generic web service. - timeout (~.duration.Duration): + timeout (google.protobuf.duration_pb2.Duration): Webhook execution timeout. Execution is considered failed if Dialogflow doesn't receive a response from webhook at the end of the @@ -83,7 +83,7 @@ class GenericWebService(proto.Message): The user name for HTTP Basic authentication. password (str): The password for HTTP Basic authentication. - request_headers (Sequence[~.gcdc_webhook.Webhook.GenericWebService.RequestHeadersEntry]): + request_headers (Sequence[google.cloud.dialogflowcx_v3beta1.types.Webhook.GenericWebService.RequestHeadersEntry]): The HTTP request headers to send together with webhook requests. """ @@ -137,7 +137,7 @@ class ListWebhooksResponse(proto.Message): [Webhooks.ListWebhooks][google.cloud.dialogflow.cx.v3beta1.Webhooks.ListWebhooks]. Attributes: - webhooks (Sequence[~.gcdc_webhook.Webhook]): + webhooks (Sequence[google.cloud.dialogflowcx_v3beta1.types.Webhook]): The list of webhooks. There will be a maximum number of items returned based on the page_size field in the request. next_page_token (str): @@ -176,7 +176,7 @@ class CreateWebhookRequest(proto.Message): parent (str): Required. The agent to create a webhook for. Format: ``projects//locations//agents/``. - webhook (~.gcdc_webhook.Webhook): + webhook (google.cloud.dialogflowcx_v3beta1.types.Webhook): Required. The webhook to create. """ @@ -190,9 +190,9 @@ class UpdateWebhookRequest(proto.Message): [Webhooks.UpdateWebhook][google.cloud.dialogflow.cx.v3beta1.Webhooks.UpdateWebhook]. Attributes: - webhook (~.gcdc_webhook.Webhook): + webhook (google.cloud.dialogflowcx_v3beta1.types.Webhook): Required. The webhook to update. - update_mask (~.field_mask.FieldMask): + update_mask (google.protobuf.field_mask_pb2.FieldMask): The mask to control which fields get updated. If the mask is not present, all fields will be updated. @@ -239,22 +239,27 @@ class WebhookRequest(proto.Message): Always present. The unique identifier of the [DetectIntentResponse][google.cloud.dialogflow.cx.v3beta1.DetectIntentResponse] that will be returned to the API caller. - fulfillment_info (~.gcdc_webhook.WebhookRequest.FulfillmentInfo): + fulfillment_info (google.cloud.dialogflowcx_v3beta1.types.WebhookRequest.FulfillmentInfo): Always present. Information about the fulfillment that triggered this webhook call. - intent_info (~.gcdc_webhook.WebhookRequest.IntentInfo): + intent_info (google.cloud.dialogflowcx_v3beta1.types.WebhookRequest.IntentInfo): Information about the last matched intent. - page_info (~.gcdc_webhook.PageInfo): + page_info (google.cloud.dialogflowcx_v3beta1.types.PageInfo): Information about page status. - session_info (~.gcdc_webhook.SessionInfo): + session_info (google.cloud.dialogflowcx_v3beta1.types.SessionInfo): Information about session status. - messages (Sequence[~.response_message.ResponseMessage]): + messages (Sequence[google.cloud.dialogflowcx_v3beta1.types.ResponseMessage]): The list of rich message responses to present to the user. Webhook can choose to append or replace this list in [WebhookResponse.fulfillment_response][google.cloud.dialogflow.cx.v3beta1.WebhookResponse.fulfillment_response]; - payload (~.struct.Struct): + payload (google.protobuf.struct_pb2.Struct): Custom data set in [QueryParameters.payload][google.cloud.dialogflow.cx.v3beta1.QueryParameters.payload]. + sentiment_analysis_result (google.cloud.dialogflowcx_v3beta1.types.WebhookRequest.SentimentAnalysisResult): + The sentiment analysis result of the current + user request. The field is filled when sentiment + analysis is configured to be enabled for the + request. """ class FulfillmentInfo(proto.Message): @@ -277,13 +282,20 @@ class IntentInfo(proto.Message): Always present. The unique identifier of the last matched [intent][google.cloud.dialogflow.cx.v3beta1.Intent]. Format: ``projects//locations//agents//intents/``. - parameters (Sequence[~.gcdc_webhook.WebhookRequest.IntentInfo.ParametersEntry]): + display_name (str): + Always present. The display name of the last matched + [intent][google.cloud.dialogflow.cx.v3beta1.Intent]. + parameters (Sequence[google.cloud.dialogflowcx_v3beta1.types.WebhookRequest.IntentInfo.ParametersEntry]): Parameters identified as a result of intent matching. This is a map of the name of the identified parameter to the value of the parameter identified from the user's utterance. All parameters defined in the matched intent that are identified will be surfaced here. + confidence (float): + The confidence of the matched intent. Values + range from 0.0 (completely uncertain) to 1.0 + (completely certain). """ class IntentParameterValue(proto.Message): @@ -293,7 +305,7 @@ class IntentParameterValue(proto.Message): original_value (str): Always present. Original text value extracted from user utterance. - resolved_value (~.struct.Value): + resolved_value (google.protobuf.struct_pb2.Value): Always present. Structured value for the parameter extracted from user utterance. """ @@ -304,6 +316,8 @@ class IntentParameterValue(proto.Message): last_matched_intent = proto.Field(proto.STRING, number=1) + display_name = proto.Field(proto.STRING, number=3) + parameters = proto.MapField( proto.STRING, proto.MESSAGE, @@ -311,6 +325,25 @@ class IntentParameterValue(proto.Message): message="WebhookRequest.IntentInfo.IntentParameterValue", ) + confidence = proto.Field(proto.FLOAT, number=4) + + class SentimentAnalysisResult(proto.Message): + r"""Represents the result of sentiment analysis. + + Attributes: + score (float): + Sentiment score between -1.0 (negative + sentiment) and 1.0 (positive sentiment). + magnitude (float): + A non-negative number in the [0, +inf) range, which + represents the absolute magnitude of sentiment, regardless + of score (positive or negative). + """ + + score = proto.Field(proto.FLOAT, number=1) + + magnitude = proto.Field(proto.FLOAT, number=2) + detect_intent_response_id = proto.Field(proto.STRING, number=1) fulfillment_info = proto.Field(proto.MESSAGE, number=6, message=FulfillmentInfo,) @@ -327,25 +360,29 @@ class IntentParameterValue(proto.Message): payload = proto.Field(proto.MESSAGE, number=8, message=struct.Struct,) + sentiment_analysis_result = proto.Field( + proto.MESSAGE, number=9, message=SentimentAnalysisResult, + ) + class WebhookResponse(proto.Message): r"""The response message for a webhook call. Attributes: - fulfillment_response (~.gcdc_webhook.WebhookResponse.FulfillmentResponse): + fulfillment_response (google.cloud.dialogflowcx_v3beta1.types.WebhookResponse.FulfillmentResponse): The fulfillment response to send to the user. This field can be omitted by the webhook if it does not intend to send any response to the user. - page_info (~.gcdc_webhook.PageInfo): + page_info (google.cloud.dialogflowcx_v3beta1.types.PageInfo): Information about page status. This field can be omitted by the webhook if it does not intend to modify page status. - session_info (~.gcdc_webhook.SessionInfo): + session_info (google.cloud.dialogflowcx_v3beta1.types.SessionInfo): Information about session status. This field can be omitted by the webhook if it does not intend to modify session status. - payload (~.struct.Struct): + payload (google.protobuf.struct_pb2.Struct): Value to append directly to [QueryResult.webhook_payloads][google.cloud.dialogflow.cx.v3beta1.QueryResult.webhook_payloads]. target_page (str): @@ -360,10 +397,10 @@ class FulfillmentResponse(proto.Message): r"""Represents a fulfillment response to the user. Attributes: - messages (Sequence[~.response_message.ResponseMessage]): + messages (Sequence[google.cloud.dialogflowcx_v3beta1.types.ResponseMessage]): The list of rich message responses to present to the user. - merge_behavior (~.gcdc_webhook.WebhookResponse.FulfillmentResponse.MergeBehavior): + merge_behavior (google.cloud.dialogflowcx_v3beta1.types.WebhookResponse.FulfillmentResponse.MergeBehavior): Merge behavior for ``messages``. """ @@ -410,7 +447,7 @@ class PageInfo(proto.Message): [WebhookResponse][google.cloud.dialogflow.cx.v3beta1.WebhookResponse]. The unique identifier of the current page. Format: ``projects//locations//agents//flows//pages/``. - form_info (~.gcdc_webhook.PageInfo.FormInfo): + form_info (google.cloud.dialogflowcx_v3beta1.types.PageInfo.FormInfo): Optional for both [WebhookRequest][google.cloud.dialogflow.cx.v3beta1.WebhookRequest] and @@ -422,7 +459,7 @@ class FormInfo(proto.Message): r"""Represents form information. Attributes: - parameter_info (Sequence[~.gcdc_webhook.PageInfo.FormInfo.ParameterInfo]): + parameter_info (Sequence[google.cloud.dialogflowcx_v3beta1.types.PageInfo.FormInfo.ParameterInfo]): Optional for both [WebhookRequest][google.cloud.dialogflow.cx.v3beta1.WebhookRequest] and @@ -451,7 +488,7 @@ class ParameterInfo(proto.Message): parameters will not trigger prompts; however, they are filled if the user specifies them. Required parameters must be filled before form filling concludes. - state (~.gcdc_webhook.PageInfo.FormInfo.ParameterInfo.ParameterState): + state (google.cloud.dialogflowcx_v3beta1.types.PageInfo.FormInfo.ParameterInfo.ParameterState): Always present for [WebhookRequest][google.cloud.dialogflow.cx.v3beta1.WebhookRequest]. Required for @@ -460,7 +497,7 @@ class ParameterInfo(proto.Message): [INVALID][google.cloud.dialogflow.cx.v3beta1.PageInfo.FormInfo.ParameterInfo.ParameterState.INVALID] by the webhook to invalidate the parameter; other values set by the webhook will be ignored. - value (~.struct.Value): + value (google.protobuf.struct_pb2.Value): Optional for both [WebhookRequest][google.cloud.dialogflow.cx.v3beta1.WebhookRequest] and @@ -518,10 +555,13 @@ class SessionInfo(proto.Message): [WebhookResponse][google.cloud.dialogflow.cx.v3beta1.WebhookResponse]. The unique identifier of the [session][google.cloud.dialogflow.cx.v3beta1.DetectIntentRequest.session]. - This field can be used by the webhook to identify a user. + This field can be used by the webhook to identify a session. Format: - ``projects//locations//agents//sessions/``. - parameters (Sequence[~.gcdc_webhook.SessionInfo.ParametersEntry]): + ``projects//locations//agents//sessions/`` + or + ``projects//locations//agents//environments//sessions/`` + if environment is specified. + parameters (Sequence[google.cloud.dialogflowcx_v3beta1.types.SessionInfo.ParametersEntry]): Optional for [WebhookRequest][google.cloud.dialogflow.cx.v3beta1.WebhookRequest]. Optional for diff --git a/noxfile.py b/noxfile.py index 87765339..0ad24c69 100644 --- a/noxfile.py +++ b/noxfile.py @@ -30,6 +30,17 @@ SYSTEM_TEST_PYTHON_VERSIONS = ["3.8"] UNIT_TEST_PYTHON_VERSIONS = ["3.6", "3.7", "3.8", "3.9"] +# 'docfx' is excluded since it only needs to run in 'docs-presubmit' +nox.options.sessions = [ + "unit", + "system", + "cover", + "lint", + "lint_setup_py", + "blacken", + "docs", +] + @nox.session(python=DEFAULT_PYTHON_VERSION) def lint(session): @@ -75,12 +86,14 @@ def default(session): session.install( "mock", "pytest", "pytest-cov", ) + session.install("-e", ".") # 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", @@ -110,6 +123,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) @@ -129,9 +145,21 @@ def system(session): # 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) diff --git a/synth.metadata b/synth.metadata index 4049b5a4..aea7c8f1 100644 --- a/synth.metadata +++ b/synth.metadata @@ -3,30 +3,30 @@ { "git": { "name": ".", - "remote": "https://github.com/googleapis/python-dialogflow-cx.git", - "sha": "09919b0e45517cedcbb1d8b5b931c7317be549b2" + "remote": "git@github.com:googleapis/python-dialogflow-cx", + "sha": "8854cbb793ceedf6a29b08c202f2a86c59387f2c" } }, { "git": { "name": "googleapis", "remote": "https://github.com/googleapis/googleapis.git", - "sha": "69697504d9eba1d064820c3085b4750767be6d08", - "internalRef": "348952930" + "sha": "369e98ef9cbae3fcbd9623ba084af51e54ddec65", + "internalRef": "361003369" } }, { "git": { "name": "synthtool", "remote": "https://github.com/googleapis/synthtool.git", - "sha": "373861061648b5fe5e0ac4f8a38b32d639ee93e4" + "sha": "6056faa36b3ab941a56f71eab8164e78af998844" } }, { "git": { "name": "synthtool", "remote": "https://github.com/googleapis/synthtool.git", - "sha": "373861061648b5fe5e0ac4f8a38b32d639ee93e4" + "sha": "6056faa36b3ab941a56f71eab8164e78af998844" } } ], @@ -49,352 +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/dialogflowcx_v3/services.rst", - "docs/dialogflowcx_v3/types.rst", - "docs/dialogflowcx_v3beta1/services.rst", - "docs/dialogflowcx_v3beta1/types.rst", - "docs/multiprocessing.rst", - "google/cloud/dialogflowcx/__init__.py", - "google/cloud/dialogflowcx/py.typed", - "google/cloud/dialogflowcx_v3/__init__.py", - "google/cloud/dialogflowcx_v3/py.typed", - "google/cloud/dialogflowcx_v3/services/__init__.py", - "google/cloud/dialogflowcx_v3/services/agents/__init__.py", - "google/cloud/dialogflowcx_v3/services/agents/async_client.py", - "google/cloud/dialogflowcx_v3/services/agents/client.py", - "google/cloud/dialogflowcx_v3/services/agents/pagers.py", - "google/cloud/dialogflowcx_v3/services/agents/transports/__init__.py", - "google/cloud/dialogflowcx_v3/services/agents/transports/base.py", - "google/cloud/dialogflowcx_v3/services/agents/transports/grpc.py", - "google/cloud/dialogflowcx_v3/services/agents/transports/grpc_asyncio.py", - "google/cloud/dialogflowcx_v3/services/entity_types/__init__.py", - "google/cloud/dialogflowcx_v3/services/entity_types/async_client.py", - "google/cloud/dialogflowcx_v3/services/entity_types/client.py", - "google/cloud/dialogflowcx_v3/services/entity_types/pagers.py", - "google/cloud/dialogflowcx_v3/services/entity_types/transports/__init__.py", - "google/cloud/dialogflowcx_v3/services/entity_types/transports/base.py", - "google/cloud/dialogflowcx_v3/services/entity_types/transports/grpc.py", - "google/cloud/dialogflowcx_v3/services/entity_types/transports/grpc_asyncio.py", - "google/cloud/dialogflowcx_v3/services/environments/__init__.py", - "google/cloud/dialogflowcx_v3/services/environments/async_client.py", - "google/cloud/dialogflowcx_v3/services/environments/client.py", - "google/cloud/dialogflowcx_v3/services/environments/pagers.py", - "google/cloud/dialogflowcx_v3/services/environments/transports/__init__.py", - "google/cloud/dialogflowcx_v3/services/environments/transports/base.py", - "google/cloud/dialogflowcx_v3/services/environments/transports/grpc.py", - "google/cloud/dialogflowcx_v3/services/environments/transports/grpc_asyncio.py", - "google/cloud/dialogflowcx_v3/services/experiments/__init__.py", - "google/cloud/dialogflowcx_v3/services/experiments/async_client.py", - "google/cloud/dialogflowcx_v3/services/experiments/client.py", - "google/cloud/dialogflowcx_v3/services/experiments/pagers.py", - "google/cloud/dialogflowcx_v3/services/experiments/transports/__init__.py", - "google/cloud/dialogflowcx_v3/services/experiments/transports/base.py", - "google/cloud/dialogflowcx_v3/services/experiments/transports/grpc.py", - "google/cloud/dialogflowcx_v3/services/experiments/transports/grpc_asyncio.py", - "google/cloud/dialogflowcx_v3/services/flows/__init__.py", - "google/cloud/dialogflowcx_v3/services/flows/async_client.py", - "google/cloud/dialogflowcx_v3/services/flows/client.py", - "google/cloud/dialogflowcx_v3/services/flows/pagers.py", - "google/cloud/dialogflowcx_v3/services/flows/transports/__init__.py", - "google/cloud/dialogflowcx_v3/services/flows/transports/base.py", - "google/cloud/dialogflowcx_v3/services/flows/transports/grpc.py", - "google/cloud/dialogflowcx_v3/services/flows/transports/grpc_asyncio.py", - "google/cloud/dialogflowcx_v3/services/intents/__init__.py", - "google/cloud/dialogflowcx_v3/services/intents/async_client.py", - "google/cloud/dialogflowcx_v3/services/intents/client.py", - "google/cloud/dialogflowcx_v3/services/intents/pagers.py", - "google/cloud/dialogflowcx_v3/services/intents/transports/__init__.py", - "google/cloud/dialogflowcx_v3/services/intents/transports/base.py", - "google/cloud/dialogflowcx_v3/services/intents/transports/grpc.py", - "google/cloud/dialogflowcx_v3/services/intents/transports/grpc_asyncio.py", - "google/cloud/dialogflowcx_v3/services/pages/__init__.py", - "google/cloud/dialogflowcx_v3/services/pages/async_client.py", - "google/cloud/dialogflowcx_v3/services/pages/client.py", - "google/cloud/dialogflowcx_v3/services/pages/pagers.py", - "google/cloud/dialogflowcx_v3/services/pages/transports/__init__.py", - "google/cloud/dialogflowcx_v3/services/pages/transports/base.py", - "google/cloud/dialogflowcx_v3/services/pages/transports/grpc.py", - "google/cloud/dialogflowcx_v3/services/pages/transports/grpc_asyncio.py", - "google/cloud/dialogflowcx_v3/services/security_settings_service/__init__.py", - "google/cloud/dialogflowcx_v3/services/security_settings_service/async_client.py", - "google/cloud/dialogflowcx_v3/services/security_settings_service/client.py", - "google/cloud/dialogflowcx_v3/services/security_settings_service/pagers.py", - "google/cloud/dialogflowcx_v3/services/security_settings_service/transports/__init__.py", - "google/cloud/dialogflowcx_v3/services/security_settings_service/transports/base.py", - "google/cloud/dialogflowcx_v3/services/security_settings_service/transports/grpc.py", - "google/cloud/dialogflowcx_v3/services/security_settings_service/transports/grpc_asyncio.py", - "google/cloud/dialogflowcx_v3/services/session_entity_types/__init__.py", - "google/cloud/dialogflowcx_v3/services/session_entity_types/async_client.py", - "google/cloud/dialogflowcx_v3/services/session_entity_types/client.py", - "google/cloud/dialogflowcx_v3/services/session_entity_types/pagers.py", - "google/cloud/dialogflowcx_v3/services/session_entity_types/transports/__init__.py", - "google/cloud/dialogflowcx_v3/services/session_entity_types/transports/base.py", - "google/cloud/dialogflowcx_v3/services/session_entity_types/transports/grpc.py", - "google/cloud/dialogflowcx_v3/services/session_entity_types/transports/grpc_asyncio.py", - "google/cloud/dialogflowcx_v3/services/sessions/__init__.py", - "google/cloud/dialogflowcx_v3/services/sessions/async_client.py", - "google/cloud/dialogflowcx_v3/services/sessions/client.py", - "google/cloud/dialogflowcx_v3/services/sessions/transports/__init__.py", - "google/cloud/dialogflowcx_v3/services/sessions/transports/base.py", - "google/cloud/dialogflowcx_v3/services/sessions/transports/grpc.py", - "google/cloud/dialogflowcx_v3/services/sessions/transports/grpc_asyncio.py", - "google/cloud/dialogflowcx_v3/services/transition_route_groups/__init__.py", - "google/cloud/dialogflowcx_v3/services/transition_route_groups/async_client.py", - "google/cloud/dialogflowcx_v3/services/transition_route_groups/client.py", - "google/cloud/dialogflowcx_v3/services/transition_route_groups/pagers.py", - "google/cloud/dialogflowcx_v3/services/transition_route_groups/transports/__init__.py", - "google/cloud/dialogflowcx_v3/services/transition_route_groups/transports/base.py", - "google/cloud/dialogflowcx_v3/services/transition_route_groups/transports/grpc.py", - "google/cloud/dialogflowcx_v3/services/transition_route_groups/transports/grpc_asyncio.py", - "google/cloud/dialogflowcx_v3/services/versions/__init__.py", - "google/cloud/dialogflowcx_v3/services/versions/async_client.py", - "google/cloud/dialogflowcx_v3/services/versions/client.py", - "google/cloud/dialogflowcx_v3/services/versions/pagers.py", - "google/cloud/dialogflowcx_v3/services/versions/transports/__init__.py", - "google/cloud/dialogflowcx_v3/services/versions/transports/base.py", - "google/cloud/dialogflowcx_v3/services/versions/transports/grpc.py", - "google/cloud/dialogflowcx_v3/services/versions/transports/grpc_asyncio.py", - "google/cloud/dialogflowcx_v3/services/webhooks/__init__.py", - "google/cloud/dialogflowcx_v3/services/webhooks/async_client.py", - "google/cloud/dialogflowcx_v3/services/webhooks/client.py", - "google/cloud/dialogflowcx_v3/services/webhooks/pagers.py", - "google/cloud/dialogflowcx_v3/services/webhooks/transports/__init__.py", - "google/cloud/dialogflowcx_v3/services/webhooks/transports/base.py", - "google/cloud/dialogflowcx_v3/services/webhooks/transports/grpc.py", - "google/cloud/dialogflowcx_v3/services/webhooks/transports/grpc_asyncio.py", - "google/cloud/dialogflowcx_v3/types/__init__.py", - "google/cloud/dialogflowcx_v3/types/agent.py", - "google/cloud/dialogflowcx_v3/types/audio_config.py", - "google/cloud/dialogflowcx_v3/types/entity_type.py", - "google/cloud/dialogflowcx_v3/types/environment.py", - "google/cloud/dialogflowcx_v3/types/experiment.py", - "google/cloud/dialogflowcx_v3/types/flow.py", - "google/cloud/dialogflowcx_v3/types/fulfillment.py", - "google/cloud/dialogflowcx_v3/types/intent.py", - "google/cloud/dialogflowcx_v3/types/page.py", - "google/cloud/dialogflowcx_v3/types/response_message.py", - "google/cloud/dialogflowcx_v3/types/security_settings.py", - "google/cloud/dialogflowcx_v3/types/session.py", - "google/cloud/dialogflowcx_v3/types/session_entity_type.py", - "google/cloud/dialogflowcx_v3/types/transition_route_group.py", - "google/cloud/dialogflowcx_v3/types/version.py", - "google/cloud/dialogflowcx_v3/types/webhook.py", - "google/cloud/dialogflowcx_v3beta1/__init__.py", - "google/cloud/dialogflowcx_v3beta1/py.typed", - "google/cloud/dialogflowcx_v3beta1/services/__init__.py", - "google/cloud/dialogflowcx_v3beta1/services/agents/__init__.py", - "google/cloud/dialogflowcx_v3beta1/services/agents/async_client.py", - "google/cloud/dialogflowcx_v3beta1/services/agents/client.py", - "google/cloud/dialogflowcx_v3beta1/services/agents/pagers.py", - "google/cloud/dialogflowcx_v3beta1/services/agents/transports/__init__.py", - "google/cloud/dialogflowcx_v3beta1/services/agents/transports/base.py", - "google/cloud/dialogflowcx_v3beta1/services/agents/transports/grpc.py", - "google/cloud/dialogflowcx_v3beta1/services/agents/transports/grpc_asyncio.py", - "google/cloud/dialogflowcx_v3beta1/services/entity_types/__init__.py", - "google/cloud/dialogflowcx_v3beta1/services/entity_types/async_client.py", - "google/cloud/dialogflowcx_v3beta1/services/entity_types/client.py", - "google/cloud/dialogflowcx_v3beta1/services/entity_types/pagers.py", - "google/cloud/dialogflowcx_v3beta1/services/entity_types/transports/__init__.py", - "google/cloud/dialogflowcx_v3beta1/services/entity_types/transports/base.py", - "google/cloud/dialogflowcx_v3beta1/services/entity_types/transports/grpc.py", - "google/cloud/dialogflowcx_v3beta1/services/entity_types/transports/grpc_asyncio.py", - "google/cloud/dialogflowcx_v3beta1/services/environments/__init__.py", - "google/cloud/dialogflowcx_v3beta1/services/environments/async_client.py", - "google/cloud/dialogflowcx_v3beta1/services/environments/client.py", - "google/cloud/dialogflowcx_v3beta1/services/environments/pagers.py", - "google/cloud/dialogflowcx_v3beta1/services/environments/transports/__init__.py", - "google/cloud/dialogflowcx_v3beta1/services/environments/transports/base.py", - "google/cloud/dialogflowcx_v3beta1/services/environments/transports/grpc.py", - "google/cloud/dialogflowcx_v3beta1/services/environments/transports/grpc_asyncio.py", - "google/cloud/dialogflowcx_v3beta1/services/experiments/__init__.py", - "google/cloud/dialogflowcx_v3beta1/services/experiments/async_client.py", - "google/cloud/dialogflowcx_v3beta1/services/experiments/client.py", - "google/cloud/dialogflowcx_v3beta1/services/experiments/pagers.py", - "google/cloud/dialogflowcx_v3beta1/services/experiments/transports/__init__.py", - "google/cloud/dialogflowcx_v3beta1/services/experiments/transports/base.py", - "google/cloud/dialogflowcx_v3beta1/services/experiments/transports/grpc.py", - "google/cloud/dialogflowcx_v3beta1/services/experiments/transports/grpc_asyncio.py", - "google/cloud/dialogflowcx_v3beta1/services/flows/__init__.py", - "google/cloud/dialogflowcx_v3beta1/services/flows/async_client.py", - "google/cloud/dialogflowcx_v3beta1/services/flows/client.py", - "google/cloud/dialogflowcx_v3beta1/services/flows/pagers.py", - "google/cloud/dialogflowcx_v3beta1/services/flows/transports/__init__.py", - "google/cloud/dialogflowcx_v3beta1/services/flows/transports/base.py", - "google/cloud/dialogflowcx_v3beta1/services/flows/transports/grpc.py", - "google/cloud/dialogflowcx_v3beta1/services/flows/transports/grpc_asyncio.py", - "google/cloud/dialogflowcx_v3beta1/services/intents/__init__.py", - "google/cloud/dialogflowcx_v3beta1/services/intents/async_client.py", - "google/cloud/dialogflowcx_v3beta1/services/intents/client.py", - "google/cloud/dialogflowcx_v3beta1/services/intents/pagers.py", - "google/cloud/dialogflowcx_v3beta1/services/intents/transports/__init__.py", - "google/cloud/dialogflowcx_v3beta1/services/intents/transports/base.py", - "google/cloud/dialogflowcx_v3beta1/services/intents/transports/grpc.py", - "google/cloud/dialogflowcx_v3beta1/services/intents/transports/grpc_asyncio.py", - "google/cloud/dialogflowcx_v3beta1/services/pages/__init__.py", - "google/cloud/dialogflowcx_v3beta1/services/pages/async_client.py", - "google/cloud/dialogflowcx_v3beta1/services/pages/client.py", - "google/cloud/dialogflowcx_v3beta1/services/pages/pagers.py", - "google/cloud/dialogflowcx_v3beta1/services/pages/transports/__init__.py", - "google/cloud/dialogflowcx_v3beta1/services/pages/transports/base.py", - "google/cloud/dialogflowcx_v3beta1/services/pages/transports/grpc.py", - "google/cloud/dialogflowcx_v3beta1/services/pages/transports/grpc_asyncio.py", - "google/cloud/dialogflowcx_v3beta1/services/security_settings_service/__init__.py", - "google/cloud/dialogflowcx_v3beta1/services/security_settings_service/async_client.py", - "google/cloud/dialogflowcx_v3beta1/services/security_settings_service/client.py", - "google/cloud/dialogflowcx_v3beta1/services/security_settings_service/pagers.py", - "google/cloud/dialogflowcx_v3beta1/services/security_settings_service/transports/__init__.py", - "google/cloud/dialogflowcx_v3beta1/services/security_settings_service/transports/base.py", - "google/cloud/dialogflowcx_v3beta1/services/security_settings_service/transports/grpc.py", - "google/cloud/dialogflowcx_v3beta1/services/security_settings_service/transports/grpc_asyncio.py", - "google/cloud/dialogflowcx_v3beta1/services/session_entity_types/__init__.py", - "google/cloud/dialogflowcx_v3beta1/services/session_entity_types/async_client.py", - "google/cloud/dialogflowcx_v3beta1/services/session_entity_types/client.py", - "google/cloud/dialogflowcx_v3beta1/services/session_entity_types/pagers.py", - "google/cloud/dialogflowcx_v3beta1/services/session_entity_types/transports/__init__.py", - "google/cloud/dialogflowcx_v3beta1/services/session_entity_types/transports/base.py", - "google/cloud/dialogflowcx_v3beta1/services/session_entity_types/transports/grpc.py", - "google/cloud/dialogflowcx_v3beta1/services/session_entity_types/transports/grpc_asyncio.py", - "google/cloud/dialogflowcx_v3beta1/services/sessions/__init__.py", - "google/cloud/dialogflowcx_v3beta1/services/sessions/async_client.py", - "google/cloud/dialogflowcx_v3beta1/services/sessions/client.py", - "google/cloud/dialogflowcx_v3beta1/services/sessions/transports/__init__.py", - "google/cloud/dialogflowcx_v3beta1/services/sessions/transports/base.py", - "google/cloud/dialogflowcx_v3beta1/services/sessions/transports/grpc.py", - "google/cloud/dialogflowcx_v3beta1/services/sessions/transports/grpc_asyncio.py", - "google/cloud/dialogflowcx_v3beta1/services/transition_route_groups/__init__.py", - "google/cloud/dialogflowcx_v3beta1/services/transition_route_groups/async_client.py", - "google/cloud/dialogflowcx_v3beta1/services/transition_route_groups/client.py", - "google/cloud/dialogflowcx_v3beta1/services/transition_route_groups/pagers.py", - "google/cloud/dialogflowcx_v3beta1/services/transition_route_groups/transports/__init__.py", - "google/cloud/dialogflowcx_v3beta1/services/transition_route_groups/transports/base.py", - "google/cloud/dialogflowcx_v3beta1/services/transition_route_groups/transports/grpc.py", - "google/cloud/dialogflowcx_v3beta1/services/transition_route_groups/transports/grpc_asyncio.py", - "google/cloud/dialogflowcx_v3beta1/services/versions/__init__.py", - "google/cloud/dialogflowcx_v3beta1/services/versions/async_client.py", - "google/cloud/dialogflowcx_v3beta1/services/versions/client.py", - "google/cloud/dialogflowcx_v3beta1/services/versions/pagers.py", - "google/cloud/dialogflowcx_v3beta1/services/versions/transports/__init__.py", - "google/cloud/dialogflowcx_v3beta1/services/versions/transports/base.py", - "google/cloud/dialogflowcx_v3beta1/services/versions/transports/grpc.py", - "google/cloud/dialogflowcx_v3beta1/services/versions/transports/grpc_asyncio.py", - "google/cloud/dialogflowcx_v3beta1/services/webhooks/__init__.py", - "google/cloud/dialogflowcx_v3beta1/services/webhooks/async_client.py", - "google/cloud/dialogflowcx_v3beta1/services/webhooks/client.py", - "google/cloud/dialogflowcx_v3beta1/services/webhooks/pagers.py", - "google/cloud/dialogflowcx_v3beta1/services/webhooks/transports/__init__.py", - "google/cloud/dialogflowcx_v3beta1/services/webhooks/transports/base.py", - "google/cloud/dialogflowcx_v3beta1/services/webhooks/transports/grpc.py", - "google/cloud/dialogflowcx_v3beta1/services/webhooks/transports/grpc_asyncio.py", - "google/cloud/dialogflowcx_v3beta1/types/__init__.py", - "google/cloud/dialogflowcx_v3beta1/types/agent.py", - "google/cloud/dialogflowcx_v3beta1/types/audio_config.py", - "google/cloud/dialogflowcx_v3beta1/types/entity_type.py", - "google/cloud/dialogflowcx_v3beta1/types/environment.py", - "google/cloud/dialogflowcx_v3beta1/types/experiment.py", - "google/cloud/dialogflowcx_v3beta1/types/flow.py", - "google/cloud/dialogflowcx_v3beta1/types/fulfillment.py", - "google/cloud/dialogflowcx_v3beta1/types/intent.py", - "google/cloud/dialogflowcx_v3beta1/types/page.py", - "google/cloud/dialogflowcx_v3beta1/types/response_message.py", - "google/cloud/dialogflowcx_v3beta1/types/security_settings.py", - "google/cloud/dialogflowcx_v3beta1/types/session.py", - "google/cloud/dialogflowcx_v3beta1/types/session_entity_type.py", - "google/cloud/dialogflowcx_v3beta1/types/transition_route_group.py", - "google/cloud/dialogflowcx_v3beta1/types/version.py", - "google/cloud/dialogflowcx_v3beta1/types/webhook.py", - "mypy.ini", - "noxfile.py", - "renovate.json", - "scripts/decrypt-secrets.sh", - "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/dialogflowcx_v3/__init__.py", - "tests/unit/gapic/dialogflowcx_v3/test_agents.py", - "tests/unit/gapic/dialogflowcx_v3/test_entity_types.py", - "tests/unit/gapic/dialogflowcx_v3/test_environments.py", - "tests/unit/gapic/dialogflowcx_v3/test_experiments.py", - "tests/unit/gapic/dialogflowcx_v3/test_flows.py", - "tests/unit/gapic/dialogflowcx_v3/test_intents.py", - "tests/unit/gapic/dialogflowcx_v3/test_pages.py", - "tests/unit/gapic/dialogflowcx_v3/test_security_settings_service.py", - "tests/unit/gapic/dialogflowcx_v3/test_session_entity_types.py", - "tests/unit/gapic/dialogflowcx_v3/test_sessions.py", - "tests/unit/gapic/dialogflowcx_v3/test_transition_route_groups.py", - "tests/unit/gapic/dialogflowcx_v3/test_versions.py", - "tests/unit/gapic/dialogflowcx_v3/test_webhooks.py", - "tests/unit/gapic/dialogflowcx_v3beta1/__init__.py", - "tests/unit/gapic/dialogflowcx_v3beta1/test_agents.py", - "tests/unit/gapic/dialogflowcx_v3beta1/test_entity_types.py", - "tests/unit/gapic/dialogflowcx_v3beta1/test_environments.py", - "tests/unit/gapic/dialogflowcx_v3beta1/test_experiments.py", - "tests/unit/gapic/dialogflowcx_v3beta1/test_flows.py", - "tests/unit/gapic/dialogflowcx_v3beta1/test_intents.py", - "tests/unit/gapic/dialogflowcx_v3beta1/test_pages.py", - "tests/unit/gapic/dialogflowcx_v3beta1/test_security_settings_service.py", - "tests/unit/gapic/dialogflowcx_v3beta1/test_session_entity_types.py", - "tests/unit/gapic/dialogflowcx_v3beta1/test_sessions.py", - "tests/unit/gapic/dialogflowcx_v3beta1/test_transition_route_groups.py", - "tests/unit/gapic/dialogflowcx_v3beta1/test_versions.py", - "tests/unit/gapic/dialogflowcx_v3beta1/test_webhooks.py" ] } \ No newline at end of file diff --git a/tests/unit/gapic/dialogflowcx_v3/__init__.py b/tests/unit/gapic/dialogflowcx_v3/__init__.py index 8b137891..42ffdf2b 100644 --- a/tests/unit/gapic/dialogflowcx_v3/__init__.py +++ b/tests/unit/gapic/dialogflowcx_v3/__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/dialogflowcx_v3/test_agents.py b/tests/unit/gapic/dialogflowcx_v3/test_agents.py index f58083c2..64e50b3e 100644 --- a/tests/unit/gapic/dialogflowcx_v3/test_agents.py +++ b/tests/unit/gapic/dialogflowcx_v3/test_agents.py @@ -41,6 +41,7 @@ from google.cloud.dialogflowcx_v3.services.agents import transports from google.cloud.dialogflowcx_v3.types import agent from google.cloud.dialogflowcx_v3.types import agent as gcdc_agent +from google.cloud.dialogflowcx_v3.types import flow from google.longrunning import operations_pb2 from google.oauth2 import service_account from google.protobuf import field_mask_pb2 as field_mask # type: ignore @@ -85,7 +86,22 @@ def test__get_default_mtls_endpoint(): assert AgentsClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi -@pytest.mark.parametrize("client_class", [AgentsClient, AgentsAsyncClient]) +@pytest.mark.parametrize("client_class", [AgentsClient, AgentsAsyncClient,]) +def test_agents_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 == "dialogflow.googleapis.com:443" + + +@pytest.mark.parametrize("client_class", [AgentsClient, AgentsAsyncClient,]) def test_agents_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() with mock.patch.object( @@ -94,16 +110,21 @@ def test_agents_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 == "dialogflow.googleapis.com:443" def test_agents_client_get_transport_class(): transport = AgentsClient.get_transport_class() - assert transport == transports.AgentsGrpcTransport + available_transports = [ + transports.AgentsGrpcTransport, + ] + assert transport in available_transports transport = AgentsClient.get_transport_class("grpc") assert transport == transports.AgentsGrpcTransport @@ -144,7 +165,7 @@ def test_agents_client_client_options(client_class, transport_class, transport_n 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, ) @@ -160,7 +181,7 @@ def test_agents_client_client_options(client_class, transport_class, transport_n 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, ) @@ -176,7 +197,7 @@ def test_agents_client_client_options(client_class, transport_class, transport_n 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, ) @@ -204,7 +225,7 @@ def test_agents_client_client_options(client_class, transport_class, transport_n 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, ) @@ -251,29 +272,25 @@ def test_agents_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. @@ -282,66 +299,53 @@ def test_agents_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", @@ -363,7 +367,7 @@ def test_agents_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, ) @@ -389,7 +393,7 @@ def test_agents_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, ) @@ -406,7 +410,7 @@ def test_agents_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, ) @@ -447,6 +451,22 @@ def test_list_agents_from_dict(): test_list_agents(request_type=dict) +def test_list_agents_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 = AgentsClient( + 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_agents), "__call__") as call: + client.list_agents() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == agent.ListAgentsRequest() + + @pytest.mark.asyncio async def test_list_agents_async( transport: str = "grpc_asyncio", request_type=agent.ListAgentsRequest @@ -729,6 +749,7 @@ def test_get_agent(transport: str = "grpc", request_type=agent.GetAgentRequest): description="description_value", avatar_uri="avatar_uri_value", start_flow="start_flow_value", + security_settings="security_settings_value", enable_stackdriver_logging=True, enable_spell_correction=True, ) @@ -759,6 +780,8 @@ def test_get_agent(transport: str = "grpc", request_type=agent.GetAgentRequest): assert response.start_flow == "start_flow_value" + assert response.security_settings == "security_settings_value" + assert response.enable_stackdriver_logging is True assert response.enable_spell_correction is True @@ -768,6 +791,22 @@ def test_get_agent_from_dict(): test_get_agent(request_type=dict) +def test_get_agent_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 = AgentsClient( + 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_agent), "__call__") as call: + client.get_agent() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == agent.GetAgentRequest() + + @pytest.mark.asyncio async def test_get_agent_async( transport: str = "grpc_asyncio", request_type=agent.GetAgentRequest @@ -792,6 +831,7 @@ async def test_get_agent_async( description="description_value", avatar_uri="avatar_uri_value", start_flow="start_flow_value", + security_settings="security_settings_value", enable_stackdriver_logging=True, enable_spell_correction=True, ) @@ -822,6 +862,8 @@ async def test_get_agent_async( assert response.start_flow == "start_flow_value" + assert response.security_settings == "security_settings_value" + assert response.enable_stackdriver_logging is True assert response.enable_spell_correction is True @@ -968,6 +1010,7 @@ def test_create_agent( description="description_value", avatar_uri="avatar_uri_value", start_flow="start_flow_value", + security_settings="security_settings_value", enable_stackdriver_logging=True, enable_spell_correction=True, ) @@ -998,6 +1041,8 @@ def test_create_agent( assert response.start_flow == "start_flow_value" + assert response.security_settings == "security_settings_value" + assert response.enable_stackdriver_logging is True assert response.enable_spell_correction is True @@ -1007,6 +1052,22 @@ def test_create_agent_from_dict(): test_create_agent(request_type=dict) +def test_create_agent_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 = AgentsClient( + 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_agent), "__call__") as call: + client.create_agent() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_agent.CreateAgentRequest() + + @pytest.mark.asyncio async def test_create_agent_async( transport: str = "grpc_asyncio", request_type=gcdc_agent.CreateAgentRequest @@ -1031,6 +1092,7 @@ async def test_create_agent_async( description="description_value", avatar_uri="avatar_uri_value", start_flow="start_flow_value", + security_settings="security_settings_value", enable_stackdriver_logging=True, enable_spell_correction=True, ) @@ -1061,6 +1123,8 @@ async def test_create_agent_async( assert response.start_flow == "start_flow_value" + assert response.security_settings == "security_settings_value" + assert response.enable_stackdriver_logging is True assert response.enable_spell_correction is True @@ -1219,6 +1283,7 @@ def test_update_agent( description="description_value", avatar_uri="avatar_uri_value", start_flow="start_flow_value", + security_settings="security_settings_value", enable_stackdriver_logging=True, enable_spell_correction=True, ) @@ -1249,6 +1314,8 @@ def test_update_agent( assert response.start_flow == "start_flow_value" + assert response.security_settings == "security_settings_value" + assert response.enable_stackdriver_logging is True assert response.enable_spell_correction is True @@ -1258,6 +1325,22 @@ def test_update_agent_from_dict(): test_update_agent(request_type=dict) +def test_update_agent_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 = AgentsClient( + 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_agent), "__call__") as call: + client.update_agent() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_agent.UpdateAgentRequest() + + @pytest.mark.asyncio async def test_update_agent_async( transport: str = "grpc_asyncio", request_type=gcdc_agent.UpdateAgentRequest @@ -1282,6 +1365,7 @@ async def test_update_agent_async( description="description_value", avatar_uri="avatar_uri_value", start_flow="start_flow_value", + security_settings="security_settings_value", enable_stackdriver_logging=True, enable_spell_correction=True, ) @@ -1312,6 +1396,8 @@ async def test_update_agent_async( assert response.start_flow == "start_flow_value" + assert response.security_settings == "security_settings_value" + assert response.enable_stackdriver_logging is True assert response.enable_spell_correction is True @@ -1480,6 +1566,22 @@ def test_delete_agent_from_dict(): test_delete_agent(request_type=dict) +def test_delete_agent_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 = AgentsClient( + 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_agent), "__call__") as call: + client.delete_agent() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == agent.DeleteAgentRequest() + + @pytest.mark.asyncio async def test_delete_agent_async( transport: str = "grpc_asyncio", request_type=agent.DeleteAgentRequest @@ -1658,6 +1760,22 @@ def test_export_agent_from_dict(): test_export_agent(request_type=dict) +def test_export_agent_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 = AgentsClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.export_agent), "__call__") as call: + client.export_agent() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == agent.ExportAgentRequest() + + @pytest.mark.asyncio async def test_export_agent_async( transport: str = "grpc_asyncio", request_type=agent.ExportAgentRequest @@ -1775,6 +1893,22 @@ def test_restore_agent_from_dict(): test_restore_agent(request_type=dict) +def test_restore_agent_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 = AgentsClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.restore_agent), "__call__") as call: + client.restore_agent() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == agent.RestoreAgentRequest() + + @pytest.mark.asyncio async def test_restore_agent_async( transport: str = "grpc_asyncio", request_type=agent.RestoreAgentRequest @@ -1862,6 +1996,367 @@ async def test_restore_agent_field_headers_async(): assert ("x-goog-request-params", "name=name/value",) in kw["metadata"] +def test_validate_agent( + transport: str = "grpc", request_type=agent.ValidateAgentRequest +): + client = AgentsClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.validate_agent), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = agent.AgentValidationResult(name="name_value",) + + response = client.validate_agent(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0] == agent.ValidateAgentRequest() + + # Establish that the response is the type that we expect. + + assert isinstance(response, agent.AgentValidationResult) + + assert response.name == "name_value" + + +def test_validate_agent_from_dict(): + test_validate_agent(request_type=dict) + + +def test_validate_agent_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 = AgentsClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.validate_agent), "__call__") as call: + client.validate_agent() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == agent.ValidateAgentRequest() + + +@pytest.mark.asyncio +async def test_validate_agent_async( + transport: str = "grpc_asyncio", request_type=agent.ValidateAgentRequest +): + client = AgentsAsyncClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.validate_agent), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + agent.AgentValidationResult(name="name_value",) + ) + + response = await client.validate_agent(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0] == agent.ValidateAgentRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, agent.AgentValidationResult) + + assert response.name == "name_value" + + +@pytest.mark.asyncio +async def test_validate_agent_async_from_dict(): + await test_validate_agent_async(request_type=dict) + + +def test_validate_agent_field_headers(): + client = AgentsClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = agent.ValidateAgentRequest() + request.name = "name/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.validate_agent), "__call__") as call: + call.return_value = agent.AgentValidationResult() + + client.validate_agent(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "name=name/value",) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_validate_agent_field_headers_async(): + client = AgentsAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = agent.ValidateAgentRequest() + request.name = "name/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.validate_agent), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + agent.AgentValidationResult() + ) + + await client.validate_agent(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "name=name/value",) in kw["metadata"] + + +def test_get_agent_validation_result( + transport: str = "grpc", request_type=agent.GetAgentValidationResultRequest +): + client = AgentsClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_agent_validation_result), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = agent.AgentValidationResult(name="name_value",) + + response = client.get_agent_validation_result(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0] == agent.GetAgentValidationResultRequest() + + # Establish that the response is the type that we expect. + + assert isinstance(response, agent.AgentValidationResult) + + assert response.name == "name_value" + + +def test_get_agent_validation_result_from_dict(): + test_get_agent_validation_result(request_type=dict) + + +def test_get_agent_validation_result_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 = AgentsClient( + 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_agent_validation_result), "__call__" + ) as call: + client.get_agent_validation_result() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == agent.GetAgentValidationResultRequest() + + +@pytest.mark.asyncio +async def test_get_agent_validation_result_async( + transport: str = "grpc_asyncio", request_type=agent.GetAgentValidationResultRequest +): + client = AgentsAsyncClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_agent_validation_result), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + agent.AgentValidationResult(name="name_value",) + ) + + response = await client.get_agent_validation_result(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0] == agent.GetAgentValidationResultRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, agent.AgentValidationResult) + + assert response.name == "name_value" + + +@pytest.mark.asyncio +async def test_get_agent_validation_result_async_from_dict(): + await test_get_agent_validation_result_async(request_type=dict) + + +def test_get_agent_validation_result_field_headers(): + client = AgentsClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = agent.GetAgentValidationResultRequest() + request.name = "name/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_agent_validation_result), "__call__" + ) as call: + call.return_value = agent.AgentValidationResult() + + client.get_agent_validation_result(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "name=name/value",) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_get_agent_validation_result_field_headers_async(): + client = AgentsAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = agent.GetAgentValidationResultRequest() + request.name = "name/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_agent_validation_result), "__call__" + ) as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + agent.AgentValidationResult() + ) + + await client.get_agent_validation_result(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "name=name/value",) in kw["metadata"] + + +def test_get_agent_validation_result_flattened(): + client = AgentsClient(credentials=credentials.AnonymousCredentials(),) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_agent_validation_result), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = agent.AgentValidationResult() + + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.get_agent_validation_result(name="name_value",) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0].name == "name_value" + + +def test_get_agent_validation_result_flattened_error(): + client = AgentsClient(credentials=credentials.AnonymousCredentials(),) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.get_agent_validation_result( + agent.GetAgentValidationResultRequest(), name="name_value", + ) + + +@pytest.mark.asyncio +async def test_get_agent_validation_result_flattened_async(): + client = AgentsAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_agent_validation_result), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = agent.AgentValidationResult() + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + agent.AgentValidationResult() + ) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.get_agent_validation_result(name="name_value",) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0].name == "name_value" + + +@pytest.mark.asyncio +async def test_get_agent_validation_result_flattened_error_async(): + client = AgentsAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.get_agent_validation_result( + agent.GetAgentValidationResultRequest(), name="name_value", + ) + + def test_credentials_transport_error(): # It is an error to provide credentials and a transport instance. transport = transports.AgentsGrpcTransport( @@ -1918,7 +2413,7 @@ def test_transport_get_channel(): @pytest.mark.parametrize( "transport_class", - [transports.AgentsGrpcTransport, transports.AgentsGrpcAsyncIOTransport], + [transports.AgentsGrpcTransport, transports.AgentsGrpcAsyncIOTransport,], ) def test_transport_adc(transport_class): # Test default credentials are used if not provided. @@ -1963,6 +2458,8 @@ def test_agents_base_transport(): "delete_agent", "export_agent", "restore_agent", + "validate_agent", + "get_agent_validation_result", ) for method in methods: with pytest.raises(NotImplementedError): @@ -2038,6 +2535,51 @@ def test_agents_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [transports.AgentsGrpcTransport, transports.AgentsGrpcAsyncIOTransport], +) +def test_agents_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/dialogflow", + ), + 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_agents_host_no_port(): client = AgentsClient( credentials=credentials.AnonymousCredentials(), @@ -2059,7 +2601,7 @@ def test_agents_host_with_port(): def test_agents_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.AgentsGrpcTransport( @@ -2071,7 +2613,7 @@ def test_agents_grpc_transport_channel(): def test_agents_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.AgentsGrpcAsyncIOTransport( @@ -2082,6 +2624,8 @@ def test_agents_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.AgentsGrpcTransport, transports.AgentsGrpcAsyncIOTransport], @@ -2091,7 +2635,7 @@ def test_agents_transport_channel_mtls_with_client_cert_source(transport_class): "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 @@ -2132,6 +2676,8 @@ def test_agents_transport_channel_mtls_with_client_cert_source(transport_class): 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.AgentsGrpcTransport, transports.AgentsGrpcAsyncIOTransport], @@ -2144,7 +2690,7 @@ def test_agents_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 @@ -2227,11 +2773,36 @@ def test_parse_agent_path(): assert expected == actual -def test_flow_path(): +def test_agent_validation_result_path(): project = "cuttlefish" location = "mussel" agent = "winkle" - flow = "nautilus" + + expected = "projects/{project}/locations/{location}/agents/{agent}/validationResult".format( + project=project, location=location, agent=agent, + ) + actual = AgentsClient.agent_validation_result_path(project, location, agent) + assert expected == actual + + +def test_parse_agent_validation_result_path(): + expected = { + "project": "nautilus", + "location": "scallop", + "agent": "abalone", + } + path = AgentsClient.agent_validation_result_path(**expected) + + # Check that the path construction is reversible. + actual = AgentsClient.parse_agent_validation_result_path(path) + assert expected == actual + + +def test_flow_path(): + project = "squid" + location = "clam" + agent = "whelk" + flow = "octopus" expected = "projects/{project}/locations/{location}/agents/{agent}/flows/{flow}".format( project=project, location=location, agent=agent, flow=flow, @@ -2242,10 +2813,10 @@ def test_flow_path(): def test_parse_flow_path(): expected = { - "project": "scallop", - "location": "abalone", - "agent": "squid", - "flow": "clam", + "project": "oyster", + "location": "nudibranch", + "agent": "cuttlefish", + "flow": "mussel", } path = AgentsClient.flow_path(**expected) @@ -2254,8 +2825,60 @@ def test_parse_flow_path(): assert expected == actual +def test_flow_validation_result_path(): + project = "winkle" + location = "nautilus" + agent = "scallop" + flow = "abalone" + + expected = "projects/{project}/locations/{location}/agents/{agent}/flows/{flow}/validationResult".format( + project=project, location=location, agent=agent, flow=flow, + ) + actual = AgentsClient.flow_validation_result_path(project, location, agent, flow) + assert expected == actual + + +def test_parse_flow_validation_result_path(): + expected = { + "project": "squid", + "location": "clam", + "agent": "whelk", + "flow": "octopus", + } + path = AgentsClient.flow_validation_result_path(**expected) + + # Check that the path construction is reversible. + actual = AgentsClient.parse_flow_validation_result_path(path) + assert expected == actual + + +def test_security_settings_path(): + project = "oyster" + location = "nudibranch" + security_settings = "cuttlefish" + + expected = "projects/{project}/locations/{location}/securitySettings/{security_settings}".format( + project=project, location=location, security_settings=security_settings, + ) + actual = AgentsClient.security_settings_path(project, location, security_settings) + assert expected == actual + + +def test_parse_security_settings_path(): + expected = { + "project": "mussel", + "location": "winkle", + "security_settings": "nautilus", + } + path = AgentsClient.security_settings_path(**expected) + + # Check that the path construction is reversible. + actual = AgentsClient.parse_security_settings_path(path) + assert expected == actual + + def test_common_billing_account_path(): - billing_account = "whelk" + billing_account = "scallop" expected = "billingAccounts/{billing_account}".format( billing_account=billing_account, @@ -2266,7 +2889,7 @@ def test_common_billing_account_path(): def test_parse_common_billing_account_path(): expected = { - "billing_account": "octopus", + "billing_account": "abalone", } path = AgentsClient.common_billing_account_path(**expected) @@ -2276,7 +2899,7 @@ def test_parse_common_billing_account_path(): def test_common_folder_path(): - folder = "oyster" + folder = "squid" expected = "folders/{folder}".format(folder=folder,) actual = AgentsClient.common_folder_path(folder) @@ -2285,7 +2908,7 @@ def test_common_folder_path(): def test_parse_common_folder_path(): expected = { - "folder": "nudibranch", + "folder": "clam", } path = AgentsClient.common_folder_path(**expected) @@ -2295,7 +2918,7 @@ def test_parse_common_folder_path(): def test_common_organization_path(): - organization = "cuttlefish" + organization = "whelk" expected = "organizations/{organization}".format(organization=organization,) actual = AgentsClient.common_organization_path(organization) @@ -2304,7 +2927,7 @@ def test_common_organization_path(): def test_parse_common_organization_path(): expected = { - "organization": "mussel", + "organization": "octopus", } path = AgentsClient.common_organization_path(**expected) @@ -2314,7 +2937,7 @@ def test_parse_common_organization_path(): def test_common_project_path(): - project = "winkle" + project = "oyster" expected = "projects/{project}".format(project=project,) actual = AgentsClient.common_project_path(project) @@ -2323,7 +2946,7 @@ def test_common_project_path(): def test_parse_common_project_path(): expected = { - "project": "nautilus", + "project": "nudibranch", } path = AgentsClient.common_project_path(**expected) @@ -2333,8 +2956,8 @@ def test_parse_common_project_path(): def test_common_location_path(): - project = "scallop" - location = "abalone" + project = "cuttlefish" + location = "mussel" expected = "projects/{project}/locations/{location}".format( project=project, location=location, @@ -2345,8 +2968,8 @@ def test_common_location_path(): def test_parse_common_location_path(): expected = { - "project": "squid", - "location": "clam", + "project": "winkle", + "location": "nautilus", } path = AgentsClient.common_location_path(**expected) diff --git a/tests/unit/gapic/dialogflowcx_v3/test_entity_types.py b/tests/unit/gapic/dialogflowcx_v3/test_entity_types.py index 22ecbedb..81805ac9 100644 --- a/tests/unit/gapic/dialogflowcx_v3/test_entity_types.py +++ b/tests/unit/gapic/dialogflowcx_v3/test_entity_types.py @@ -83,7 +83,22 @@ def test__get_default_mtls_endpoint(): assert EntityTypesClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi -@pytest.mark.parametrize("client_class", [EntityTypesClient, EntityTypesAsyncClient]) +@pytest.mark.parametrize("client_class", [EntityTypesClient, EntityTypesAsyncClient,]) +def test_entity_types_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 == "dialogflow.googleapis.com:443" + + +@pytest.mark.parametrize("client_class", [EntityTypesClient, EntityTypesAsyncClient,]) def test_entity_types_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() with mock.patch.object( @@ -92,16 +107,21 @@ def test_entity_types_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 == "dialogflow.googleapis.com:443" def test_entity_types_client_get_transport_class(): transport = EntityTypesClient.get_transport_class() - assert transport == transports.EntityTypesGrpcTransport + available_transports = [ + transports.EntityTypesGrpcTransport, + ] + assert transport in available_transports transport = EntityTypesClient.get_transport_class("grpc") assert transport == transports.EntityTypesGrpcTransport @@ -150,7 +170,7 @@ def test_entity_types_client_client_options( credentials_file=None, host="squid.clam.whelk", scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -166,7 +186,7 @@ def test_entity_types_client_client_options( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -182,7 +202,7 @@ def test_entity_types_client_client_options( credentials_file=None, host=client.DEFAULT_MTLS_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -210,7 +230,7 @@ def test_entity_types_client_client_options( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id="octopus", client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -259,29 +279,25 @@ def test_entity_types_client_mtls_env_auto( client_cert_source=client_cert_source_callback ) with mock.patch.object(transport_class, "__init__") as patched: - ssl_channel_creds = mock.Mock() - with mock.patch( - "grpc.ssl_channel_credentials", return_value=ssl_channel_creds - ): - patched.return_value = None - client = client_class(client_options=options) + patched.return_value = None + client = client_class(client_options=options) - if use_client_cert_env == "false": - expected_ssl_channel_creds = None - expected_host = client.DEFAULT_ENDPOINT - else: - expected_ssl_channel_creds = ssl_channel_creds - expected_host = client.DEFAULT_MTLS_ENDPOINT + if use_client_cert_env == "false": + expected_client_cert_source = None + expected_host = client.DEFAULT_ENDPOINT + else: + expected_client_cert_source = client_cert_source_callback + expected_host = client.DEFAULT_MTLS_ENDPOINT - patched.assert_called_once_with( - credentials=None, - credentials_file=None, - host=expected_host, - scopes=None, - ssl_channel_credentials=expected_ssl_channel_creds, - quota_project_id=None, - client_info=transports.base.DEFAULT_CLIENT_INFO, - ) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=expected_host, + scopes=None, + client_cert_source_for_mtls=expected_client_cert_source, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) # Check the case ADC client cert is provided. Whether client cert is used depends on # GOOGLE_API_USE_CLIENT_CERTIFICATE value. @@ -290,66 +306,53 @@ def test_entity_types_client_mtls_env_auto( ): with mock.patch.object(transport_class, "__init__") as patched: with mock.patch( - "google.auth.transport.grpc.SslCredentials.__init__", return_value=None + "google.auth.transport.mtls.has_default_client_cert_source", + return_value=True, ): with mock.patch( - "google.auth.transport.grpc.SslCredentials.is_mtls", - new_callable=mock.PropertyMock, - ) as is_mtls_mock: - with mock.patch( - "google.auth.transport.grpc.SslCredentials.ssl_credentials", - new_callable=mock.PropertyMock, - ) as ssl_credentials_mock: - if use_client_cert_env == "false": - is_mtls_mock.return_value = False - ssl_credentials_mock.return_value = None - expected_host = client.DEFAULT_ENDPOINT - expected_ssl_channel_creds = None - else: - is_mtls_mock.return_value = True - ssl_credentials_mock.return_value = mock.Mock() - expected_host = client.DEFAULT_MTLS_ENDPOINT - expected_ssl_channel_creds = ( - ssl_credentials_mock.return_value - ) - - patched.return_value = None - client = client_class() - patched.assert_called_once_with( - credentials=None, - credentials_file=None, - host=expected_host, - scopes=None, - ssl_channel_credentials=expected_ssl_channel_creds, - quota_project_id=None, - client_info=transports.base.DEFAULT_CLIENT_INFO, - ) + "google.auth.transport.mtls.default_client_cert_source", + return_value=client_cert_source_callback, + ): + if use_client_cert_env == "false": + expected_host = client.DEFAULT_ENDPOINT + expected_client_cert_source = None + else: + expected_host = client.DEFAULT_MTLS_ENDPOINT + expected_client_cert_source = client_cert_source_callback - # Check the case client_cert_source and ADC client cert are not provided. - with mock.patch.dict( - os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env} - ): - with mock.patch.object(transport_class, "__init__") as patched: - with mock.patch( - "google.auth.transport.grpc.SslCredentials.__init__", return_value=None - ): - with mock.patch( - "google.auth.transport.grpc.SslCredentials.is_mtls", - new_callable=mock.PropertyMock, - ) as is_mtls_mock: - is_mtls_mock.return_value = False patched.return_value = None client = client_class() patched.assert_called_once_with( credentials=None, credentials_file=None, - host=client.DEFAULT_ENDPOINT, + host=expected_host, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=expected_client_cert_source, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) + # Check the case client_cert_source and ADC client cert are not provided. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env} + ): + with mock.patch.object(transport_class, "__init__") as patched: + with mock.patch( + "google.auth.transport.mtls.has_default_client_cert_source", + return_value=False, + ): + patched.return_value = None + client = client_class() + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) + @pytest.mark.parametrize( "client_class,transport_class,transport_name", @@ -375,7 +378,7 @@ def test_entity_types_client_client_options_scopes( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=["1", "2"], - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -405,7 +408,7 @@ def test_entity_types_client_client_options_credentials_file( credentials_file="credentials.json", host=client.DEFAULT_ENDPOINT, scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -422,7 +425,7 @@ def test_entity_types_client_client_options_from_dict(): credentials_file=None, host="squid.clam.whelk", scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -467,6 +470,24 @@ def test_list_entity_types_from_dict(): test_list_entity_types(request_type=dict) +def test_list_entity_types_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 = EntityTypesClient( + 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_entity_types), "__call__" + ) as call: + client.list_entity_types() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == entity_type.ListEntityTypesRequest() + + @pytest.mark.asyncio async def test_list_entity_types_async( transport: str = "grpc_asyncio", request_type=entity_type.ListEntityTypesRequest @@ -809,6 +830,7 @@ def test_get_entity_type( kind=entity_type.EntityType.Kind.KIND_MAP, auto_expansion_mode=entity_type.EntityType.AutoExpansionMode.AUTO_EXPANSION_MODE_DEFAULT, enable_fuzzy_extraction=True, + redact=True, ) response = client.get_entity_type(request) @@ -836,11 +858,29 @@ def test_get_entity_type( assert response.enable_fuzzy_extraction is True + assert response.redact is True + def test_get_entity_type_from_dict(): test_get_entity_type(request_type=dict) +def test_get_entity_type_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 = EntityTypesClient( + 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_entity_type), "__call__") as call: + client.get_entity_type() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == entity_type.GetEntityTypeRequest() + + @pytest.mark.asyncio async def test_get_entity_type_async( transport: str = "grpc_asyncio", request_type=entity_type.GetEntityTypeRequest @@ -863,6 +903,7 @@ async def test_get_entity_type_async( kind=entity_type.EntityType.Kind.KIND_MAP, auto_expansion_mode=entity_type.EntityType.AutoExpansionMode.AUTO_EXPANSION_MODE_DEFAULT, enable_fuzzy_extraction=True, + redact=True, ) ) @@ -890,6 +931,8 @@ async def test_get_entity_type_async( assert response.enable_fuzzy_extraction is True + assert response.redact is True + @pytest.mark.asyncio async def test_get_entity_type_async_from_dict(): @@ -1036,6 +1079,7 @@ def test_create_entity_type( kind=gcdc_entity_type.EntityType.Kind.KIND_MAP, auto_expansion_mode=gcdc_entity_type.EntityType.AutoExpansionMode.AUTO_EXPANSION_MODE_DEFAULT, enable_fuzzy_extraction=True, + redact=True, ) response = client.create_entity_type(request) @@ -1063,11 +1107,31 @@ def test_create_entity_type( assert response.enable_fuzzy_extraction is True + assert response.redact is True + def test_create_entity_type_from_dict(): test_create_entity_type(request_type=dict) +def test_create_entity_type_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 = EntityTypesClient( + 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_entity_type), "__call__" + ) as call: + client.create_entity_type() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_entity_type.CreateEntityTypeRequest() + + @pytest.mark.asyncio async def test_create_entity_type_async( transport: str = "grpc_asyncio", @@ -1093,6 +1157,7 @@ async def test_create_entity_type_async( kind=gcdc_entity_type.EntityType.Kind.KIND_MAP, auto_expansion_mode=gcdc_entity_type.EntityType.AutoExpansionMode.AUTO_EXPANSION_MODE_DEFAULT, enable_fuzzy_extraction=True, + redact=True, ) ) @@ -1120,6 +1185,8 @@ async def test_create_entity_type_async( assert response.enable_fuzzy_extraction is True + assert response.redact is True + @pytest.mark.asyncio async def test_create_entity_type_async_from_dict(): @@ -1288,6 +1355,7 @@ def test_update_entity_type( kind=gcdc_entity_type.EntityType.Kind.KIND_MAP, auto_expansion_mode=gcdc_entity_type.EntityType.AutoExpansionMode.AUTO_EXPANSION_MODE_DEFAULT, enable_fuzzy_extraction=True, + redact=True, ) response = client.update_entity_type(request) @@ -1315,11 +1383,31 @@ def test_update_entity_type( assert response.enable_fuzzy_extraction is True + assert response.redact is True + def test_update_entity_type_from_dict(): test_update_entity_type(request_type=dict) +def test_update_entity_type_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 = EntityTypesClient( + 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_entity_type), "__call__" + ) as call: + client.update_entity_type() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_entity_type.UpdateEntityTypeRequest() + + @pytest.mark.asyncio async def test_update_entity_type_async( transport: str = "grpc_asyncio", @@ -1345,6 +1433,7 @@ async def test_update_entity_type_async( kind=gcdc_entity_type.EntityType.Kind.KIND_MAP, auto_expansion_mode=gcdc_entity_type.EntityType.AutoExpansionMode.AUTO_EXPANSION_MODE_DEFAULT, enable_fuzzy_extraction=True, + redact=True, ) ) @@ -1372,6 +1461,8 @@ async def test_update_entity_type_async( assert response.enable_fuzzy_extraction is True + assert response.redact is True + @pytest.mark.asyncio async def test_update_entity_type_async_from_dict(): @@ -1556,6 +1647,24 @@ def test_delete_entity_type_from_dict(): test_delete_entity_type(request_type=dict) +def test_delete_entity_type_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 = EntityTypesClient( + 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_entity_type), "__call__" + ) as call: + client.delete_entity_type() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == entity_type.DeleteEntityTypeRequest() + + @pytest.mark.asyncio async def test_delete_entity_type_async( transport: str = "grpc_asyncio", request_type=entity_type.DeleteEntityTypeRequest @@ -1770,7 +1879,7 @@ def test_transport_get_channel(): @pytest.mark.parametrize( "transport_class", - [transports.EntityTypesGrpcTransport, transports.EntityTypesGrpcAsyncIOTransport], + [transports.EntityTypesGrpcTransport, transports.EntityTypesGrpcAsyncIOTransport,], ) def test_transport_adc(transport_class): # Test default credentials are used if not provided. @@ -1883,6 +1992,51 @@ def test_entity_types_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [transports.EntityTypesGrpcTransport, transports.EntityTypesGrpcAsyncIOTransport], +) +def test_entity_types_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/dialogflow", + ), + 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_entity_types_host_no_port(): client = EntityTypesClient( credentials=credentials.AnonymousCredentials(), @@ -1904,7 +2058,7 @@ def test_entity_types_host_with_port(): def test_entity_types_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.EntityTypesGrpcTransport( @@ -1916,7 +2070,7 @@ def test_entity_types_grpc_transport_channel(): def test_entity_types_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.EntityTypesGrpcAsyncIOTransport( @@ -1927,6 +2081,8 @@ def test_entity_types_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.EntityTypesGrpcTransport, transports.EntityTypesGrpcAsyncIOTransport], @@ -1936,7 +2092,7 @@ def test_entity_types_transport_channel_mtls_with_client_cert_source(transport_c "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 @@ -1977,6 +2133,8 @@ def test_entity_types_transport_channel_mtls_with_client_cert_source(transport_c 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.EntityTypesGrpcTransport, transports.EntityTypesGrpcAsyncIOTransport], @@ -1989,7 +2147,7 @@ def test_entity_types_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/dialogflowcx_v3/test_environments.py b/tests/unit/gapic/dialogflowcx_v3/test_environments.py index 4f05cd0d..b8e4a510 100644 --- a/tests/unit/gapic/dialogflowcx_v3/test_environments.py +++ b/tests/unit/gapic/dialogflowcx_v3/test_environments.py @@ -89,7 +89,22 @@ def test__get_default_mtls_endpoint(): assert EnvironmentsClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi -@pytest.mark.parametrize("client_class", [EnvironmentsClient, EnvironmentsAsyncClient]) +@pytest.mark.parametrize("client_class", [EnvironmentsClient, EnvironmentsAsyncClient,]) +def test_environments_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 == "dialogflow.googleapis.com:443" + + +@pytest.mark.parametrize("client_class", [EnvironmentsClient, EnvironmentsAsyncClient,]) def test_environments_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() with mock.patch.object( @@ -98,16 +113,21 @@ def test_environments_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 == "dialogflow.googleapis.com:443" def test_environments_client_get_transport_class(): transport = EnvironmentsClient.get_transport_class() - assert transport == transports.EnvironmentsGrpcTransport + available_transports = [ + transports.EnvironmentsGrpcTransport, + ] + assert transport in available_transports transport = EnvironmentsClient.get_transport_class("grpc") assert transport == transports.EnvironmentsGrpcTransport @@ -156,7 +176,7 @@ def test_environments_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, ) @@ -172,7 +192,7 @@ def test_environments_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, ) @@ -188,7 +208,7 @@ def test_environments_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, ) @@ -216,7 +236,7 @@ def test_environments_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, ) @@ -265,29 +285,25 @@ def test_environments_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. @@ -296,66 +312,53 @@ def test_environments_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", @@ -381,7 +384,7 @@ def test_environments_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, ) @@ -411,7 +414,7 @@ def test_environments_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, ) @@ -428,7 +431,7 @@ def test_environments_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_list_environments_from_dict(): test_list_environments(request_type=dict) +def test_list_environments_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 = EnvironmentsClient( + 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_environments), "__call__" + ) as call: + client.list_environments() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == environment.ListEnvironmentsRequest() + + @pytest.mark.asyncio async def test_list_environments_async( transport: str = "grpc_asyncio", request_type=environment.ListEnvironmentsRequest @@ -838,6 +859,22 @@ def test_get_environment_from_dict(): test_get_environment(request_type=dict) +def test_get_environment_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 = EnvironmentsClient( + 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_environment), "__call__") as call: + client.get_environment() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == environment.GetEnvironmentRequest() + + @pytest.mark.asyncio async def test_get_environment_async( transport: str = "grpc_asyncio", request_type=environment.GetEnvironmentRequest @@ -1036,6 +1073,24 @@ def test_create_environment_from_dict(): test_create_environment(request_type=dict) +def test_create_environment_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 = EnvironmentsClient( + 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_environment), "__call__" + ) as call: + client.create_environment() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_environment.CreateEnvironmentRequest() + + @pytest.mark.asyncio async def test_create_environment_async( transport: str = "grpc_asyncio", @@ -1249,6 +1304,24 @@ def test_update_environment_from_dict(): test_update_environment(request_type=dict) +def test_update_environment_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 = EnvironmentsClient( + 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_environment), "__call__" + ) as call: + client.update_environment() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_environment.UpdateEnvironmentRequest() + + @pytest.mark.asyncio async def test_update_environment_async( transport: str = "grpc_asyncio", @@ -1466,6 +1539,24 @@ def test_delete_environment_from_dict(): test_delete_environment(request_type=dict) +def test_delete_environment_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 = EnvironmentsClient( + 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_environment), "__call__" + ) as call: + client.delete_environment() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == environment.DeleteEnvironmentRequest() + + @pytest.mark.asyncio async def test_delete_environment_async( transport: str = "grpc_asyncio", request_type=environment.DeleteEnvironmentRequest @@ -1663,6 +1754,24 @@ def test_lookup_environment_history_from_dict(): test_lookup_environment_history(request_type=dict) +def test_lookup_environment_history_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = EnvironmentsClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.lookup_environment_history), "__call__" + ) as call: + client.lookup_environment_history() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == environment.LookupEnvironmentHistoryRequest() + + @pytest.mark.asyncio async def test_lookup_environment_history_async( transport: str = "grpc_asyncio", @@ -2042,7 +2151,10 @@ def test_transport_get_channel(): @pytest.mark.parametrize( "transport_class", - [transports.EnvironmentsGrpcTransport, transports.EnvironmentsGrpcAsyncIOTransport], + [ + transports.EnvironmentsGrpcTransport, + transports.EnvironmentsGrpcAsyncIOTransport, + ], ) def test_transport_adc(transport_class): # Test default credentials are used if not provided. @@ -2161,6 +2273,51 @@ def test_environments_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [transports.EnvironmentsGrpcTransport, transports.EnvironmentsGrpcAsyncIOTransport], +) +def test_environments_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/dialogflow", + ), + 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_environments_host_no_port(): client = EnvironmentsClient( credentials=credentials.AnonymousCredentials(), @@ -2182,7 +2339,7 @@ def test_environments_host_with_port(): def test_environments_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.EnvironmentsGrpcTransport( @@ -2194,7 +2351,7 @@ def test_environments_grpc_transport_channel(): def test_environments_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.EnvironmentsGrpcAsyncIOTransport( @@ -2205,6 +2362,8 @@ def test_environments_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.EnvironmentsGrpcTransport, transports.EnvironmentsGrpcAsyncIOTransport], @@ -2214,7 +2373,7 @@ def test_environments_transport_channel_mtls_with_client_cert_source(transport_c "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 @@ -2255,6 +2414,8 @@ def test_environments_transport_channel_mtls_with_client_cert_source(transport_c 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.EnvironmentsGrpcTransport, transports.EnvironmentsGrpcAsyncIOTransport], @@ -2267,7 +2428,7 @@ def test_environments_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/dialogflowcx_v3/test_experiments.py b/tests/unit/gapic/dialogflowcx_v3/test_experiments.py index 1818b5af..5f2f59aa 100644 --- a/tests/unit/gapic/dialogflowcx_v3/test_experiments.py +++ b/tests/unit/gapic/dialogflowcx_v3/test_experiments.py @@ -85,7 +85,22 @@ def test__get_default_mtls_endpoint(): assert ExperimentsClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi -@pytest.mark.parametrize("client_class", [ExperimentsClient, ExperimentsAsyncClient]) +@pytest.mark.parametrize("client_class", [ExperimentsClient, ExperimentsAsyncClient,]) +def test_experiments_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 == "dialogflow.googleapis.com:443" + + +@pytest.mark.parametrize("client_class", [ExperimentsClient, ExperimentsAsyncClient,]) def test_experiments_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() with mock.patch.object( @@ -94,16 +109,21 @@ def test_experiments_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 == "dialogflow.googleapis.com:443" def test_experiments_client_get_transport_class(): transport = ExperimentsClient.get_transport_class() - assert transport == transports.ExperimentsGrpcTransport + available_transports = [ + transports.ExperimentsGrpcTransport, + ] + assert transport in available_transports transport = ExperimentsClient.get_transport_class("grpc") assert transport == transports.ExperimentsGrpcTransport @@ -152,7 +172,7 @@ def test_experiments_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, ) @@ -168,7 +188,7 @@ def test_experiments_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, ) @@ -184,7 +204,7 @@ def test_experiments_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, ) @@ -212,7 +232,7 @@ def test_experiments_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, ) @@ -261,29 +281,25 @@ def test_experiments_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. @@ -292,66 +308,53 @@ def test_experiments_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", @@ -377,7 +380,7 @@ def test_experiments_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, ) @@ -407,7 +410,7 @@ def test_experiments_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, ) @@ -424,7 +427,7 @@ def test_experiments_client_client_options_from_dict(): credentials_file=None, host="squid.clam.whelk", scopes=None, - ssl_channel_credentials=None, + client_cert_source_for_mtls=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -467,6 +470,22 @@ def test_list_experiments_from_dict(): test_list_experiments(request_type=dict) +def test_list_experiments_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 = ExperimentsClient( + 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_experiments), "__call__") as call: + client.list_experiments() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == experiment.ListExperimentsRequest() + + @pytest.mark.asyncio async def test_list_experiments_async( transport: str = "grpc_asyncio", request_type=experiment.ListExperimentsRequest @@ -807,6 +826,22 @@ def test_get_experiment_from_dict(): test_get_experiment(request_type=dict) +def test_get_experiment_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 = ExperimentsClient( + 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_experiment), "__call__") as call: + client.get_experiment() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == experiment.GetExperimentRequest() + + @pytest.mark.asyncio async def test_get_experiment_async( transport: str = "grpc_asyncio", request_type=experiment.GetExperimentRequest @@ -1022,6 +1057,24 @@ def test_create_experiment_from_dict(): test_create_experiment(request_type=dict) +def test_create_experiment_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 = ExperimentsClient( + 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_experiment), "__call__" + ) as call: + client.create_experiment() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_experiment.CreateExperimentRequest() + + @pytest.mark.asyncio async def test_create_experiment_async( transport: str = "grpc_asyncio", @@ -1262,6 +1315,24 @@ def test_update_experiment_from_dict(): test_update_experiment(request_type=dict) +def test_update_experiment_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 = ExperimentsClient( + 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_experiment), "__call__" + ) as call: + client.update_experiment() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_experiment.UpdateExperimentRequest() + + @pytest.mark.asyncio async def test_update_experiment_async( transport: str = "grpc_asyncio", @@ -1492,6 +1563,24 @@ def test_delete_experiment_from_dict(): test_delete_experiment(request_type=dict) +def test_delete_experiment_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 = ExperimentsClient( + 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_experiment), "__call__" + ) as call: + client.delete_experiment() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == experiment.DeleteExperimentRequest() + + @pytest.mark.asyncio async def test_delete_experiment_async( transport: str = "grpc_asyncio", request_type=experiment.DeleteExperimentRequest @@ -1696,6 +1785,22 @@ def test_start_experiment_from_dict(): test_start_experiment(request_type=dict) +def test_start_experiment_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 = ExperimentsClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.start_experiment), "__call__") as call: + client.start_experiment() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == experiment.StartExperimentRequest() + + @pytest.mark.asyncio async def test_start_experiment_async( transport: str = "grpc_asyncio", request_type=experiment.StartExperimentRequest @@ -1909,6 +2014,22 @@ def test_stop_experiment_from_dict(): test_stop_experiment(request_type=dict) +def test_stop_experiment_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 = ExperimentsClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.stop_experiment), "__call__") as call: + client.stop_experiment() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == experiment.StopExperimentRequest() + + @pytest.mark.asyncio async def test_stop_experiment_async( transport: str = "grpc_asyncio", request_type=experiment.StopExperimentRequest @@ -2132,7 +2253,7 @@ def test_transport_get_channel(): @pytest.mark.parametrize( "transport_class", - [transports.ExperimentsGrpcTransport, transports.ExperimentsGrpcAsyncIOTransport], + [transports.ExperimentsGrpcTransport, transports.ExperimentsGrpcAsyncIOTransport,], ) def test_transport_adc(transport_class): # Test default credentials are used if not provided. @@ -2247,6 +2368,51 @@ def test_experiments_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [transports.ExperimentsGrpcTransport, transports.ExperimentsGrpcAsyncIOTransport], +) +def test_experiments_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/dialogflow", + ), + 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_experiments_host_no_port(): client = ExperimentsClient( credentials=credentials.AnonymousCredentials(), @@ -2268,7 +2434,7 @@ def test_experiments_host_with_port(): def test_experiments_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.ExperimentsGrpcTransport( @@ -2280,7 +2446,7 @@ def test_experiments_grpc_transport_channel(): def test_experiments_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.ExperimentsGrpcAsyncIOTransport( @@ -2291,6 +2457,8 @@ def test_experiments_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.ExperimentsGrpcTransport, transports.ExperimentsGrpcAsyncIOTransport], @@ -2300,7 +2468,7 @@ def test_experiments_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 @@ -2341,6 +2509,8 @@ def test_experiments_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.ExperimentsGrpcTransport, transports.ExperimentsGrpcAsyncIOTransport], @@ -2353,7 +2523,7 @@ def test_experiments_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/dialogflowcx_v3/test_flows.py b/tests/unit/gapic/dialogflowcx_v3/test_flows.py index e98c1fe9..685cfaff 100644 --- a/tests/unit/gapic/dialogflowcx_v3/test_flows.py +++ b/tests/unit/gapic/dialogflowcx_v3/test_flows.py @@ -44,10 +44,12 @@ from google.cloud.dialogflowcx_v3.types import fulfillment from google.cloud.dialogflowcx_v3.types import page from google.cloud.dialogflowcx_v3.types import response_message +from google.cloud.dialogflowcx_v3.types import validation_message from google.longrunning import operations_pb2 from google.oauth2 import service_account from google.protobuf import field_mask_pb2 as field_mask # type: ignore from google.protobuf import struct_pb2 as struct # type: ignore +from google.protobuf import timestamp_pb2 as timestamp # type: ignore def client_cert_source_callback(): @@ -88,7 +90,22 @@ def test__get_default_mtls_endpoint(): assert FlowsClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi -@pytest.mark.parametrize("client_class", [FlowsClient, FlowsAsyncClient]) +@pytest.mark.parametrize("client_class", [FlowsClient, FlowsAsyncClient,]) +def test_flows_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 == "dialogflow.googleapis.com:443" + + +@pytest.mark.parametrize("client_class", [FlowsClient, FlowsAsyncClient,]) def test_flows_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() with mock.patch.object( @@ -97,16 +114,21 @@ def test_flows_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 == "dialogflow.googleapis.com:443" def test_flows_client_get_transport_class(): transport = FlowsClient.get_transport_class() - assert transport == transports.FlowsGrpcTransport + available_transports = [ + transports.FlowsGrpcTransport, + ] + assert transport in available_transports transport = FlowsClient.get_transport_class("grpc") assert transport == transports.FlowsGrpcTransport @@ -147,7 +169,7 @@ def test_flows_client_client_options(client_class, transport_class, transport_na 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, ) @@ -163,7 +185,7 @@ def test_flows_client_client_options(client_class, transport_class, transport_na 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, ) @@ -179,7 +201,7 @@ def test_flows_client_client_options(client_class, transport_class, transport_na 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, ) @@ -207,7 +229,7 @@ def test_flows_client_client_options(client_class, transport_class, transport_na 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, ) @@ -254,29 +276,25 @@ def test_flows_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. @@ -285,66 +303,53 @@ def test_flows_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", @@ -366,7 +371,7 @@ def test_flows_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, ) @@ -392,7 +397,7 @@ def test_flows_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, ) @@ -409,7 +414,7 @@ def test_flows_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, ) @@ -456,6 +461,22 @@ def test_create_flow_from_dict(): test_create_flow(request_type=dict) +def test_create_flow_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 = FlowsClient( + 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_flow), "__call__") as call: + client.create_flow() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_flow.CreateFlowRequest() + + @pytest.mark.asyncio async def test_create_flow_async( transport: str = "grpc_asyncio", request_type=gcdc_flow.CreateFlowRequest @@ -658,6 +679,22 @@ def test_delete_flow_from_dict(): test_delete_flow(request_type=dict) +def test_delete_flow_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 = FlowsClient( + 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_flow), "__call__") as call: + client.delete_flow() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == flow.DeleteFlowRequest() + + @pytest.mark.asyncio async def test_delete_flow_async( transport: str = "grpc_asyncio", request_type=flow.DeleteFlowRequest @@ -841,6 +878,22 @@ def test_list_flows_from_dict(): test_list_flows(request_type=dict) +def test_list_flows_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 = FlowsClient( + 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_flows), "__call__") as call: + client.list_flows() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == flow.ListFlowsRequest() + + @pytest.mark.asyncio async def test_list_flows_async( transport: str = "grpc_asyncio", request_type=flow.ListFlowsRequest @@ -1140,6 +1193,22 @@ def test_get_flow_from_dict(): test_get_flow(request_type=dict) +def test_get_flow_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 = FlowsClient( + 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_flow), "__call__") as call: + client.get_flow() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == flow.GetFlowRequest() + + @pytest.mark.asyncio async def test_get_flow_async( transport: str = "grpc_asyncio", request_type=flow.GetFlowRequest @@ -1341,6 +1410,22 @@ def test_update_flow_from_dict(): test_update_flow(request_type=dict) +def test_update_flow_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 = FlowsClient( + 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_flow), "__call__") as call: + client.update_flow() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_flow.UpdateFlowRequest() + + @pytest.mark.asyncio async def test_update_flow_async( transport: str = "grpc_asyncio", request_type=gcdc_flow.UpdateFlowRequest @@ -1545,6 +1630,22 @@ def test_train_flow_from_dict(): test_train_flow(request_type=dict) +def test_train_flow_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 = FlowsClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.train_flow), "__call__") as call: + client.train_flow() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == flow.TrainFlowRequest() + + @pytest.mark.asyncio async def test_train_flow_async( transport: str = "grpc_asyncio", request_type=flow.TrainFlowRequest @@ -1699,6 +1800,365 @@ async def test_train_flow_flattened_error_async(): ) +def test_validate_flow(transport: str = "grpc", request_type=flow.ValidateFlowRequest): + client = FlowsClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.validate_flow), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = flow.FlowValidationResult(name="name_value",) + + response = client.validate_flow(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0] == flow.ValidateFlowRequest() + + # Establish that the response is the type that we expect. + + assert isinstance(response, flow.FlowValidationResult) + + assert response.name == "name_value" + + +def test_validate_flow_from_dict(): + test_validate_flow(request_type=dict) + + +def test_validate_flow_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 = FlowsClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.validate_flow), "__call__") as call: + client.validate_flow() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == flow.ValidateFlowRequest() + + +@pytest.mark.asyncio +async def test_validate_flow_async( + transport: str = "grpc_asyncio", request_type=flow.ValidateFlowRequest +): + client = FlowsAsyncClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.validate_flow), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + flow.FlowValidationResult(name="name_value",) + ) + + response = await client.validate_flow(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0] == flow.ValidateFlowRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, flow.FlowValidationResult) + + assert response.name == "name_value" + + +@pytest.mark.asyncio +async def test_validate_flow_async_from_dict(): + await test_validate_flow_async(request_type=dict) + + +def test_validate_flow_field_headers(): + client = FlowsClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = flow.ValidateFlowRequest() + request.name = "name/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.validate_flow), "__call__") as call: + call.return_value = flow.FlowValidationResult() + + client.validate_flow(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "name=name/value",) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_validate_flow_field_headers_async(): + client = FlowsAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = flow.ValidateFlowRequest() + request.name = "name/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.validate_flow), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + flow.FlowValidationResult() + ) + + await client.validate_flow(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "name=name/value",) in kw["metadata"] + + +def test_get_flow_validation_result( + transport: str = "grpc", request_type=flow.GetFlowValidationResultRequest +): + client = FlowsClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_flow_validation_result), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = flow.FlowValidationResult(name="name_value",) + + response = client.get_flow_validation_result(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0] == flow.GetFlowValidationResultRequest() + + # Establish that the response is the type that we expect. + + assert isinstance(response, flow.FlowValidationResult) + + assert response.name == "name_value" + + +def test_get_flow_validation_result_from_dict(): + test_get_flow_validation_result(request_type=dict) + + +def test_get_flow_validation_result_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 = FlowsClient( + 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_flow_validation_result), "__call__" + ) as call: + client.get_flow_validation_result() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == flow.GetFlowValidationResultRequest() + + +@pytest.mark.asyncio +async def test_get_flow_validation_result_async( + transport: str = "grpc_asyncio", request_type=flow.GetFlowValidationResultRequest +): + client = FlowsAsyncClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_flow_validation_result), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + flow.FlowValidationResult(name="name_value",) + ) + + response = await client.get_flow_validation_result(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0] == flow.GetFlowValidationResultRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, flow.FlowValidationResult) + + assert response.name == "name_value" + + +@pytest.mark.asyncio +async def test_get_flow_validation_result_async_from_dict(): + await test_get_flow_validation_result_async(request_type=dict) + + +def test_get_flow_validation_result_field_headers(): + client = FlowsClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = flow.GetFlowValidationResultRequest() + request.name = "name/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_flow_validation_result), "__call__" + ) as call: + call.return_value = flow.FlowValidationResult() + + client.get_flow_validation_result(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "name=name/value",) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_get_flow_validation_result_field_headers_async(): + client = FlowsAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = flow.GetFlowValidationResultRequest() + request.name = "name/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_flow_validation_result), "__call__" + ) as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + flow.FlowValidationResult() + ) + + await client.get_flow_validation_result(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "name=name/value",) in kw["metadata"] + + +def test_get_flow_validation_result_flattened(): + client = FlowsClient(credentials=credentials.AnonymousCredentials(),) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_flow_validation_result), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = flow.FlowValidationResult() + + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.get_flow_validation_result(name="name_value",) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0].name == "name_value" + + +def test_get_flow_validation_result_flattened_error(): + client = FlowsClient(credentials=credentials.AnonymousCredentials(),) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.get_flow_validation_result( + flow.GetFlowValidationResultRequest(), name="name_value", + ) + + +@pytest.mark.asyncio +async def test_get_flow_validation_result_flattened_async(): + client = FlowsAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_flow_validation_result), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = flow.FlowValidationResult() + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + flow.FlowValidationResult() + ) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.get_flow_validation_result(name="name_value",) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0].name == "name_value" + + +@pytest.mark.asyncio +async def test_get_flow_validation_result_flattened_error_async(): + client = FlowsAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.get_flow_validation_result( + flow.GetFlowValidationResultRequest(), name="name_value", + ) + + def test_credentials_transport_error(): # It is an error to provide credentials and a transport instance. transport = transports.FlowsGrpcTransport( @@ -1755,7 +2215,7 @@ def test_transport_get_channel(): @pytest.mark.parametrize( "transport_class", - [transports.FlowsGrpcTransport, transports.FlowsGrpcAsyncIOTransport], + [transports.FlowsGrpcTransport, transports.FlowsGrpcAsyncIOTransport,], ) def test_transport_adc(transport_class): # Test default credentials are used if not provided. @@ -1799,6 +2259,8 @@ def test_flows_base_transport(): "get_flow", "update_flow", "train_flow", + "validate_flow", + "get_flow_validation_result", ) for method in methods: with pytest.raises(NotImplementedError): @@ -1874,6 +2336,51 @@ def test_flows_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [transports.FlowsGrpcTransport, transports.FlowsGrpcAsyncIOTransport], +) +def test_flows_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/dialogflow", + ), + 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_flows_host_no_port(): client = FlowsClient( credentials=credentials.AnonymousCredentials(), @@ -1895,7 +2402,7 @@ def test_flows_host_with_port(): def test_flows_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.FlowsGrpcTransport(host="squid.clam.whelk", channel=channel,) @@ -1905,7 +2412,7 @@ def test_flows_grpc_transport_channel(): def test_flows_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.FlowsGrpcAsyncIOTransport( @@ -1916,6 +2423,8 @@ def test_flows_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.FlowsGrpcTransport, transports.FlowsGrpcAsyncIOTransport], @@ -1925,7 +2434,7 @@ def test_flows_transport_channel_mtls_with_client_cert_source(transport_class): "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 @@ -1966,6 +2475,8 @@ def test_flows_transport_channel_mtls_with_client_cert_source(transport_class): 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.FlowsGrpcTransport, transports.FlowsGrpcAsyncIOTransport], @@ -1978,7 +2489,7 @@ def test_flows_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 @@ -2063,11 +2574,38 @@ def test_parse_flow_path(): assert expected == actual -def test_intent_path(): +def test_flow_validation_result_path(): project = "winkle" location = "nautilus" agent = "scallop" - intent = "abalone" + flow = "abalone" + + expected = "projects/{project}/locations/{location}/agents/{agent}/flows/{flow}/validationResult".format( + project=project, location=location, agent=agent, flow=flow, + ) + actual = FlowsClient.flow_validation_result_path(project, location, agent, flow) + assert expected == actual + + +def test_parse_flow_validation_result_path(): + expected = { + "project": "squid", + "location": "clam", + "agent": "whelk", + "flow": "octopus", + } + path = FlowsClient.flow_validation_result_path(**expected) + + # Check that the path construction is reversible. + actual = FlowsClient.parse_flow_validation_result_path(path) + assert expected == actual + + +def test_intent_path(): + project = "oyster" + location = "nudibranch" + agent = "cuttlefish" + intent = "mussel" expected = "projects/{project}/locations/{location}/agents/{agent}/intents/{intent}".format( project=project, location=location, agent=agent, intent=intent, @@ -2078,10 +2616,10 @@ def test_intent_path(): def test_parse_intent_path(): expected = { - "project": "squid", - "location": "clam", - "agent": "whelk", - "intent": "octopus", + "project": "winkle", + "location": "nautilus", + "agent": "scallop", + "intent": "abalone", } path = FlowsClient.intent_path(**expected) @@ -2091,11 +2629,11 @@ def test_parse_intent_path(): def test_page_path(): - project = "oyster" - location = "nudibranch" - agent = "cuttlefish" - flow = "mussel" - page = "winkle" + project = "squid" + location = "clam" + agent = "whelk" + flow = "octopus" + page = "oyster" expected = "projects/{project}/locations/{location}/agents/{agent}/flows/{flow}/pages/{page}".format( project=project, location=location, agent=agent, flow=flow, page=page, @@ -2106,11 +2644,11 @@ def test_page_path(): def test_parse_page_path(): expected = { - "project": "nautilus", - "location": "scallop", - "agent": "abalone", - "flow": "squid", - "page": "clam", + "project": "nudibranch", + "location": "cuttlefish", + "agent": "mussel", + "flow": "winkle", + "page": "nautilus", } path = FlowsClient.page_path(**expected) @@ -2120,10 +2658,10 @@ def test_parse_page_path(): def test_webhook_path(): - project = "whelk" - location = "octopus" - agent = "oyster" - webhook = "nudibranch" + project = "scallop" + location = "abalone" + agent = "squid" + webhook = "clam" expected = "projects/{project}/locations/{location}/agents/{agent}/webhooks/{webhook}".format( project=project, location=location, agent=agent, webhook=webhook, @@ -2134,10 +2672,10 @@ def test_webhook_path(): def test_parse_webhook_path(): expected = { - "project": "cuttlefish", - "location": "mussel", - "agent": "winkle", - "webhook": "nautilus", + "project": "whelk", + "location": "octopus", + "agent": "oyster", + "webhook": "nudibranch", } path = FlowsClient.webhook_path(**expected) @@ -2147,7 +2685,7 @@ def test_parse_webhook_path(): def test_common_billing_account_path(): - billing_account = "scallop" + billing_account = "cuttlefish" expected = "billingAccounts/{billing_account}".format( billing_account=billing_account, @@ -2158,7 +2696,7 @@ def test_common_billing_account_path(): def test_parse_common_billing_account_path(): expected = { - "billing_account": "abalone", + "billing_account": "mussel", } path = FlowsClient.common_billing_account_path(**expected) @@ -2168,7 +2706,7 @@ def test_parse_common_billing_account_path(): def test_common_folder_path(): - folder = "squid" + folder = "winkle" expected = "folders/{folder}".format(folder=folder,) actual = FlowsClient.common_folder_path(folder) @@ -2177,7 +2715,7 @@ def test_common_folder_path(): def test_parse_common_folder_path(): expected = { - "folder": "clam", + "folder": "nautilus", } path = FlowsClient.common_folder_path(**expected) @@ -2187,7 +2725,7 @@ def test_parse_common_folder_path(): def test_common_organization_path(): - organization = "whelk" + organization = "scallop" expected = "organizations/{organization}".format(organization=organization,) actual = FlowsClient.common_organization_path(organization) @@ -2196,7 +2734,7 @@ def test_common_organization_path(): def test_parse_common_organization_path(): expected = { - "organization": "octopus", + "organization": "abalone", } path = FlowsClient.common_organization_path(**expected) @@ -2206,7 +2744,7 @@ def test_parse_common_organization_path(): def test_common_project_path(): - project = "oyster" + project = "squid" expected = "projects/{project}".format(project=project,) actual = FlowsClient.common_project_path(project) @@ -2215,7 +2753,7 @@ def test_common_project_path(): def test_parse_common_project_path(): expected = { - "project": "nudibranch", + "project": "clam", } path = FlowsClient.common_project_path(**expected) @@ -2225,8 +2763,8 @@ def test_parse_common_project_path(): def test_common_location_path(): - project = "cuttlefish" - location = "mussel" + project = "whelk" + location = "octopus" expected = "projects/{project}/locations/{location}".format( project=project, location=location, @@ -2237,8 +2775,8 @@ def test_common_location_path(): def test_parse_common_location_path(): expected = { - "project": "winkle", - "location": "nautilus", + "project": "oyster", + "location": "nudibranch", } path = FlowsClient.common_location_path(**expected) diff --git a/tests/unit/gapic/dialogflowcx_v3/test_intents.py b/tests/unit/gapic/dialogflowcx_v3/test_intents.py index 5735461e..55bd7934 100644 --- a/tests/unit/gapic/dialogflowcx_v3/test_intents.py +++ b/tests/unit/gapic/dialogflowcx_v3/test_intents.py @@ -80,7 +80,22 @@ def test__get_default_mtls_endpoint(): assert IntentsClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi -@pytest.mark.parametrize("client_class", [IntentsClient, IntentsAsyncClient]) +@pytest.mark.parametrize("client_class", [IntentsClient, IntentsAsyncClient,]) +def test_intents_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 == "dialogflow.googleapis.com:443" + + +@pytest.mark.parametrize("client_class", [IntentsClient, IntentsAsyncClient,]) def test_intents_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() with mock.patch.object( @@ -89,16 +104,21 @@ def test_intents_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 == "dialogflow.googleapis.com:443" def test_intents_client_get_transport_class(): transport = IntentsClient.get_transport_class() - assert transport == transports.IntentsGrpcTransport + available_transports = [ + transports.IntentsGrpcTransport, + ] + assert transport in available_transports transport = IntentsClient.get_transport_class("grpc") assert transport == transports.IntentsGrpcTransport @@ -139,7 +159,7 @@ def test_intents_client_client_options(client_class, transport_class, transport_ 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, ) @@ -155,7 +175,7 @@ def test_intents_client_client_options(client_class, transport_class, transport_ 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, ) @@ -171,7 +191,7 @@ def test_intents_client_client_options(client_class, transport_class, transport_ 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, ) @@ -199,7 +219,7 @@ def test_intents_client_client_options(client_class, transport_class, transport_ 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, ) @@ -246,29 +266,25 @@ def test_intents_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. @@ -277,66 +293,53 @@ def test_intents_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", @@ -358,7 +361,7 @@ def test_intents_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, ) @@ -384,7 +387,7 @@ def test_intents_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, ) @@ -401,7 +404,7 @@ def test_intents_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, ) @@ -442,6 +445,22 @@ def test_list_intents_from_dict(): test_list_intents(request_type=dict) +def test_list_intents_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 = IntentsClient( + 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_intents), "__call__") as call: + client.list_intents() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == intent.ListIntentsRequest() + + @pytest.mark.asyncio async def test_list_intents_async( transport: str = "grpc_asyncio", request_type=intent.ListIntentsRequest @@ -759,6 +778,22 @@ def test_get_intent_from_dict(): test_get_intent(request_type=dict) +def test_get_intent_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 = IntentsClient( + 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_intent), "__call__") as call: + client.get_intent() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == intent.GetIntentRequest() + + @pytest.mark.asyncio async def test_get_intent_async( transport: str = "grpc_asyncio", request_type=intent.GetIntentRequest @@ -974,6 +1009,22 @@ def test_create_intent_from_dict(): test_create_intent(request_type=dict) +def test_create_intent_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 = IntentsClient( + 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_intent), "__call__") as call: + client.create_intent() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_intent.CreateIntentRequest() + + @pytest.mark.asyncio async def test_create_intent_async( transport: str = "grpc_asyncio", request_type=gcdc_intent.CreateIntentRequest @@ -1201,6 +1252,22 @@ def test_update_intent_from_dict(): test_update_intent(request_type=dict) +def test_update_intent_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 = IntentsClient( + 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_intent), "__call__") as call: + client.update_intent() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_intent.UpdateIntentRequest() + + @pytest.mark.asyncio async def test_update_intent_async( transport: str = "grpc_asyncio", request_type=gcdc_intent.UpdateIntentRequest @@ -1413,6 +1480,22 @@ def test_delete_intent_from_dict(): test_delete_intent(request_type=dict) +def test_delete_intent_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 = IntentsClient( + 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_intent), "__call__") as call: + client.delete_intent() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == intent.DeleteIntentRequest() + + @pytest.mark.asyncio async def test_delete_intent_async( transport: str = "grpc_asyncio", request_type=intent.DeleteIntentRequest @@ -1617,7 +1700,7 @@ def test_transport_get_channel(): @pytest.mark.parametrize( "transport_class", - [transports.IntentsGrpcTransport, transports.IntentsGrpcAsyncIOTransport], + [transports.IntentsGrpcTransport, transports.IntentsGrpcAsyncIOTransport,], ) def test_transport_adc(transport_class): # Test default credentials are used if not provided. @@ -1730,6 +1813,51 @@ def test_intents_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [transports.IntentsGrpcTransport, transports.IntentsGrpcAsyncIOTransport], +) +def test_intents_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/dialogflow", + ), + 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_intents_host_no_port(): client = IntentsClient( credentials=credentials.AnonymousCredentials(), @@ -1751,7 +1879,7 @@ def test_intents_host_with_port(): def test_intents_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.IntentsGrpcTransport( @@ -1763,7 +1891,7 @@ def test_intents_grpc_transport_channel(): def test_intents_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.IntentsGrpcAsyncIOTransport( @@ -1774,6 +1902,8 @@ def test_intents_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.IntentsGrpcTransport, transports.IntentsGrpcAsyncIOTransport], @@ -1783,7 +1913,7 @@ def test_intents_transport_channel_mtls_with_client_cert_source(transport_class) "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 @@ -1824,6 +1954,8 @@ def test_intents_transport_channel_mtls_with_client_cert_source(transport_class) 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.IntentsGrpcTransport, transports.IntentsGrpcAsyncIOTransport], @@ -1836,7 +1968,7 @@ def test_intents_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/dialogflowcx_v3/test_pages.py b/tests/unit/gapic/dialogflowcx_v3/test_pages.py index 63101426..eb3f3413 100644 --- a/tests/unit/gapic/dialogflowcx_v3/test_pages.py +++ b/tests/unit/gapic/dialogflowcx_v3/test_pages.py @@ -83,7 +83,22 @@ def test__get_default_mtls_endpoint(): assert PagesClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi -@pytest.mark.parametrize("client_class", [PagesClient, PagesAsyncClient]) +@pytest.mark.parametrize("client_class", [PagesClient, PagesAsyncClient,]) +def test_pages_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 == "dialogflow.googleapis.com:443" + + +@pytest.mark.parametrize("client_class", [PagesClient, PagesAsyncClient,]) def test_pages_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() with mock.patch.object( @@ -92,16 +107,21 @@ def test_pages_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 == "dialogflow.googleapis.com:443" def test_pages_client_get_transport_class(): transport = PagesClient.get_transport_class() - assert transport == transports.PagesGrpcTransport + available_transports = [ + transports.PagesGrpcTransport, + ] + assert transport in available_transports transport = PagesClient.get_transport_class("grpc") assert transport == transports.PagesGrpcTransport @@ -142,7 +162,7 @@ def test_pages_client_client_options(client_class, transport_class, transport_na 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, ) @@ -158,7 +178,7 @@ def test_pages_client_client_options(client_class, transport_class, transport_na 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, ) @@ -174,7 +194,7 @@ def test_pages_client_client_options(client_class, transport_class, transport_na 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, ) @@ -202,7 +222,7 @@ def test_pages_client_client_options(client_class, transport_class, transport_na 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, ) @@ -249,29 +269,25 @@ def test_pages_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. @@ -280,66 +296,53 @@ def test_pages_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", @@ -361,7 +364,7 @@ def test_pages_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, ) @@ -387,7 +390,7 @@ def test_pages_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, ) @@ -404,7 +407,7 @@ def test_pages_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, ) @@ -445,6 +448,22 @@ def test_list_pages_from_dict(): test_list_pages(request_type=dict) +def test_list_pages_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 = PagesClient( + 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_pages), "__call__") as call: + client.list_pages() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == page.ListPagesRequest() + + @pytest.mark.asyncio async def test_list_pages_async( transport: str = "grpc_asyncio", request_type=page.ListPagesRequest @@ -744,6 +763,22 @@ def test_get_page_from_dict(): test_get_page(request_type=dict) +def test_get_page_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 = PagesClient( + 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_page), "__call__") as call: + client.get_page() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == page.GetPageRequest() + + @pytest.mark.asyncio async def test_get_page_async( transport: str = "grpc_asyncio", request_type=page.GetPageRequest @@ -945,6 +980,22 @@ def test_create_page_from_dict(): test_create_page(request_type=dict) +def test_create_page_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 = PagesClient( + 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_page), "__call__") as call: + client.create_page() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_page.CreatePageRequest() + + @pytest.mark.asyncio async def test_create_page_async( transport: str = "grpc_asyncio", request_type=gcdc_page.CreatePageRequest @@ -1158,6 +1209,22 @@ def test_update_page_from_dict(): test_update_page(request_type=dict) +def test_update_page_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 = PagesClient( + 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_page), "__call__") as call: + client.update_page() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_page.UpdatePageRequest() + + @pytest.mark.asyncio async def test_update_page_async( transport: str = "grpc_asyncio", request_type=gcdc_page.UpdatePageRequest @@ -1362,6 +1429,22 @@ def test_delete_page_from_dict(): test_delete_page(request_type=dict) +def test_delete_page_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 = PagesClient( + 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_page), "__call__") as call: + client.delete_page() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == page.DeletePageRequest() + + @pytest.mark.asyncio async def test_delete_page_async( transport: str = "grpc_asyncio", request_type=page.DeletePageRequest @@ -1566,7 +1649,7 @@ def test_transport_get_channel(): @pytest.mark.parametrize( "transport_class", - [transports.PagesGrpcTransport, transports.PagesGrpcAsyncIOTransport], + [transports.PagesGrpcTransport, transports.PagesGrpcAsyncIOTransport,], ) def test_transport_adc(transport_class): # Test default credentials are used if not provided. @@ -1679,6 +1762,51 @@ def test_pages_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [transports.PagesGrpcTransport, transports.PagesGrpcAsyncIOTransport], +) +def test_pages_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/dialogflow", + ), + 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_pages_host_no_port(): client = PagesClient( credentials=credentials.AnonymousCredentials(), @@ -1700,7 +1828,7 @@ def test_pages_host_with_port(): def test_pages_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.PagesGrpcTransport(host="squid.clam.whelk", channel=channel,) @@ -1710,7 +1838,7 @@ def test_pages_grpc_transport_channel(): def test_pages_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.PagesGrpcAsyncIOTransport( @@ -1721,6 +1849,8 @@ def test_pages_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.PagesGrpcTransport, transports.PagesGrpcAsyncIOTransport], @@ -1730,7 +1860,7 @@ def test_pages_transport_channel_mtls_with_client_cert_source(transport_class): "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 @@ -1771,6 +1901,8 @@ def test_pages_transport_channel_mtls_with_client_cert_source(transport_class): 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.PagesGrpcTransport, transports.PagesGrpcAsyncIOTransport], @@ -1783,7 +1915,7 @@ def test_pages_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/dialogflowcx_v3/test_security_settings_service.py b/tests/unit/gapic/dialogflowcx_v3/test_security_settings_service.py index 560e9732..d0eb88ee 100644 --- a/tests/unit/gapic/dialogflowcx_v3/test_security_settings_service.py +++ b/tests/unit/gapic/dialogflowcx_v3/test_security_settings_service.py @@ -94,7 +94,24 @@ def test__get_default_mtls_endpoint(): @pytest.mark.parametrize( - "client_class", [SecuritySettingsServiceClient, SecuritySettingsServiceAsyncClient] + "client_class", [SecuritySettingsServiceClient, SecuritySettingsServiceAsyncClient,] +) +def test_security_settings_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 == "dialogflow.googleapis.com:443" + + +@pytest.mark.parametrize( + "client_class", [SecuritySettingsServiceClient, SecuritySettingsServiceAsyncClient,] ) def test_security_settings_service_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() @@ -104,16 +121,21 @@ def test_security_settings_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 == "dialogflow.googleapis.com:443" def test_security_settings_service_client_get_transport_class(): transport = SecuritySettingsServiceClient.get_transport_class() - assert transport == transports.SecuritySettingsServiceGrpcTransport + available_transports = [ + transports.SecuritySettingsServiceGrpcTransport, + ] + assert transport in available_transports transport = SecuritySettingsServiceClient.get_transport_class("grpc") assert transport == transports.SecuritySettingsServiceGrpcTransport @@ -168,7 +190,7 @@ def test_security_settings_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, ) @@ -184,7 +206,7 @@ def test_security_settings_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, ) @@ -200,7 +222,7 @@ def test_security_settings_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, ) @@ -228,7 +250,7 @@ def test_security_settings_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, ) @@ -289,29 +311,25 @@ def test_security_settings_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. @@ -320,66 +338,53 @@ def test_security_settings_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", @@ -409,7 +414,7 @@ def test_security_settings_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, ) @@ -443,7 +448,7 @@ def test_security_settings_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, ) @@ -462,7 +467,7 @@ def test_security_settings_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, ) @@ -534,6 +539,24 @@ def test_create_security_settings_from_dict(): test_create_security_settings(request_type=dict) +def test_create_security_settings_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 = SecuritySettingsServiceClient( + 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_security_settings), "__call__" + ) as call: + client.create_security_settings() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_security_settings.CreateSecuritySettingsRequest() + + @pytest.mark.asyncio async def test_create_security_settings_async( transport: str = "grpc_asyncio", @@ -831,6 +854,24 @@ def test_get_security_settings_from_dict(): test_get_security_settings(request_type=dict) +def test_get_security_settings_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 = SecuritySettingsServiceClient( + 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_security_settings), "__call__" + ) as call: + client.get_security_settings() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == security_settings.GetSecuritySettingsRequest() + + @pytest.mark.asyncio async def test_get_security_settings_async( transport: str = "grpc_asyncio", @@ -1103,6 +1144,24 @@ def test_update_security_settings_from_dict(): test_update_security_settings(request_type=dict) +def test_update_security_settings_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 = SecuritySettingsServiceClient( + 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_security_settings), "__call__" + ) as call: + client.update_security_settings() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_security_settings.UpdateSecuritySettingsRequest() + + @pytest.mark.asyncio async def test_update_security_settings_async( transport: str = "grpc_asyncio", @@ -1380,6 +1439,24 @@ def test_list_security_settings_from_dict(): test_list_security_settings(request_type=dict) +def test_list_security_settings_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 = SecuritySettingsServiceClient( + 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_security_settings), "__call__" + ) as call: + client.list_security_settings() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == security_settings.ListSecuritySettingsRequest() + + @pytest.mark.asyncio async def test_list_security_settings_async( transport: str = "grpc_asyncio", @@ -1774,6 +1851,24 @@ def test_delete_security_settings_from_dict(): test_delete_security_settings(request_type=dict) +def test_delete_security_settings_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 = SecuritySettingsServiceClient( + 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_security_settings), "__call__" + ) as call: + client.delete_security_settings() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == security_settings.DeleteSecuritySettingsRequest() + + @pytest.mark.asyncio async def test_delete_security_settings_async( transport: str = "grpc_asyncio", @@ -2121,6 +2216,56 @@ def test_security_settings_service_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [ + transports.SecuritySettingsServiceGrpcTransport, + transports.SecuritySettingsServiceGrpcAsyncIOTransport, + ], +) +def test_security_settings_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/dialogflow", + ), + 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_security_settings_service_host_no_port(): client = SecuritySettingsServiceClient( credentials=credentials.AnonymousCredentials(), @@ -2142,7 +2287,7 @@ def test_security_settings_service_host_with_port(): def test_security_settings_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.SecuritySettingsServiceGrpcTransport( @@ -2154,7 +2299,7 @@ def test_security_settings_service_grpc_transport_channel(): def test_security_settings_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.SecuritySettingsServiceGrpcAsyncIOTransport( @@ -2165,6 +2310,8 @@ def test_security_settings_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", [ @@ -2179,7 +2326,7 @@ def test_security_settings_service_transport_channel_mtls_with_client_cert_sourc "grpc.ssl_channel_credentials", autospec=True ) as grpc_ssl_channel_cred: with mock.patch.object( - transport_class, "create_channel", autospec=True + transport_class, "create_channel" ) as grpc_create_channel: mock_ssl_cred = mock.Mock() grpc_ssl_channel_cred.return_value = mock_ssl_cred @@ -2220,6 +2367,8 @@ def test_security_settings_service_transport_channel_mtls_with_client_cert_sourc assert transport._ssl_channel_credentials == mock_ssl_cred +# Remove this test when deprecated arguments (api_mtls_endpoint, client_cert_source) are +# removed from grpc/grpc_asyncio transport constructor. @pytest.mark.parametrize( "transport_class", [ @@ -2235,7 +2384,7 @@ def test_security_settings_service_transport_channel_mtls_with_adc(transport_cla ssl_credentials=mock.PropertyMock(return_value=mock_ssl_cred), ): with mock.patch.object( - transport_class, "create_channel", autospec=True + transport_class, "create_channel" ) as grpc_create_channel: mock_grpc_channel = mock.Mock() grpc_create_channel.return_value = mock_grpc_channel diff --git a/tests/unit/gapic/dialogflowcx_v3/test_session_entity_types.py b/tests/unit/gapic/dialogflowcx_v3/test_session_entity_types.py index 07e17479..530e9a89 100644 --- a/tests/unit/gapic/dialogflowcx_v3/test_session_entity_types.py +++ b/tests/unit/gapic/dialogflowcx_v3/test_session_entity_types.py @@ -95,7 +95,24 @@ def test__get_default_mtls_endpoint(): @pytest.mark.parametrize( - "client_class", [SessionEntityTypesClient, SessionEntityTypesAsyncClient] + "client_class", [SessionEntityTypesClient, SessionEntityTypesAsyncClient,] +) +def test_session_entity_types_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 == "dialogflow.googleapis.com:443" + + +@pytest.mark.parametrize( + "client_class", [SessionEntityTypesClient, SessionEntityTypesAsyncClient,] ) def test_session_entity_types_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() @@ -105,16 +122,21 @@ def test_session_entity_types_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 == "dialogflow.googleapis.com:443" def test_session_entity_types_client_get_transport_class(): transport = SessionEntityTypesClient.get_transport_class() - assert transport == transports.SessionEntityTypesGrpcTransport + available_transports = [ + transports.SessionEntityTypesGrpcTransport, + ] + assert transport in available_transports transport = SessionEntityTypesClient.get_transport_class("grpc") assert transport == transports.SessionEntityTypesGrpcTransport @@ -165,7 +187,7 @@ def test_session_entity_types_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 +203,7 @@ def test_session_entity_types_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 +219,7 @@ def test_session_entity_types_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 +247,7 @@ def test_session_entity_types_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, ) @@ -286,29 +308,25 @@ def test_session_entity_types_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. @@ -317,66 +335,53 @@ def test_session_entity_types_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", @@ -402,7 +407,7 @@ def test_session_entity_types_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, ) @@ -432,7 +437,7 @@ def test_session_entity_types_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, ) @@ -451,7 +456,7 @@ def test_session_entity_types_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, ) @@ -497,6 +502,24 @@ def test_list_session_entity_types_from_dict(): test_list_session_entity_types(request_type=dict) +def test_list_session_entity_types_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 = SessionEntityTypesClient( + 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_session_entity_types), "__call__" + ) as call: + client.list_session_entity_types() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == session_entity_type.ListSessionEntityTypesRequest() + + @pytest.mark.asyncio async def test_list_session_entity_types_async( transport: str = "grpc_asyncio", @@ -896,6 +919,24 @@ def test_get_session_entity_type_from_dict(): test_get_session_entity_type(request_type=dict) +def test_get_session_entity_type_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 = SessionEntityTypesClient( + 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_session_entity_type), "__call__" + ) as call: + client.get_session_entity_type() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == session_entity_type.GetSessionEntityTypeRequest() + + @pytest.mark.asyncio async def test_get_session_entity_type_async( transport: str = "grpc_asyncio", @@ -1123,6 +1164,24 @@ def test_create_session_entity_type_from_dict(): test_create_session_entity_type(request_type=dict) +def test_create_session_entity_type_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 = SessionEntityTypesClient( + 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_session_entity_type), "__call__" + ) as call: + client.create_session_entity_type() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_session_entity_type.CreateSessionEntityTypeRequest() + + @pytest.mark.asyncio async def test_create_session_entity_type_async( transport: str = "grpc_asyncio", @@ -1380,6 +1439,24 @@ def test_update_session_entity_type_from_dict(): test_update_session_entity_type(request_type=dict) +def test_update_session_entity_type_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 = SessionEntityTypesClient( + 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_session_entity_type), "__call__" + ) as call: + client.update_session_entity_type() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_session_entity_type.UpdateSessionEntityTypeRequest() + + @pytest.mark.asyncio async def test_update_session_entity_type_async( transport: str = "grpc_asyncio", @@ -1632,6 +1709,24 @@ def test_delete_session_entity_type_from_dict(): test_delete_session_entity_type(request_type=dict) +def test_delete_session_entity_type_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 = SessionEntityTypesClient( + 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_session_entity_type), "__call__" + ) as call: + client.delete_session_entity_type() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == session_entity_type.DeleteSessionEntityTypeRequest() + + @pytest.mark.asyncio async def test_delete_session_entity_type_async( transport: str = "grpc_asyncio", @@ -1969,6 +2064,56 @@ def test_session_entity_types_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [ + transports.SessionEntityTypesGrpcTransport, + transports.SessionEntityTypesGrpcAsyncIOTransport, + ], +) +def test_session_entity_types_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/dialogflow", + ), + 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_session_entity_types_host_no_port(): client = SessionEntityTypesClient( credentials=credentials.AnonymousCredentials(), @@ -1990,7 +2135,7 @@ def test_session_entity_types_host_with_port(): def test_session_entity_types_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.SessionEntityTypesGrpcTransport( @@ -2002,7 +2147,7 @@ def test_session_entity_types_grpc_transport_channel(): def test_session_entity_types_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.SessionEntityTypesGrpcAsyncIOTransport( @@ -2013,6 +2158,8 @@ def test_session_entity_types_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", [ @@ -2027,7 +2174,7 @@ def test_session_entity_types_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 @@ -2068,6 +2215,8 @@ def test_session_entity_types_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", [ @@ -2083,7 +2232,7 @@ def test_session_entity_types_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/dialogflowcx_v3/test_sessions.py b/tests/unit/gapic/dialogflowcx_v3/test_sessions.py index 9dd954d5..47d2e0a8 100644 --- a/tests/unit/gapic/dialogflowcx_v3/test_sessions.py +++ b/tests/unit/gapic/dialogflowcx_v3/test_sessions.py @@ -85,7 +85,22 @@ def test__get_default_mtls_endpoint(): assert SessionsClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi -@pytest.mark.parametrize("client_class", [SessionsClient, SessionsAsyncClient]) +@pytest.mark.parametrize("client_class", [SessionsClient, SessionsAsyncClient,]) +def test_sessions_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 == "dialogflow.googleapis.com:443" + + +@pytest.mark.parametrize("client_class", [SessionsClient, SessionsAsyncClient,]) def test_sessions_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() with mock.patch.object( @@ -94,16 +109,21 @@ def test_sessions_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 == "dialogflow.googleapis.com:443" def test_sessions_client_get_transport_class(): transport = SessionsClient.get_transport_class() - assert transport == transports.SessionsGrpcTransport + available_transports = [ + transports.SessionsGrpcTransport, + ] + assert transport in available_transports transport = SessionsClient.get_transport_class("grpc") assert transport == transports.SessionsGrpcTransport @@ -146,7 +166,7 @@ def test_sessions_client_client_options(client_class, transport_class, transport 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, ) @@ -162,7 +182,7 @@ def test_sessions_client_client_options(client_class, transport_class, transport 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, ) @@ -178,7 +198,7 @@ def test_sessions_client_client_options(client_class, transport_class, transport 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, ) @@ -206,7 +226,7 @@ def test_sessions_client_client_options(client_class, transport_class, transport 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, ) @@ -255,29 +275,25 @@ def test_sessions_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. @@ -286,66 +302,53 @@ def test_sessions_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", @@ -367,7 +370,7 @@ def test_sessions_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, ) @@ -393,7 +396,7 @@ def test_sessions_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, ) @@ -410,7 +413,7 @@ def test_sessions_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, ) @@ -455,6 +458,22 @@ def test_detect_intent_from_dict(): test_detect_intent(request_type=dict) +def test_detect_intent_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 = SessionsClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.detect_intent), "__call__") as call: + client.detect_intent() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == session.DetectIntentRequest() + + @pytest.mark.asyncio async def test_detect_intent_async( transport: str = "grpc_asyncio", request_type=session.DetectIntentRequest @@ -658,6 +677,22 @@ def test_match_intent_from_dict(): test_match_intent(request_type=dict) +def test_match_intent_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 = SessionsClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.match_intent), "__call__") as call: + client.match_intent() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == session.MatchIntentRequest() + + @pytest.mark.asyncio async def test_match_intent_async( transport: str = "grpc_asyncio", request_type=session.MatchIntentRequest @@ -784,6 +819,22 @@ def test_fulfill_intent_from_dict(): test_fulfill_intent(request_type=dict) +def test_fulfill_intent_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 = SessionsClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.fulfill_intent), "__call__") as call: + client.fulfill_intent() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == session.FulfillIntentRequest() + + @pytest.mark.asyncio async def test_fulfill_intent_async( transport: str = "grpc_asyncio", request_type=session.FulfillIntentRequest @@ -939,7 +990,7 @@ def test_transport_get_channel(): @pytest.mark.parametrize( "transport_class", - [transports.SessionsGrpcTransport, transports.SessionsGrpcAsyncIOTransport], + [transports.SessionsGrpcTransport, transports.SessionsGrpcAsyncIOTransport,], ) def test_transport_adc(transport_class): # Test default credentials are used if not provided. @@ -1051,6 +1102,51 @@ def test_sessions_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [transports.SessionsGrpcTransport, transports.SessionsGrpcAsyncIOTransport], +) +def test_sessions_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/dialogflow", + ), + 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_sessions_host_no_port(): client = SessionsClient( credentials=credentials.AnonymousCredentials(), @@ -1072,7 +1168,7 @@ def test_sessions_host_with_port(): def test_sessions_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.SessionsGrpcTransport( @@ -1084,7 +1180,7 @@ def test_sessions_grpc_transport_channel(): def test_sessions_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.SessionsGrpcAsyncIOTransport( @@ -1095,6 +1191,8 @@ def test_sessions_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.SessionsGrpcTransport, transports.SessionsGrpcAsyncIOTransport], @@ -1104,7 +1202,7 @@ def test_sessions_transport_channel_mtls_with_client_cert_source(transport_class "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 @@ -1145,6 +1243,8 @@ def test_sessions_transport_channel_mtls_with_client_cert_source(transport_class 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.SessionsGrpcTransport, transports.SessionsGrpcAsyncIOTransport], @@ -1157,7 +1257,7 @@ def test_sessions_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/dialogflowcx_v3/test_test_cases.py b/tests/unit/gapic/dialogflowcx_v3/test_test_cases.py new file mode 100644 index 00000000..8f221cbb --- /dev/null +++ b/tests/unit/gapic/dialogflowcx_v3/test_test_cases.py @@ -0,0 +1,3630 @@ +# -*- 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. +# + +import os +import mock + +import grpc +from grpc.experimental import aio +import math +import pytest +from proto.marshal.rules.dates import DurationRule, TimestampRule + +from google import auth +from google.api_core import client_options +from google.api_core import exceptions +from google.api_core import future +from google.api_core import gapic_v1 +from google.api_core import grpc_helpers +from google.api_core import grpc_helpers_async +from google.api_core import operation_async # type: ignore +from google.api_core import operations_v1 +from google.auth import credentials +from google.auth.exceptions import MutualTLSChannelError +from google.cloud.dialogflowcx_v3.services.test_cases import TestCasesAsyncClient +from google.cloud.dialogflowcx_v3.services.test_cases import TestCasesClient +from google.cloud.dialogflowcx_v3.services.test_cases import pagers +from google.cloud.dialogflowcx_v3.services.test_cases import transports +from google.cloud.dialogflowcx_v3.types import audio_config +from google.cloud.dialogflowcx_v3.types import fulfillment +from google.cloud.dialogflowcx_v3.types import intent +from google.cloud.dialogflowcx_v3.types import page +from google.cloud.dialogflowcx_v3.types import response_message +from google.cloud.dialogflowcx_v3.types import session +from google.cloud.dialogflowcx_v3.types import test_case +from google.cloud.dialogflowcx_v3.types import test_case as gcdc_test_case +from google.longrunning import operations_pb2 +from google.oauth2 import service_account +from google.protobuf import any_pb2 as gp_any # type: ignore +from google.protobuf import field_mask_pb2 as field_mask # type: ignore +from google.protobuf import struct_pb2 as struct # type: ignore +from google.protobuf import timestamp_pb2 as timestamp # type: ignore +from google.rpc import status_pb2 as status # type: ignore + + +def client_cert_source_callback(): + return b"cert bytes", b"key bytes" + + +# If default endpoint is localhost, then default mtls endpoint will be the same. +# This method modifies the default endpoint so the client can produce a different +# mtls endpoint for endpoint testing purposes. +def modify_default_endpoint(client): + return ( + "foo.googleapis.com" + if ("localhost" in client.DEFAULT_ENDPOINT) + else client.DEFAULT_ENDPOINT + ) + + +def test__get_default_mtls_endpoint(): + api_endpoint = "example.googleapis.com" + api_mtls_endpoint = "example.mtls.googleapis.com" + sandbox_endpoint = "example.sandbox.googleapis.com" + sandbox_mtls_endpoint = "example.mtls.sandbox.googleapis.com" + non_googleapi = "api.example.com" + + assert TestCasesClient._get_default_mtls_endpoint(None) is None + assert TestCasesClient._get_default_mtls_endpoint(api_endpoint) == api_mtls_endpoint + assert ( + TestCasesClient._get_default_mtls_endpoint(api_mtls_endpoint) + == api_mtls_endpoint + ) + assert ( + TestCasesClient._get_default_mtls_endpoint(sandbox_endpoint) + == sandbox_mtls_endpoint + ) + assert ( + TestCasesClient._get_default_mtls_endpoint(sandbox_mtls_endpoint) + == sandbox_mtls_endpoint + ) + assert TestCasesClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi + + +@pytest.mark.parametrize("client_class", [TestCasesClient, TestCasesAsyncClient,]) +def test_test_cases_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 == "dialogflow.googleapis.com:443" + + +@pytest.mark.parametrize("client_class", [TestCasesClient, TestCasesAsyncClient,]) +def test_test_cases_client_from_service_account_file(client_class): + creds = credentials.AnonymousCredentials() + with mock.patch.object( + service_account.Credentials, "from_service_account_file" + ) as factory: + factory.return_value = creds + client = client_class.from_service_account_file("dummy/file/path.json") + 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 == "dialogflow.googleapis.com:443" + + +def test_test_cases_client_get_transport_class(): + transport = TestCasesClient.get_transport_class() + available_transports = [ + transports.TestCasesGrpcTransport, + ] + assert transport in available_transports + + transport = TestCasesClient.get_transport_class("grpc") + assert transport == transports.TestCasesGrpcTransport + + +@pytest.mark.parametrize( + "client_class,transport_class,transport_name", + [ + (TestCasesClient, transports.TestCasesGrpcTransport, "grpc"), + ( + TestCasesAsyncClient, + transports.TestCasesGrpcAsyncIOTransport, + "grpc_asyncio", + ), + ], +) +@mock.patch.object( + TestCasesClient, "DEFAULT_ENDPOINT", modify_default_endpoint(TestCasesClient) +) +@mock.patch.object( + TestCasesAsyncClient, + "DEFAULT_ENDPOINT", + modify_default_endpoint(TestCasesAsyncClient), +) +def test_test_cases_client_client_options( + client_class, transport_class, transport_name +): + # Check that if channel is provided we won't create a new one. + with mock.patch.object(TestCasesClient, "get_transport_class") as gtc: + transport = transport_class(credentials=credentials.AnonymousCredentials()) + client = client_class(transport=transport) + gtc.assert_not_called() + + # Check that if channel is provided via str we will create a new one. + with mock.patch.object(TestCasesClient, "get_transport_class") as gtc: + client = client_class(transport=transport_name) + gtc.assert_called() + + # Check the case api_endpoint is provided. + options = client_options.ClientOptions(api_endpoint="squid.clam.whelk") + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(client_options=options) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host="squid.clam.whelk", + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) + + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT is + # "never". + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}): + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class() + 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, + ) + + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT is + # "always". + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}): + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class() + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_MTLS_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) + + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT has + # unsupported value. + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "Unsupported"}): + with pytest.raises(MutualTLSChannelError): + client = client_class() + + # Check the case GOOGLE_API_USE_CLIENT_CERTIFICATE has unsupported value. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"} + ): + with pytest.raises(ValueError): + client = client_class() + + # Check the case quota_project_id is provided + options = client_options.ClientOptions(quota_project_id="octopus") + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(client_options=options) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id="octopus", + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) + + +@pytest.mark.parametrize( + "client_class,transport_class,transport_name,use_client_cert_env", + [ + (TestCasesClient, transports.TestCasesGrpcTransport, "grpc", "true"), + ( + TestCasesAsyncClient, + transports.TestCasesGrpcAsyncIOTransport, + "grpc_asyncio", + "true", + ), + (TestCasesClient, transports.TestCasesGrpcTransport, "grpc", "false"), + ( + TestCasesAsyncClient, + transports.TestCasesGrpcAsyncIOTransport, + "grpc_asyncio", + "false", + ), + ], +) +@mock.patch.object( + TestCasesClient, "DEFAULT_ENDPOINT", modify_default_endpoint(TestCasesClient) +) +@mock.patch.object( + TestCasesAsyncClient, + "DEFAULT_ENDPOINT", + modify_default_endpoint(TestCasesAsyncClient), +) +@mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "auto"}) +def test_test_cases_client_mtls_env_auto( + client_class, transport_class, transport_name, use_client_cert_env +): + # This tests the endpoint autoswitch behavior. Endpoint is autoswitched to the default + # mtls endpoint, if GOOGLE_API_USE_CLIENT_CERTIFICATE is "true" and client cert exists. + + # Check the case client_cert_source is provided. Whether client cert is used depends on + # GOOGLE_API_USE_CLIENT_CERTIFICATE value. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env} + ): + options = client_options.ClientOptions( + client_cert_source=client_cert_source_callback + ) + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(client_options=options) + + if use_client_cert_env == "false": + expected_client_cert_source = None + expected_host = client.DEFAULT_ENDPOINT + else: + expected_client_cert_source = client_cert_source_callback + expected_host = client.DEFAULT_MTLS_ENDPOINT + + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=expected_host, + scopes=None, + client_cert_source_for_mtls=expected_client_cert_source, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) + + # Check the case ADC client cert is provided. Whether client cert is used depends on + # GOOGLE_API_USE_CLIENT_CERTIFICATE value. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env} + ): + with mock.patch.object(transport_class, "__init__") as patched: + with mock.patch( + "google.auth.transport.mtls.has_default_client_cert_source", + return_value=True, + ): + with mock.patch( + "google.auth.transport.mtls.default_client_cert_source", + return_value=client_cert_source_callback, + ): + if use_client_cert_env == "false": + expected_host = client.DEFAULT_ENDPOINT + expected_client_cert_source = None + else: + expected_host = client.DEFAULT_MTLS_ENDPOINT + expected_client_cert_source = client_cert_source_callback + + patched.return_value = None + client = client_class() + 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 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", + [ + (TestCasesClient, transports.TestCasesGrpcTransport, "grpc"), + ( + TestCasesAsyncClient, + transports.TestCasesGrpcAsyncIOTransport, + "grpc_asyncio", + ), + ], +) +def test_test_cases_client_client_options_scopes( + client_class, transport_class, transport_name +): + # Check the case scopes are provided. + options = client_options.ClientOptions(scopes=["1", "2"],) + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(client_options=options) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=["1", "2"], + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) + + +@pytest.mark.parametrize( + "client_class,transport_class,transport_name", + [ + (TestCasesClient, transports.TestCasesGrpcTransport, "grpc"), + ( + TestCasesAsyncClient, + transports.TestCasesGrpcAsyncIOTransport, + "grpc_asyncio", + ), + ], +) +def test_test_cases_client_client_options_credentials_file( + client_class, transport_class, transport_name +): + # Check the case credentials file is provided. + options = client_options.ClientOptions(credentials_file="credentials.json") + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(client_options=options) + patched.assert_called_once_with( + credentials=None, + credentials_file="credentials.json", + host=client.DEFAULT_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) + + +def test_test_cases_client_client_options_from_dict(): + with mock.patch( + "google.cloud.dialogflowcx_v3.services.test_cases.transports.TestCasesGrpcTransport.__init__" + ) as grpc_transport: + grpc_transport.return_value = None + client = TestCasesClient(client_options={"api_endpoint": "squid.clam.whelk"}) + grpc_transport.assert_called_once_with( + credentials=None, + credentials_file=None, + host="squid.clam.whelk", + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) + + +def test_list_test_cases( + transport: str = "grpc", request_type=test_case.ListTestCasesRequest +): + client = TestCasesClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_test_cases), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = test_case.ListTestCasesResponse( + next_page_token="next_page_token_value", + ) + + response = client.list_test_cases(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.ListTestCasesRequest() + + # Establish that the response is the type that we expect. + + assert isinstance(response, pagers.ListTestCasesPager) + + assert response.next_page_token == "next_page_token_value" + + +def test_list_test_cases_from_dict(): + test_list_test_cases(request_type=dict) + + +def test_list_test_cases_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 = TestCasesClient( + 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_test_cases), "__call__") as call: + client.list_test_cases() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.ListTestCasesRequest() + + +@pytest.mark.asyncio +async def test_list_test_cases_async( + transport: str = "grpc_asyncio", request_type=test_case.ListTestCasesRequest +): + client = TestCasesAsyncClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_test_cases), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + test_case.ListTestCasesResponse(next_page_token="next_page_token_value",) + ) + + response = await client.list_test_cases(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.ListTestCasesRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListTestCasesAsyncPager) + + assert response.next_page_token == "next_page_token_value" + + +@pytest.mark.asyncio +async def test_list_test_cases_async_from_dict(): + await test_list_test_cases_async(request_type=dict) + + +def test_list_test_cases_field_headers(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = test_case.ListTestCasesRequest() + request.parent = "parent/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_test_cases), "__call__") as call: + call.return_value = test_case.ListTestCasesResponse() + + client.list_test_cases(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "parent=parent/value",) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_list_test_cases_field_headers_async(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = test_case.ListTestCasesRequest() + request.parent = "parent/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_test_cases), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + test_case.ListTestCasesResponse() + ) + + await client.list_test_cases(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "parent=parent/value",) in kw["metadata"] + + +def test_list_test_cases_flattened(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials(),) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_test_cases), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = test_case.ListTestCasesResponse() + + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.list_test_cases(parent="parent_value",) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0].parent == "parent_value" + + +def test_list_test_cases_flattened_error(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials(),) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_test_cases( + test_case.ListTestCasesRequest(), parent="parent_value", + ) + + +@pytest.mark.asyncio +async def test_list_test_cases_flattened_async(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_test_cases), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = test_case.ListTestCasesResponse() + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + test_case.ListTestCasesResponse() + ) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.list_test_cases(parent="parent_value",) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0].parent == "parent_value" + + +@pytest.mark.asyncio +async def test_list_test_cases_flattened_error_async(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.list_test_cases( + test_case.ListTestCasesRequest(), parent="parent_value", + ) + + +def test_list_test_cases_pager(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials,) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_test_cases), "__call__") as call: + # Set the response to a series of pages. + call.side_effect = ( + test_case.ListTestCasesResponse( + test_cases=[ + test_case.TestCase(), + test_case.TestCase(), + test_case.TestCase(), + ], + next_page_token="abc", + ), + test_case.ListTestCasesResponse(test_cases=[], next_page_token="def",), + test_case.ListTestCasesResponse( + test_cases=[test_case.TestCase(),], next_page_token="ghi", + ), + test_case.ListTestCasesResponse( + test_cases=[test_case.TestCase(), test_case.TestCase(),], + ), + RuntimeError, + ) + + metadata = () + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", ""),)), + ) + pager = client.list_test_cases(request={}) + + assert pager._metadata == metadata + + results = [i for i in pager] + assert len(results) == 6 + assert all(isinstance(i, test_case.TestCase) for i in results) + + +def test_list_test_cases_pages(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials,) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_test_cases), "__call__") as call: + # Set the response to a series of pages. + call.side_effect = ( + test_case.ListTestCasesResponse( + test_cases=[ + test_case.TestCase(), + test_case.TestCase(), + test_case.TestCase(), + ], + next_page_token="abc", + ), + test_case.ListTestCasesResponse(test_cases=[], next_page_token="def",), + test_case.ListTestCasesResponse( + test_cases=[test_case.TestCase(),], next_page_token="ghi", + ), + test_case.ListTestCasesResponse( + test_cases=[test_case.TestCase(), test_case.TestCase(),], + ), + RuntimeError, + ) + pages = list(client.list_test_cases(request={}).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + +@pytest.mark.asyncio +async def test_list_test_cases_async_pager(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials,) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_test_cases), "__call__", new_callable=mock.AsyncMock + ) as call: + # Set the response to a series of pages. + call.side_effect = ( + test_case.ListTestCasesResponse( + test_cases=[ + test_case.TestCase(), + test_case.TestCase(), + test_case.TestCase(), + ], + next_page_token="abc", + ), + test_case.ListTestCasesResponse(test_cases=[], next_page_token="def",), + test_case.ListTestCasesResponse( + test_cases=[test_case.TestCase(),], next_page_token="ghi", + ), + test_case.ListTestCasesResponse( + test_cases=[test_case.TestCase(), test_case.TestCase(),], + ), + RuntimeError, + ) + async_pager = await client.list_test_cases(request={},) + assert async_pager.next_page_token == "abc" + responses = [] + async for response in async_pager: + responses.append(response) + + assert len(responses) == 6 + assert all(isinstance(i, test_case.TestCase) for i in responses) + + +@pytest.mark.asyncio +async def test_list_test_cases_async_pages(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials,) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_test_cases), "__call__", new_callable=mock.AsyncMock + ) as call: + # Set the response to a series of pages. + call.side_effect = ( + test_case.ListTestCasesResponse( + test_cases=[ + test_case.TestCase(), + test_case.TestCase(), + test_case.TestCase(), + ], + next_page_token="abc", + ), + test_case.ListTestCasesResponse(test_cases=[], next_page_token="def",), + test_case.ListTestCasesResponse( + test_cases=[test_case.TestCase(),], next_page_token="ghi", + ), + test_case.ListTestCasesResponse( + test_cases=[test_case.TestCase(), test_case.TestCase(),], + ), + RuntimeError, + ) + pages = [] + async for page_ in (await client.list_test_cases(request={})).pages: + pages.append(page_) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + +def test_batch_delete_test_cases( + transport: str = "grpc", request_type=test_case.BatchDeleteTestCasesRequest +): + client = TestCasesClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.batch_delete_test_cases), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = None + + response = client.batch_delete_test_cases(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.BatchDeleteTestCasesRequest() + + # Establish that the response is the type that we expect. + assert response is None + + +def test_batch_delete_test_cases_from_dict(): + test_batch_delete_test_cases(request_type=dict) + + +def test_batch_delete_test_cases_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 = TestCasesClient( + 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_test_cases), "__call__" + ) as call: + client.batch_delete_test_cases() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.BatchDeleteTestCasesRequest() + + +@pytest.mark.asyncio +async def test_batch_delete_test_cases_async( + transport: str = "grpc_asyncio", request_type=test_case.BatchDeleteTestCasesRequest +): + client = TestCasesAsyncClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.batch_delete_test_cases), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + + response = await client.batch_delete_test_cases(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.BatchDeleteTestCasesRequest() + + # Establish that the response is the type that we expect. + assert response is None + + +@pytest.mark.asyncio +async def test_batch_delete_test_cases_async_from_dict(): + await test_batch_delete_test_cases_async(request_type=dict) + + +def test_batch_delete_test_cases_field_headers(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = test_case.BatchDeleteTestCasesRequest() + request.parent = "parent/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.batch_delete_test_cases), "__call__" + ) as call: + call.return_value = None + + client.batch_delete_test_cases(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "parent=parent/value",) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_batch_delete_test_cases_field_headers_async(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = test_case.BatchDeleteTestCasesRequest() + request.parent = "parent/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.batch_delete_test_cases), "__call__" + ) as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + + await client.batch_delete_test_cases(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "parent=parent/value",) in kw["metadata"] + + +def test_batch_delete_test_cases_flattened(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials(),) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.batch_delete_test_cases), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = None + + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.batch_delete_test_cases(parent="parent_value",) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0].parent == "parent_value" + + +def test_batch_delete_test_cases_flattened_error(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials(),) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.batch_delete_test_cases( + test_case.BatchDeleteTestCasesRequest(), parent="parent_value", + ) + + +@pytest.mark.asyncio +async def test_batch_delete_test_cases_flattened_async(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.batch_delete_test_cases), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = None + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.batch_delete_test_cases(parent="parent_value",) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0].parent == "parent_value" + + +@pytest.mark.asyncio +async def test_batch_delete_test_cases_flattened_error_async(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.batch_delete_test_cases( + test_case.BatchDeleteTestCasesRequest(), parent="parent_value", + ) + + +def test_get_test_case( + transport: str = "grpc", request_type=test_case.GetTestCaseRequest +): + client = TestCasesClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_test_case), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = test_case.TestCase( + name="name_value", + tags=["tags_value"], + display_name="display_name_value", + notes="notes_value", + ) + + response = client.get_test_case(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.GetTestCaseRequest() + + # Establish that the response is the type that we expect. + + assert isinstance(response, test_case.TestCase) + + assert response.name == "name_value" + + assert response.tags == ["tags_value"] + + assert response.display_name == "display_name_value" + + assert response.notes == "notes_value" + + +def test_get_test_case_from_dict(): + test_get_test_case(request_type=dict) + + +def test_get_test_case_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 = TestCasesClient( + 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_test_case), "__call__") as call: + client.get_test_case() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.GetTestCaseRequest() + + +@pytest.mark.asyncio +async def test_get_test_case_async( + transport: str = "grpc_asyncio", request_type=test_case.GetTestCaseRequest +): + client = TestCasesAsyncClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_test_case), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + test_case.TestCase( + name="name_value", + tags=["tags_value"], + display_name="display_name_value", + notes="notes_value", + ) + ) + + response = await client.get_test_case(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.GetTestCaseRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, test_case.TestCase) + + assert response.name == "name_value" + + assert response.tags == ["tags_value"] + + assert response.display_name == "display_name_value" + + assert response.notes == "notes_value" + + +@pytest.mark.asyncio +async def test_get_test_case_async_from_dict(): + await test_get_test_case_async(request_type=dict) + + +def test_get_test_case_field_headers(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = test_case.GetTestCaseRequest() + request.name = "name/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_test_case), "__call__") as call: + call.return_value = test_case.TestCase() + + client.get_test_case(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "name=name/value",) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_get_test_case_field_headers_async(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = test_case.GetTestCaseRequest() + request.name = "name/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_test_case), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(test_case.TestCase()) + + await client.get_test_case(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "name=name/value",) in kw["metadata"] + + +def test_get_test_case_flattened(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials(),) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_test_case), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = test_case.TestCase() + + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.get_test_case(name="name_value",) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0].name == "name_value" + + +def test_get_test_case_flattened_error(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials(),) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.get_test_case( + test_case.GetTestCaseRequest(), name="name_value", + ) + + +@pytest.mark.asyncio +async def test_get_test_case_flattened_async(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_test_case), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = test_case.TestCase() + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(test_case.TestCase()) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.get_test_case(name="name_value",) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0].name == "name_value" + + +@pytest.mark.asyncio +async def test_get_test_case_flattened_error_async(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.get_test_case( + test_case.GetTestCaseRequest(), name="name_value", + ) + + +def test_create_test_case( + transport: str = "grpc", request_type=gcdc_test_case.CreateTestCaseRequest +): + client = TestCasesClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.create_test_case), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = gcdc_test_case.TestCase( + name="name_value", + tags=["tags_value"], + display_name="display_name_value", + notes="notes_value", + ) + + response = client.create_test_case(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_test_case.CreateTestCaseRequest() + + # Establish that the response is the type that we expect. + + assert isinstance(response, gcdc_test_case.TestCase) + + assert response.name == "name_value" + + assert response.tags == ["tags_value"] + + assert response.display_name == "display_name_value" + + assert response.notes == "notes_value" + + +def test_create_test_case_from_dict(): + test_create_test_case(request_type=dict) + + +def test_create_test_case_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 = TestCasesClient( + 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_test_case), "__call__") as call: + client.create_test_case() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_test_case.CreateTestCaseRequest() + + +@pytest.mark.asyncio +async def test_create_test_case_async( + transport: str = "grpc_asyncio", request_type=gcdc_test_case.CreateTestCaseRequest +): + client = TestCasesAsyncClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.create_test_case), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + gcdc_test_case.TestCase( + name="name_value", + tags=["tags_value"], + display_name="display_name_value", + notes="notes_value", + ) + ) + + response = await client.create_test_case(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_test_case.CreateTestCaseRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_test_case.TestCase) + + assert response.name == "name_value" + + assert response.tags == ["tags_value"] + + assert response.display_name == "display_name_value" + + assert response.notes == "notes_value" + + +@pytest.mark.asyncio +async def test_create_test_case_async_from_dict(): + await test_create_test_case_async(request_type=dict) + + +def test_create_test_case_field_headers(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = gcdc_test_case.CreateTestCaseRequest() + request.parent = "parent/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.create_test_case), "__call__") as call: + call.return_value = gcdc_test_case.TestCase() + + client.create_test_case(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "parent=parent/value",) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_create_test_case_field_headers_async(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = gcdc_test_case.CreateTestCaseRequest() + request.parent = "parent/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.create_test_case), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + gcdc_test_case.TestCase() + ) + + await client.create_test_case(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "parent=parent/value",) in kw["metadata"] + + +def test_create_test_case_flattened(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials(),) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.create_test_case), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = gcdc_test_case.TestCase() + + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.create_test_case( + parent="parent_value", test_case=gcdc_test_case.TestCase(name="name_value"), + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0].parent == "parent_value" + + assert args[0].test_case == gcdc_test_case.TestCase(name="name_value") + + +def test_create_test_case_flattened_error(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials(),) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.create_test_case( + gcdc_test_case.CreateTestCaseRequest(), + parent="parent_value", + test_case=gcdc_test_case.TestCase(name="name_value"), + ) + + +@pytest.mark.asyncio +async def test_create_test_case_flattened_async(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.create_test_case), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = gcdc_test_case.TestCase() + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + gcdc_test_case.TestCase() + ) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.create_test_case( + parent="parent_value", test_case=gcdc_test_case.TestCase(name="name_value"), + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0].parent == "parent_value" + + assert args[0].test_case == gcdc_test_case.TestCase(name="name_value") + + +@pytest.mark.asyncio +async def test_create_test_case_flattened_error_async(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.create_test_case( + gcdc_test_case.CreateTestCaseRequest(), + parent="parent_value", + test_case=gcdc_test_case.TestCase(name="name_value"), + ) + + +def test_update_test_case( + transport: str = "grpc", request_type=gcdc_test_case.UpdateTestCaseRequest +): + client = TestCasesClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.update_test_case), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = gcdc_test_case.TestCase( + name="name_value", + tags=["tags_value"], + display_name="display_name_value", + notes="notes_value", + ) + + response = client.update_test_case(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_test_case.UpdateTestCaseRequest() + + # Establish that the response is the type that we expect. + + assert isinstance(response, gcdc_test_case.TestCase) + + assert response.name == "name_value" + + assert response.tags == ["tags_value"] + + assert response.display_name == "display_name_value" + + assert response.notes == "notes_value" + + +def test_update_test_case_from_dict(): + test_update_test_case(request_type=dict) + + +def test_update_test_case_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 = TestCasesClient( + 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_test_case), "__call__") as call: + client.update_test_case() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_test_case.UpdateTestCaseRequest() + + +@pytest.mark.asyncio +async def test_update_test_case_async( + transport: str = "grpc_asyncio", request_type=gcdc_test_case.UpdateTestCaseRequest +): + client = TestCasesAsyncClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.update_test_case), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + gcdc_test_case.TestCase( + name="name_value", + tags=["tags_value"], + display_name="display_name_value", + notes="notes_value", + ) + ) + + response = await client.update_test_case(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_test_case.UpdateTestCaseRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_test_case.TestCase) + + assert response.name == "name_value" + + assert response.tags == ["tags_value"] + + assert response.display_name == "display_name_value" + + assert response.notes == "notes_value" + + +@pytest.mark.asyncio +async def test_update_test_case_async_from_dict(): + await test_update_test_case_async(request_type=dict) + + +def test_update_test_case_field_headers(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = gcdc_test_case.UpdateTestCaseRequest() + request.test_case.name = "test_case.name/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.update_test_case), "__call__") as call: + call.return_value = gcdc_test_case.TestCase() + + client.update_test_case(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "test_case.name=test_case.name/value",) in kw[ + "metadata" + ] + + +@pytest.mark.asyncio +async def test_update_test_case_field_headers_async(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = gcdc_test_case.UpdateTestCaseRequest() + request.test_case.name = "test_case.name/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.update_test_case), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + gcdc_test_case.TestCase() + ) + + await client.update_test_case(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "test_case.name=test_case.name/value",) in kw[ + "metadata" + ] + + +def test_update_test_case_flattened(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials(),) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.update_test_case), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = gcdc_test_case.TestCase() + + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.update_test_case( + test_case=gcdc_test_case.TestCase(name="name_value"), + update_mask=field_mask.FieldMask(paths=["paths_value"]), + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0].test_case == gcdc_test_case.TestCase(name="name_value") + + assert args[0].update_mask == field_mask.FieldMask(paths=["paths_value"]) + + +def test_update_test_case_flattened_error(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials(),) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.update_test_case( + gcdc_test_case.UpdateTestCaseRequest(), + test_case=gcdc_test_case.TestCase(name="name_value"), + update_mask=field_mask.FieldMask(paths=["paths_value"]), + ) + + +@pytest.mark.asyncio +async def test_update_test_case_flattened_async(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.update_test_case), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = gcdc_test_case.TestCase() + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + gcdc_test_case.TestCase() + ) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.update_test_case( + test_case=gcdc_test_case.TestCase(name="name_value"), + update_mask=field_mask.FieldMask(paths=["paths_value"]), + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0].test_case == gcdc_test_case.TestCase(name="name_value") + + assert args[0].update_mask == field_mask.FieldMask(paths=["paths_value"]) + + +@pytest.mark.asyncio +async def test_update_test_case_flattened_error_async(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.update_test_case( + gcdc_test_case.UpdateTestCaseRequest(), + test_case=gcdc_test_case.TestCase(name="name_value"), + update_mask=field_mask.FieldMask(paths=["paths_value"]), + ) + + +def test_run_test_case( + transport: str = "grpc", request_type=test_case.RunTestCaseRequest +): + client = TestCasesClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.run_test_case), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation(name="operations/spam") + + response = client.run_test_case(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.RunTestCaseRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, future.Future) + + +def test_run_test_case_from_dict(): + test_run_test_case(request_type=dict) + + +def test_run_test_case_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 = TestCasesClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.run_test_case), "__call__") as call: + client.run_test_case() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.RunTestCaseRequest() + + +@pytest.mark.asyncio +async def test_run_test_case_async( + transport: str = "grpc_asyncio", request_type=test_case.RunTestCaseRequest +): + client = TestCasesAsyncClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.run_test_case), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation(name="operations/spam") + ) + + response = await client.run_test_case(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.RunTestCaseRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, future.Future) + + +@pytest.mark.asyncio +async def test_run_test_case_async_from_dict(): + await test_run_test_case_async(request_type=dict) + + +def test_run_test_case_field_headers(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = test_case.RunTestCaseRequest() + request.name = "name/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.run_test_case), "__call__") as call: + call.return_value = operations_pb2.Operation(name="operations/op") + + client.run_test_case(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "name=name/value",) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_run_test_case_field_headers_async(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = test_case.RunTestCaseRequest() + request.name = "name/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.run_test_case), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation(name="operations/op") + ) + + await client.run_test_case(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "name=name/value",) in kw["metadata"] + + +def test_batch_run_test_cases( + transport: str = "grpc", request_type=test_case.BatchRunTestCasesRequest +): + client = TestCasesClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.batch_run_test_cases), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation(name="operations/spam") + + response = client.batch_run_test_cases(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.BatchRunTestCasesRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, future.Future) + + +def test_batch_run_test_cases_from_dict(): + test_batch_run_test_cases(request_type=dict) + + +def test_batch_run_test_cases_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 = TestCasesClient( + 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_run_test_cases), "__call__" + ) as call: + client.batch_run_test_cases() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.BatchRunTestCasesRequest() + + +@pytest.mark.asyncio +async def test_batch_run_test_cases_async( + transport: str = "grpc_asyncio", request_type=test_case.BatchRunTestCasesRequest +): + client = TestCasesAsyncClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.batch_run_test_cases), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation(name="operations/spam") + ) + + response = await client.batch_run_test_cases(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.BatchRunTestCasesRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, future.Future) + + +@pytest.mark.asyncio +async def test_batch_run_test_cases_async_from_dict(): + await test_batch_run_test_cases_async(request_type=dict) + + +def test_batch_run_test_cases_field_headers(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = test_case.BatchRunTestCasesRequest() + request.parent = "parent/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.batch_run_test_cases), "__call__" + ) as call: + call.return_value = operations_pb2.Operation(name="operations/op") + + client.batch_run_test_cases(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "parent=parent/value",) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_batch_run_test_cases_field_headers_async(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = test_case.BatchRunTestCasesRequest() + request.parent = "parent/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.batch_run_test_cases), "__call__" + ) as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation(name="operations/op") + ) + + await client.batch_run_test_cases(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "parent=parent/value",) in kw["metadata"] + + +def test_calculate_coverage( + transport: str = "grpc", request_type=test_case.CalculateCoverageRequest +): + client = TestCasesClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.calculate_coverage), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = test_case.CalculateCoverageResponse( + agent="agent_value", + intent_coverage=test_case.IntentCoverage( + intents=[test_case.IntentCoverage.Intent(intent="intent_value")] + ), + ) + + response = client.calculate_coverage(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.CalculateCoverageRequest() + + # Establish that the response is the type that we expect. + + assert isinstance(response, test_case.CalculateCoverageResponse) + + assert response.agent == "agent_value" + + +def test_calculate_coverage_from_dict(): + test_calculate_coverage(request_type=dict) + + +def test_calculate_coverage_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 = TestCasesClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.calculate_coverage), "__call__" + ) as call: + client.calculate_coverage() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.CalculateCoverageRequest() + + +@pytest.mark.asyncio +async def test_calculate_coverage_async( + transport: str = "grpc_asyncio", request_type=test_case.CalculateCoverageRequest +): + client = TestCasesAsyncClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.calculate_coverage), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + test_case.CalculateCoverageResponse(agent="agent_value",) + ) + + response = await client.calculate_coverage(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.CalculateCoverageRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, test_case.CalculateCoverageResponse) + + assert response.agent == "agent_value" + + +@pytest.mark.asyncio +async def test_calculate_coverage_async_from_dict(): + await test_calculate_coverage_async(request_type=dict) + + +def test_calculate_coverage_field_headers(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = test_case.CalculateCoverageRequest() + request.agent = "agent/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.calculate_coverage), "__call__" + ) as call: + call.return_value = test_case.CalculateCoverageResponse() + + client.calculate_coverage(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "agent=agent/value",) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_calculate_coverage_field_headers_async(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = test_case.CalculateCoverageRequest() + request.agent = "agent/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.calculate_coverage), "__call__" + ) as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + test_case.CalculateCoverageResponse() + ) + + await client.calculate_coverage(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "agent=agent/value",) in kw["metadata"] + + +def test_import_test_cases( + transport: str = "grpc", request_type=test_case.ImportTestCasesRequest +): + client = TestCasesClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.import_test_cases), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation(name="operations/spam") + + response = client.import_test_cases(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.ImportTestCasesRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, future.Future) + + +def test_import_test_cases_from_dict(): + test_import_test_cases(request_type=dict) + + +def test_import_test_cases_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 = TestCasesClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.import_test_cases), "__call__" + ) as call: + client.import_test_cases() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.ImportTestCasesRequest() + + +@pytest.mark.asyncio +async def test_import_test_cases_async( + transport: str = "grpc_asyncio", request_type=test_case.ImportTestCasesRequest +): + client = TestCasesAsyncClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.import_test_cases), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation(name="operations/spam") + ) + + response = await client.import_test_cases(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.ImportTestCasesRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, future.Future) + + +@pytest.mark.asyncio +async def test_import_test_cases_async_from_dict(): + await test_import_test_cases_async(request_type=dict) + + +def test_import_test_cases_field_headers(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = test_case.ImportTestCasesRequest() + request.parent = "parent/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.import_test_cases), "__call__" + ) as call: + call.return_value = operations_pb2.Operation(name="operations/op") + + client.import_test_cases(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "parent=parent/value",) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_import_test_cases_field_headers_async(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = test_case.ImportTestCasesRequest() + request.parent = "parent/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.import_test_cases), "__call__" + ) as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation(name="operations/op") + ) + + await client.import_test_cases(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "parent=parent/value",) in kw["metadata"] + + +def test_export_test_cases( + transport: str = "grpc", request_type=test_case.ExportTestCasesRequest +): + client = TestCasesClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.export_test_cases), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation(name="operations/spam") + + response = client.export_test_cases(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.ExportTestCasesRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, future.Future) + + +def test_export_test_cases_from_dict(): + test_export_test_cases(request_type=dict) + + +def test_export_test_cases_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 = TestCasesClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.export_test_cases), "__call__" + ) as call: + client.export_test_cases() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.ExportTestCasesRequest() + + +@pytest.mark.asyncio +async def test_export_test_cases_async( + transport: str = "grpc_asyncio", request_type=test_case.ExportTestCasesRequest +): + client = TestCasesAsyncClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.export_test_cases), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation(name="operations/spam") + ) + + response = await client.export_test_cases(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.ExportTestCasesRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, future.Future) + + +@pytest.mark.asyncio +async def test_export_test_cases_async_from_dict(): + await test_export_test_cases_async(request_type=dict) + + +def test_export_test_cases_field_headers(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = test_case.ExportTestCasesRequest() + request.parent = "parent/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.export_test_cases), "__call__" + ) as call: + call.return_value = operations_pb2.Operation(name="operations/op") + + client.export_test_cases(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "parent=parent/value",) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_export_test_cases_field_headers_async(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = test_case.ExportTestCasesRequest() + request.parent = "parent/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.export_test_cases), "__call__" + ) as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation(name="operations/op") + ) + + await client.export_test_cases(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "parent=parent/value",) in kw["metadata"] + + +def test_list_test_case_results( + transport: str = "grpc", request_type=test_case.ListTestCaseResultsRequest +): + client = TestCasesClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_test_case_results), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = test_case.ListTestCaseResultsResponse( + next_page_token="next_page_token_value", + ) + + response = client.list_test_case_results(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.ListTestCaseResultsRequest() + + # Establish that the response is the type that we expect. + + assert isinstance(response, pagers.ListTestCaseResultsPager) + + assert response.next_page_token == "next_page_token_value" + + +def test_list_test_case_results_from_dict(): + test_list_test_case_results(request_type=dict) + + +def test_list_test_case_results_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 = TestCasesClient( + 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_test_case_results), "__call__" + ) as call: + client.list_test_case_results() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.ListTestCaseResultsRequest() + + +@pytest.mark.asyncio +async def test_list_test_case_results_async( + transport: str = "grpc_asyncio", request_type=test_case.ListTestCaseResultsRequest +): + client = TestCasesAsyncClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_test_case_results), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + test_case.ListTestCaseResultsResponse( + next_page_token="next_page_token_value", + ) + ) + + response = await client.list_test_case_results(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.ListTestCaseResultsRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListTestCaseResultsAsyncPager) + + assert response.next_page_token == "next_page_token_value" + + +@pytest.mark.asyncio +async def test_list_test_case_results_async_from_dict(): + await test_list_test_case_results_async(request_type=dict) + + +def test_list_test_case_results_field_headers(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = test_case.ListTestCaseResultsRequest() + request.parent = "parent/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_test_case_results), "__call__" + ) as call: + call.return_value = test_case.ListTestCaseResultsResponse() + + client.list_test_case_results(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "parent=parent/value",) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_list_test_case_results_field_headers_async(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = test_case.ListTestCaseResultsRequest() + request.parent = "parent/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_test_case_results), "__call__" + ) as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + test_case.ListTestCaseResultsResponse() + ) + + await client.list_test_case_results(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "parent=parent/value",) in kw["metadata"] + + +def test_list_test_case_results_flattened(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials(),) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_test_case_results), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = test_case.ListTestCaseResultsResponse() + + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.list_test_case_results(parent="parent_value",) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0].parent == "parent_value" + + +def test_list_test_case_results_flattened_error(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials(),) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_test_case_results( + test_case.ListTestCaseResultsRequest(), parent="parent_value", + ) + + +@pytest.mark.asyncio +async def test_list_test_case_results_flattened_async(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_test_case_results), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = test_case.ListTestCaseResultsResponse() + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + test_case.ListTestCaseResultsResponse() + ) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.list_test_case_results(parent="parent_value",) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0].parent == "parent_value" + + +@pytest.mark.asyncio +async def test_list_test_case_results_flattened_error_async(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.list_test_case_results( + test_case.ListTestCaseResultsRequest(), parent="parent_value", + ) + + +def test_list_test_case_results_pager(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials,) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_test_case_results), "__call__" + ) as call: + # Set the response to a series of pages. + call.side_effect = ( + test_case.ListTestCaseResultsResponse( + test_case_results=[ + test_case.TestCaseResult(), + test_case.TestCaseResult(), + test_case.TestCaseResult(), + ], + next_page_token="abc", + ), + test_case.ListTestCaseResultsResponse( + test_case_results=[], next_page_token="def", + ), + test_case.ListTestCaseResultsResponse( + test_case_results=[test_case.TestCaseResult(),], next_page_token="ghi", + ), + test_case.ListTestCaseResultsResponse( + test_case_results=[ + test_case.TestCaseResult(), + test_case.TestCaseResult(), + ], + ), + RuntimeError, + ) + + metadata = () + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", ""),)), + ) + pager = client.list_test_case_results(request={}) + + assert pager._metadata == metadata + + results = [i for i in pager] + assert len(results) == 6 + assert all(isinstance(i, test_case.TestCaseResult) for i in results) + + +def test_list_test_case_results_pages(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials,) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_test_case_results), "__call__" + ) as call: + # Set the response to a series of pages. + call.side_effect = ( + test_case.ListTestCaseResultsResponse( + test_case_results=[ + test_case.TestCaseResult(), + test_case.TestCaseResult(), + test_case.TestCaseResult(), + ], + next_page_token="abc", + ), + test_case.ListTestCaseResultsResponse( + test_case_results=[], next_page_token="def", + ), + test_case.ListTestCaseResultsResponse( + test_case_results=[test_case.TestCaseResult(),], next_page_token="ghi", + ), + test_case.ListTestCaseResultsResponse( + test_case_results=[ + test_case.TestCaseResult(), + test_case.TestCaseResult(), + ], + ), + RuntimeError, + ) + pages = list(client.list_test_case_results(request={}).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + +@pytest.mark.asyncio +async def test_list_test_case_results_async_pager(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials,) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_test_case_results), + "__call__", + new_callable=mock.AsyncMock, + ) as call: + # Set the response to a series of pages. + call.side_effect = ( + test_case.ListTestCaseResultsResponse( + test_case_results=[ + test_case.TestCaseResult(), + test_case.TestCaseResult(), + test_case.TestCaseResult(), + ], + next_page_token="abc", + ), + test_case.ListTestCaseResultsResponse( + test_case_results=[], next_page_token="def", + ), + test_case.ListTestCaseResultsResponse( + test_case_results=[test_case.TestCaseResult(),], next_page_token="ghi", + ), + test_case.ListTestCaseResultsResponse( + test_case_results=[ + test_case.TestCaseResult(), + test_case.TestCaseResult(), + ], + ), + RuntimeError, + ) + async_pager = await client.list_test_case_results(request={},) + assert async_pager.next_page_token == "abc" + responses = [] + async for response in async_pager: + responses.append(response) + + assert len(responses) == 6 + assert all(isinstance(i, test_case.TestCaseResult) for i in responses) + + +@pytest.mark.asyncio +async def test_list_test_case_results_async_pages(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials,) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_test_case_results), + "__call__", + new_callable=mock.AsyncMock, + ) as call: + # Set the response to a series of pages. + call.side_effect = ( + test_case.ListTestCaseResultsResponse( + test_case_results=[ + test_case.TestCaseResult(), + test_case.TestCaseResult(), + test_case.TestCaseResult(), + ], + next_page_token="abc", + ), + test_case.ListTestCaseResultsResponse( + test_case_results=[], next_page_token="def", + ), + test_case.ListTestCaseResultsResponse( + test_case_results=[test_case.TestCaseResult(),], next_page_token="ghi", + ), + test_case.ListTestCaseResultsResponse( + test_case_results=[ + test_case.TestCaseResult(), + test_case.TestCaseResult(), + ], + ), + RuntimeError, + ) + pages = [] + async for page_ in (await client.list_test_case_results(request={})).pages: + pages.append(page_) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.TestCasesGrpcTransport( + credentials=credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = TestCasesClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.TestCasesGrpcTransport( + credentials=credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = TestCasesClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.TestCasesGrpcTransport( + credentials=credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = TestCasesClient( + client_options={"scopes": ["1", "2"]}, transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.TestCasesGrpcTransport( + credentials=credentials.AnonymousCredentials(), + ) + client = TestCasesClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.TestCasesGrpcTransport( + credentials=credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.TestCasesGrpcAsyncIOTransport( + credentials=credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [transports.TestCasesGrpcTransport, transports.TestCasesGrpcAsyncIOTransport,], +) +def test_transport_adc(transport_class): + # Test default credentials are used if not provided. + with mock.patch.object(auth, "default") as adc: + adc.return_value = (credentials.AnonymousCredentials(), None) + transport_class() + adc.assert_called_once() + + +def test_transport_grpc_default(): + # A client should use the gRPC transport by default. + client = TestCasesClient(credentials=credentials.AnonymousCredentials(),) + assert isinstance(client.transport, transports.TestCasesGrpcTransport,) + + +def test_test_cases_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(exceptions.DuplicateCredentialArgs): + transport = transports.TestCasesTransport( + credentials=credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_test_cases_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflowcx_v3.services.test_cases.transports.TestCasesTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.TestCasesTransport( + credentials=credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + "list_test_cases", + "batch_delete_test_cases", + "get_test_case", + "create_test_case", + "update_test_case", + "run_test_case", + "batch_run_test_cases", + "calculate_coverage", + "import_test_cases", + "export_test_cases", + "list_test_case_results", + ) + for method in methods: + with pytest.raises(NotImplementedError): + getattr(transport, method)(request=object()) + + # Additionally, the LRO client (a property) should + # also raise NotImplementedError + with pytest.raises(NotImplementedError): + transport.operations_client + + +def test_test_cases_base_transport_with_credentials_file(): + # Instantiate the base transport with a credentials file + with mock.patch.object( + auth, "load_credentials_from_file" + ) as load_creds, mock.patch( + "google.cloud.dialogflowcx_v3.services.test_cases.transports.TestCasesTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + load_creds.return_value = (credentials.AnonymousCredentials(), None) + transport = transports.TestCasesTransport( + credentials_file="credentials.json", quota_project_id="octopus", + ) + load_creds.assert_called_once_with( + "credentials.json", + scopes=( + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/dialogflow", + ), + quota_project_id="octopus", + ) + + +def test_test_cases_base_transport_with_adc(): + # Test the default credentials are used if credentials and credentials_file are None. + with mock.patch.object(auth, "default") as adc, mock.patch( + "google.cloud.dialogflowcx_v3.services.test_cases.transports.TestCasesTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + adc.return_value = (credentials.AnonymousCredentials(), None) + transport = transports.TestCasesTransport() + adc.assert_called_once() + + +def test_test_cases_auth_adc(): + # If no credentials are provided, we should use ADC credentials. + with mock.patch.object(auth, "default") as adc: + adc.return_value = (credentials.AnonymousCredentials(), None) + TestCasesClient() + adc.assert_called_once_with( + scopes=( + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/dialogflow", + ), + quota_project_id=None, + ) + + +def test_test_cases_transport_auth_adc(): + # If credentials and host are not provided, the transport class should use + # ADC credentials. + with mock.patch.object(auth, "default") as adc: + adc.return_value = (credentials.AnonymousCredentials(), None) + transports.TestCasesGrpcTransport( + host="squid.clam.whelk", quota_project_id="octopus" + ) + adc.assert_called_once_with( + scopes=( + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/dialogflow", + ), + quota_project_id="octopus", + ) + + +@pytest.mark.parametrize( + "transport_class", + [transports.TestCasesGrpcTransport, transports.TestCasesGrpcAsyncIOTransport], +) +def test_test_cases_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/dialogflow", + ), + 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_test_cases_host_no_port(): + client = TestCasesClient( + credentials=credentials.AnonymousCredentials(), + client_options=client_options.ClientOptions( + api_endpoint="dialogflow.googleapis.com" + ), + ) + assert client.transport._host == "dialogflow.googleapis.com:443" + + +def test_test_cases_host_with_port(): + client = TestCasesClient( + credentials=credentials.AnonymousCredentials(), + client_options=client_options.ClientOptions( + api_endpoint="dialogflow.googleapis.com:8000" + ), + ) + assert client.transport._host == "dialogflow.googleapis.com:8000" + + +def test_test_cases_grpc_transport_channel(): + channel = grpc.secure_channel("http://localhost/", grpc.local_channel_credentials()) + + # Check that channel is used if provided. + transport = transports.TestCasesGrpcTransport( + host="squid.clam.whelk", channel=channel, + ) + assert transport.grpc_channel == channel + assert transport._host == "squid.clam.whelk:443" + assert transport._ssl_channel_credentials == None + + +def test_test_cases_grpc_asyncio_transport_channel(): + channel = aio.secure_channel("http://localhost/", grpc.local_channel_credentials()) + + # Check that channel is used if provided. + transport = transports.TestCasesGrpcAsyncIOTransport( + host="squid.clam.whelk", channel=channel, + ) + assert transport.grpc_channel == channel + assert transport._host == "squid.clam.whelk:443" + assert transport._ssl_channel_credentials == None + + +# Remove this test when deprecated arguments (api_mtls_endpoint, client_cert_source) are +# removed from grpc/grpc_asyncio transport constructor. +@pytest.mark.parametrize( + "transport_class", + [transports.TestCasesGrpcTransport, transports.TestCasesGrpcAsyncIOTransport], +) +def test_test_cases_transport_channel_mtls_with_client_cert_source(transport_class): + with mock.patch( + "grpc.ssl_channel_credentials", autospec=True + ) as grpc_ssl_channel_cred: + with mock.patch.object( + transport_class, "create_channel" + ) as grpc_create_channel: + mock_ssl_cred = mock.Mock() + grpc_ssl_channel_cred.return_value = mock_ssl_cred + + mock_grpc_channel = mock.Mock() + grpc_create_channel.return_value = mock_grpc_channel + + cred = credentials.AnonymousCredentials() + with pytest.warns(DeprecationWarning): + with mock.patch.object(auth, "default") as adc: + adc.return_value = (cred, None) + transport = transport_class( + host="squid.clam.whelk", + api_mtls_endpoint="mtls.squid.clam.whelk", + client_cert_source=client_cert_source_callback, + ) + adc.assert_called_once() + + grpc_ssl_channel_cred.assert_called_once_with( + certificate_chain=b"cert bytes", private_key=b"key bytes" + ) + grpc_create_channel.assert_called_once_with( + "mtls.squid.clam.whelk:443", + credentials=cred, + credentials_file=None, + scopes=( + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/dialogflow", + ), + ssl_credentials=mock_ssl_cred, + quota_project_id=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + assert transport.grpc_channel == mock_grpc_channel + assert transport._ssl_channel_credentials == mock_ssl_cred + + +# Remove this test when deprecated arguments (api_mtls_endpoint, client_cert_source) are +# removed from grpc/grpc_asyncio transport constructor. +@pytest.mark.parametrize( + "transport_class", + [transports.TestCasesGrpcTransport, transports.TestCasesGrpcAsyncIOTransport], +) +def test_test_cases_transport_channel_mtls_with_adc(transport_class): + mock_ssl_cred = mock.Mock() + with mock.patch.multiple( + "google.auth.transport.grpc.SslCredentials", + __init__=mock.Mock(return_value=None), + ssl_credentials=mock.PropertyMock(return_value=mock_ssl_cred), + ): + with mock.patch.object( + transport_class, "create_channel" + ) as grpc_create_channel: + mock_grpc_channel = mock.Mock() + grpc_create_channel.return_value = mock_grpc_channel + mock_cred = mock.Mock() + + with pytest.warns(DeprecationWarning): + transport = transport_class( + host="squid.clam.whelk", + credentials=mock_cred, + api_mtls_endpoint="mtls.squid.clam.whelk", + client_cert_source=None, + ) + + grpc_create_channel.assert_called_once_with( + "mtls.squid.clam.whelk:443", + credentials=mock_cred, + credentials_file=None, + scopes=( + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/dialogflow", + ), + ssl_credentials=mock_ssl_cred, + quota_project_id=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + assert transport.grpc_channel == mock_grpc_channel + + +def test_test_cases_grpc_lro_client(): + client = TestCasesClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + transport = client.transport + + # Ensure that we have a api-core operations client. + assert isinstance(transport.operations_client, operations_v1.OperationsClient,) + + # Ensure that subsequent calls to the property send the exact same object. + assert transport.operations_client is transport.operations_client + + +def test_test_cases_grpc_lro_async_client(): + client = TestCasesAsyncClient( + credentials=credentials.AnonymousCredentials(), transport="grpc_asyncio", + ) + transport = client.transport + + # Ensure that we have a api-core operations client. + assert isinstance(transport.operations_client, operations_v1.OperationsAsyncClient,) + + # Ensure that subsequent calls to the property send the exact same object. + assert transport.operations_client is transport.operations_client + + +def test_agent_path(): + project = "squid" + location = "clam" + agent = "whelk" + + expected = "projects/{project}/locations/{location}/agents/{agent}".format( + project=project, location=location, agent=agent, + ) + actual = TestCasesClient.agent_path(project, location, agent) + assert expected == actual + + +def test_parse_agent_path(): + expected = { + "project": "octopus", + "location": "oyster", + "agent": "nudibranch", + } + path = TestCasesClient.agent_path(**expected) + + # Check that the path construction is reversible. + actual = TestCasesClient.parse_agent_path(path) + assert expected == actual + + +def test_entity_type_path(): + project = "cuttlefish" + location = "mussel" + agent = "winkle" + entity_type = "nautilus" + + expected = "projects/{project}/locations/{location}/agents/{agent}/entityTypes/{entity_type}".format( + project=project, location=location, agent=agent, entity_type=entity_type, + ) + actual = TestCasesClient.entity_type_path(project, location, agent, entity_type) + assert expected == actual + + +def test_parse_entity_type_path(): + expected = { + "project": "scallop", + "location": "abalone", + "agent": "squid", + "entity_type": "clam", + } + path = TestCasesClient.entity_type_path(**expected) + + # Check that the path construction is reversible. + actual = TestCasesClient.parse_entity_type_path(path) + assert expected == actual + + +def test_environment_path(): + project = "whelk" + location = "octopus" + agent = "oyster" + environment = "nudibranch" + + expected = "projects/{project}/locations/{location}/agents/{agent}/environments/{environment}".format( + project=project, location=location, agent=agent, environment=environment, + ) + actual = TestCasesClient.environment_path(project, location, agent, environment) + assert expected == actual + + +def test_parse_environment_path(): + expected = { + "project": "cuttlefish", + "location": "mussel", + "agent": "winkle", + "environment": "nautilus", + } + path = TestCasesClient.environment_path(**expected) + + # Check that the path construction is reversible. + actual = TestCasesClient.parse_environment_path(path) + assert expected == actual + + +def test_flow_path(): + project = "scallop" + location = "abalone" + agent = "squid" + flow = "clam" + + expected = "projects/{project}/locations/{location}/agents/{agent}/flows/{flow}".format( + project=project, location=location, agent=agent, flow=flow, + ) + actual = TestCasesClient.flow_path(project, location, agent, flow) + assert expected == actual + + +def test_parse_flow_path(): + expected = { + "project": "whelk", + "location": "octopus", + "agent": "oyster", + "flow": "nudibranch", + } + path = TestCasesClient.flow_path(**expected) + + # Check that the path construction is reversible. + actual = TestCasesClient.parse_flow_path(path) + assert expected == actual + + +def test_intent_path(): + project = "cuttlefish" + location = "mussel" + agent = "winkle" + intent = "nautilus" + + expected = "projects/{project}/locations/{location}/agents/{agent}/intents/{intent}".format( + project=project, location=location, agent=agent, intent=intent, + ) + actual = TestCasesClient.intent_path(project, location, agent, intent) + assert expected == actual + + +def test_parse_intent_path(): + expected = { + "project": "scallop", + "location": "abalone", + "agent": "squid", + "intent": "clam", + } + path = TestCasesClient.intent_path(**expected) + + # Check that the path construction is reversible. + actual = TestCasesClient.parse_intent_path(path) + assert expected == actual + + +def test_page_path(): + project = "whelk" + location = "octopus" + agent = "oyster" + flow = "nudibranch" + page = "cuttlefish" + + expected = "projects/{project}/locations/{location}/agents/{agent}/flows/{flow}/pages/{page}".format( + project=project, location=location, agent=agent, flow=flow, page=page, + ) + actual = TestCasesClient.page_path(project, location, agent, flow, page) + assert expected == actual + + +def test_parse_page_path(): + expected = { + "project": "mussel", + "location": "winkle", + "agent": "nautilus", + "flow": "scallop", + "page": "abalone", + } + path = TestCasesClient.page_path(**expected) + + # Check that the path construction is reversible. + actual = TestCasesClient.parse_page_path(path) + assert expected == actual + + +def test_test_case_path(): + project = "squid" + location = "clam" + agent = "whelk" + test_case = "octopus" + + expected = "projects/{project}/locations/{location}/agents/{agent}/testCases/{test_case}".format( + project=project, location=location, agent=agent, test_case=test_case, + ) + actual = TestCasesClient.test_case_path(project, location, agent, test_case) + assert expected == actual + + +def test_parse_test_case_path(): + expected = { + "project": "oyster", + "location": "nudibranch", + "agent": "cuttlefish", + "test_case": "mussel", + } + path = TestCasesClient.test_case_path(**expected) + + # Check that the path construction is reversible. + actual = TestCasesClient.parse_test_case_path(path) + assert expected == actual + + +def test_test_case_result_path(): + project = "winkle" + location = "nautilus" + agent = "scallop" + test_case = "abalone" + result = "squid" + + expected = "projects/{project}/locations/{location}/agents/{agent}/testCases/{test_case}/results/{result}".format( + project=project, + location=location, + agent=agent, + test_case=test_case, + result=result, + ) + actual = TestCasesClient.test_case_result_path( + project, location, agent, test_case, result + ) + assert expected == actual + + +def test_parse_test_case_result_path(): + expected = { + "project": "clam", + "location": "whelk", + "agent": "octopus", + "test_case": "oyster", + "result": "nudibranch", + } + path = TestCasesClient.test_case_result_path(**expected) + + # Check that the path construction is reversible. + actual = TestCasesClient.parse_test_case_result_path(path) + assert expected == actual + + +def test_transition_route_group_path(): + project = "cuttlefish" + location = "mussel" + agent = "winkle" + flow = "nautilus" + transition_route_group = "scallop" + + expected = "projects/{project}/locations/{location}/agents/{agent}/flows/{flow}/transitionRouteGroups/{transition_route_group}".format( + project=project, + location=location, + agent=agent, + flow=flow, + transition_route_group=transition_route_group, + ) + actual = TestCasesClient.transition_route_group_path( + project, location, agent, flow, transition_route_group + ) + assert expected == actual + + +def test_parse_transition_route_group_path(): + expected = { + "project": "abalone", + "location": "squid", + "agent": "clam", + "flow": "whelk", + "transition_route_group": "octopus", + } + path = TestCasesClient.transition_route_group_path(**expected) + + # Check that the path construction is reversible. + actual = TestCasesClient.parse_transition_route_group_path(path) + assert expected == actual + + +def test_webhook_path(): + project = "oyster" + location = "nudibranch" + agent = "cuttlefish" + webhook = "mussel" + + expected = "projects/{project}/locations/{location}/agents/{agent}/webhooks/{webhook}".format( + project=project, location=location, agent=agent, webhook=webhook, + ) + actual = TestCasesClient.webhook_path(project, location, agent, webhook) + assert expected == actual + + +def test_parse_webhook_path(): + expected = { + "project": "winkle", + "location": "nautilus", + "agent": "scallop", + "webhook": "abalone", + } + path = TestCasesClient.webhook_path(**expected) + + # Check that the path construction is reversible. + actual = TestCasesClient.parse_webhook_path(path) + assert expected == actual + + +def test_common_billing_account_path(): + billing_account = "squid" + + expected = "billingAccounts/{billing_account}".format( + billing_account=billing_account, + ) + actual = TestCasesClient.common_billing_account_path(billing_account) + assert expected == actual + + +def test_parse_common_billing_account_path(): + expected = { + "billing_account": "clam", + } + path = TestCasesClient.common_billing_account_path(**expected) + + # Check that the path construction is reversible. + actual = TestCasesClient.parse_common_billing_account_path(path) + assert expected == actual + + +def test_common_folder_path(): + folder = "whelk" + + expected = "folders/{folder}".format(folder=folder,) + actual = TestCasesClient.common_folder_path(folder) + assert expected == actual + + +def test_parse_common_folder_path(): + expected = { + "folder": "octopus", + } + path = TestCasesClient.common_folder_path(**expected) + + # Check that the path construction is reversible. + actual = TestCasesClient.parse_common_folder_path(path) + assert expected == actual + + +def test_common_organization_path(): + organization = "oyster" + + expected = "organizations/{organization}".format(organization=organization,) + actual = TestCasesClient.common_organization_path(organization) + assert expected == actual + + +def test_parse_common_organization_path(): + expected = { + "organization": "nudibranch", + } + path = TestCasesClient.common_organization_path(**expected) + + # Check that the path construction is reversible. + actual = TestCasesClient.parse_common_organization_path(path) + assert expected == actual + + +def test_common_project_path(): + project = "cuttlefish" + + expected = "projects/{project}".format(project=project,) + actual = TestCasesClient.common_project_path(project) + assert expected == actual + + +def test_parse_common_project_path(): + expected = { + "project": "mussel", + } + path = TestCasesClient.common_project_path(**expected) + + # Check that the path construction is reversible. + actual = TestCasesClient.parse_common_project_path(path) + assert expected == actual + + +def test_common_location_path(): + project = "winkle" + location = "nautilus" + + expected = "projects/{project}/locations/{location}".format( + project=project, location=location, + ) + actual = TestCasesClient.common_location_path(project, location) + assert expected == actual + + +def test_parse_common_location_path(): + expected = { + "project": "scallop", + "location": "abalone", + } + path = TestCasesClient.common_location_path(**expected) + + # Check that the path construction is reversible. + actual = TestCasesClient.parse_common_location_path(path) + assert expected == actual + + +def test_client_withDEFAULT_CLIENT_INFO(): + client_info = gapic_v1.client_info.ClientInfo() + + with mock.patch.object( + transports.TestCasesTransport, "_prep_wrapped_messages" + ) as prep: + client = TestCasesClient( + credentials=credentials.AnonymousCredentials(), client_info=client_info, + ) + prep.assert_called_once_with(client_info) + + with mock.patch.object( + transports.TestCasesTransport, "_prep_wrapped_messages" + ) as prep: + transport_class = TestCasesClient.get_transport_class() + transport = transport_class( + credentials=credentials.AnonymousCredentials(), client_info=client_info, + ) + prep.assert_called_once_with(client_info) diff --git a/tests/unit/gapic/dialogflowcx_v3/test_transition_route_groups.py b/tests/unit/gapic/dialogflowcx_v3/test_transition_route_groups.py index 71459521..a147c3ff 100644 --- a/tests/unit/gapic/dialogflowcx_v3/test_transition_route_groups.py +++ b/tests/unit/gapic/dialogflowcx_v3/test_transition_route_groups.py @@ -98,7 +98,24 @@ def test__get_default_mtls_endpoint(): @pytest.mark.parametrize( - "client_class", [TransitionRouteGroupsClient, TransitionRouteGroupsAsyncClient] + "client_class", [TransitionRouteGroupsClient, TransitionRouteGroupsAsyncClient,] +) +def test_transition_route_groups_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 == "dialogflow.googleapis.com:443" + + +@pytest.mark.parametrize( + "client_class", [TransitionRouteGroupsClient, TransitionRouteGroupsAsyncClient,] ) def test_transition_route_groups_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() @@ -108,16 +125,21 @@ def test_transition_route_groups_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 == "dialogflow.googleapis.com:443" def test_transition_route_groups_client_get_transport_class(): transport = TransitionRouteGroupsClient.get_transport_class() - assert transport == transports.TransitionRouteGroupsGrpcTransport + available_transports = [ + transports.TransitionRouteGroupsGrpcTransport, + ] + assert transport in available_transports transport = TransitionRouteGroupsClient.get_transport_class("grpc") assert transport == transports.TransitionRouteGroupsGrpcTransport @@ -172,7 +194,7 @@ def test_transition_route_groups_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, ) @@ -188,7 +210,7 @@ def test_transition_route_groups_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, ) @@ -204,7 +226,7 @@ def test_transition_route_groups_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, ) @@ -232,7 +254,7 @@ def test_transition_route_groups_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, ) @@ -293,29 +315,25 @@ def test_transition_route_groups_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. @@ -324,66 +342,53 @@ def test_transition_route_groups_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", @@ -413,7 +418,7 @@ def test_transition_route_groups_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, ) @@ -447,7 +452,7 @@ def test_transition_route_groups_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, ) @@ -466,7 +471,7 @@ def test_transition_route_groups_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, ) @@ -512,6 +517,24 @@ def test_list_transition_route_groups_from_dict(): test_list_transition_route_groups(request_type=dict) +def test_list_transition_route_groups_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 = TransitionRouteGroupsClient( + 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_transition_route_groups), "__call__" + ) as call: + client.list_transition_route_groups() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == transition_route_group.ListTransitionRouteGroupsRequest() + + @pytest.mark.asyncio async def test_list_transition_route_groups_async( transport: str = "grpc_asyncio", @@ -926,6 +949,24 @@ def test_get_transition_route_group_from_dict(): test_get_transition_route_group(request_type=dict) +def test_get_transition_route_group_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 = TransitionRouteGroupsClient( + 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_transition_route_group), "__call__" + ) as call: + client.get_transition_route_group() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == transition_route_group.GetTransitionRouteGroupRequest() + + @pytest.mark.asyncio async def test_get_transition_route_group_async( transport: str = "grpc_asyncio", @@ -1153,6 +1194,26 @@ def test_create_transition_route_group_from_dict(): test_create_transition_route_group(request_type=dict) +def test_create_transition_route_group_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 = TransitionRouteGroupsClient( + 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_transition_route_group), "__call__" + ) as call: + client.create_transition_route_group() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert ( + args[0] == gcdc_transition_route_group.CreateTransitionRouteGroupRequest() + ) + + @pytest.mark.asyncio async def test_create_transition_route_group_async( transport: str = "grpc_asyncio", @@ -1412,6 +1473,26 @@ def test_update_transition_route_group_from_dict(): test_update_transition_route_group(request_type=dict) +def test_update_transition_route_group_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 = TransitionRouteGroupsClient( + 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_transition_route_group), "__call__" + ) as call: + client.update_transition_route_group() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert ( + args[0] == gcdc_transition_route_group.UpdateTransitionRouteGroupRequest() + ) + + @pytest.mark.asyncio async def test_update_transition_route_group_async( transport: str = "grpc_asyncio", @@ -1668,6 +1749,24 @@ def test_delete_transition_route_group_from_dict(): test_delete_transition_route_group(request_type=dict) +def test_delete_transition_route_group_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 = TransitionRouteGroupsClient( + 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_transition_route_group), "__call__" + ) as call: + client.delete_transition_route_group() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == transition_route_group.DeleteTransitionRouteGroupRequest() + + @pytest.mark.asyncio async def test_delete_transition_route_group_async( transport: str = "grpc_asyncio", @@ -2015,6 +2114,56 @@ def test_transition_route_groups_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [ + transports.TransitionRouteGroupsGrpcTransport, + transports.TransitionRouteGroupsGrpcAsyncIOTransport, + ], +) +def test_transition_route_groups_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/dialogflow", + ), + 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_transition_route_groups_host_no_port(): client = TransitionRouteGroupsClient( credentials=credentials.AnonymousCredentials(), @@ -2036,7 +2185,7 @@ def test_transition_route_groups_host_with_port(): def test_transition_route_groups_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.TransitionRouteGroupsGrpcTransport( @@ -2048,7 +2197,7 @@ def test_transition_route_groups_grpc_transport_channel(): def test_transition_route_groups_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.TransitionRouteGroupsGrpcAsyncIOTransport( @@ -2059,6 +2208,8 @@ def test_transition_route_groups_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", [ @@ -2073,7 +2224,7 @@ def test_transition_route_groups_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 @@ -2114,6 +2265,8 @@ def test_transition_route_groups_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", [ @@ -2129,7 +2282,7 @@ def test_transition_route_groups_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/dialogflowcx_v3/test_versions.py b/tests/unit/gapic/dialogflowcx_v3/test_versions.py index 75312e56..f0f02f05 100644 --- a/tests/unit/gapic/dialogflowcx_v3/test_versions.py +++ b/tests/unit/gapic/dialogflowcx_v3/test_versions.py @@ -88,7 +88,22 @@ def test__get_default_mtls_endpoint(): assert VersionsClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi -@pytest.mark.parametrize("client_class", [VersionsClient, VersionsAsyncClient]) +@pytest.mark.parametrize("client_class", [VersionsClient, VersionsAsyncClient,]) +def test_versions_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 == "dialogflow.googleapis.com:443" + + +@pytest.mark.parametrize("client_class", [VersionsClient, VersionsAsyncClient,]) def test_versions_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() with mock.patch.object( @@ -97,16 +112,21 @@ def test_versions_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 == "dialogflow.googleapis.com:443" def test_versions_client_get_transport_class(): transport = VersionsClient.get_transport_class() - assert transport == transports.VersionsGrpcTransport + available_transports = [ + transports.VersionsGrpcTransport, + ] + assert transport in available_transports transport = VersionsClient.get_transport_class("grpc") assert transport == transports.VersionsGrpcTransport @@ -149,7 +169,7 @@ def test_versions_client_client_options(client_class, transport_class, transport 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_versions_client_client_options(client_class, transport_class, transport 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_versions_client_client_options(client_class, transport_class, transport 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_versions_client_client_options(client_class, transport_class, transport 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_versions_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_versions_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", @@ -370,7 +373,7 @@ def test_versions_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, ) @@ -396,7 +399,7 @@ def test_versions_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, ) @@ -413,7 +416,7 @@ def test_versions_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, ) @@ -456,6 +459,22 @@ def test_list_versions_from_dict(): test_list_versions(request_type=dict) +def test_list_versions_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 = VersionsClient( + 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_versions), "__call__") as call: + client.list_versions() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == version.ListVersionsRequest() + + @pytest.mark.asyncio async def test_list_versions_async( transport: str = "grpc_asyncio", request_type=version.ListVersionsRequest @@ -778,6 +797,22 @@ def test_get_version_from_dict(): test_get_version(request_type=dict) +def test_get_version_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 = VersionsClient( + 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_version), "__call__") as call: + client.get_version() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == version.GetVersionRequest() + + @pytest.mark.asyncio async def test_get_version_async( transport: str = "grpc_asyncio", request_type=version.GetVersionRequest @@ -973,6 +1008,22 @@ def test_create_version_from_dict(): test_create_version(request_type=dict) +def test_create_version_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 = VersionsClient( + 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_version), "__call__") as call: + client.create_version() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_version.CreateVersionRequest() + + @pytest.mark.asyncio async def test_create_version_async( transport: str = "grpc_asyncio", request_type=gcdc_version.CreateVersionRequest @@ -1185,6 +1236,22 @@ def test_update_version_from_dict(): test_update_version(request_type=dict) +def test_update_version_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 = VersionsClient( + 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_version), "__call__") as call: + client.update_version() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_version.UpdateVersionRequest() + + @pytest.mark.asyncio async def test_update_version_async( transport: str = "grpc_asyncio", request_type=gcdc_version.UpdateVersionRequest @@ -1402,6 +1469,22 @@ def test_delete_version_from_dict(): test_delete_version(request_type=dict) +def test_delete_version_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 = VersionsClient( + 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_version), "__call__") as call: + client.delete_version() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == version.DeleteVersionRequest() + + @pytest.mark.asyncio async def test_delete_version_async( transport: str = "grpc_asyncio", request_type=version.DeleteVersionRequest @@ -1580,6 +1663,22 @@ def test_load_version_from_dict(): test_load_version(request_type=dict) +def test_load_version_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 = VersionsClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.load_version), "__call__") as call: + client.load_version() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == version.LoadVersionRequest() + + @pytest.mark.asyncio async def test_load_version_async( transport: str = "grpc_asyncio", request_type=version.LoadVersionRequest @@ -1790,7 +1889,7 @@ def test_transport_get_channel(): @pytest.mark.parametrize( "transport_class", - [transports.VersionsGrpcTransport, transports.VersionsGrpcAsyncIOTransport], + [transports.VersionsGrpcTransport, transports.VersionsGrpcAsyncIOTransport,], ) def test_transport_adc(transport_class): # Test default credentials are used if not provided. @@ -1909,6 +2008,51 @@ def test_versions_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [transports.VersionsGrpcTransport, transports.VersionsGrpcAsyncIOTransport], +) +def test_versions_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/dialogflow", + ), + 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_versions_host_no_port(): client = VersionsClient( credentials=credentials.AnonymousCredentials(), @@ -1930,7 +2074,7 @@ def test_versions_host_with_port(): def test_versions_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.VersionsGrpcTransport( @@ -1942,7 +2086,7 @@ def test_versions_grpc_transport_channel(): def test_versions_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.VersionsGrpcAsyncIOTransport( @@ -1953,6 +2097,8 @@ def test_versions_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.VersionsGrpcTransport, transports.VersionsGrpcAsyncIOTransport], @@ -1962,7 +2108,7 @@ def test_versions_transport_channel_mtls_with_client_cert_source(transport_class "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 @@ -2003,6 +2149,8 @@ def test_versions_transport_channel_mtls_with_client_cert_source(transport_class 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.VersionsGrpcTransport, transports.VersionsGrpcAsyncIOTransport], @@ -2015,7 +2163,7 @@ def test_versions_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/dialogflowcx_v3/test_webhooks.py b/tests/unit/gapic/dialogflowcx_v3/test_webhooks.py index b93c373b..fcae841e 100644 --- a/tests/unit/gapic/dialogflowcx_v3/test_webhooks.py +++ b/tests/unit/gapic/dialogflowcx_v3/test_webhooks.py @@ -82,7 +82,22 @@ def test__get_default_mtls_endpoint(): assert WebhooksClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi -@pytest.mark.parametrize("client_class", [WebhooksClient, WebhooksAsyncClient]) +@pytest.mark.parametrize("client_class", [WebhooksClient, WebhooksAsyncClient,]) +def test_webhooks_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 == "dialogflow.googleapis.com:443" + + +@pytest.mark.parametrize("client_class", [WebhooksClient, WebhooksAsyncClient,]) def test_webhooks_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() with mock.patch.object( @@ -91,16 +106,21 @@ def test_webhooks_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 == "dialogflow.googleapis.com:443" def test_webhooks_client_get_transport_class(): transport = WebhooksClient.get_transport_class() - assert transport == transports.WebhooksGrpcTransport + available_transports = [ + transports.WebhooksGrpcTransport, + ] + assert transport in available_transports transport = WebhooksClient.get_transport_class("grpc") assert transport == transports.WebhooksGrpcTransport @@ -143,7 +163,7 @@ def test_webhooks_client_client_options(client_class, transport_class, transport 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, ) @@ -159,7 +179,7 @@ def test_webhooks_client_client_options(client_class, transport_class, transport 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, ) @@ -175,7 +195,7 @@ def test_webhooks_client_client_options(client_class, transport_class, transport 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, ) @@ -203,7 +223,7 @@ def test_webhooks_client_client_options(client_class, transport_class, transport 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, ) @@ -252,29 +272,25 @@ def test_webhooks_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. @@ -283,66 +299,53 @@ def test_webhooks_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", @@ -364,7 +367,7 @@ def test_webhooks_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, ) @@ -390,7 +393,7 @@ def test_webhooks_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, ) @@ -407,7 +410,7 @@ def test_webhooks_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, ) @@ -450,6 +453,22 @@ def test_list_webhooks_from_dict(): test_list_webhooks(request_type=dict) +def test_list_webhooks_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 = WebhooksClient( + 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_webhooks), "__call__") as call: + client.list_webhooks() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == webhook.ListWebhooksRequest() + + @pytest.mark.asyncio async def test_list_webhooks_async( transport: str = "grpc_asyncio", request_type=webhook.ListWebhooksRequest @@ -770,6 +789,22 @@ def test_get_webhook_from_dict(): test_get_webhook(request_type=dict) +def test_get_webhook_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 = WebhooksClient( + 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_webhook), "__call__") as call: + client.get_webhook() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == webhook.GetWebhookRequest() + + @pytest.mark.asyncio async def test_get_webhook_async( transport: str = "grpc_asyncio", request_type=webhook.GetWebhookRequest @@ -972,6 +1007,22 @@ def test_create_webhook_from_dict(): test_create_webhook(request_type=dict) +def test_create_webhook_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 = WebhooksClient( + 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_webhook), "__call__") as call: + client.create_webhook() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_webhook.CreateWebhookRequest() + + @pytest.mark.asyncio async def test_create_webhook_async( transport: str = "grpc_asyncio", request_type=gcdc_webhook.CreateWebhookRequest @@ -1190,6 +1241,22 @@ def test_update_webhook_from_dict(): test_update_webhook(request_type=dict) +def test_update_webhook_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 = WebhooksClient( + 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_webhook), "__call__") as call: + client.update_webhook() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_webhook.UpdateWebhookRequest() + + @pytest.mark.asyncio async def test_update_webhook_async( transport: str = "grpc_asyncio", request_type=gcdc_webhook.UpdateWebhookRequest @@ -1402,6 +1469,22 @@ def test_delete_webhook_from_dict(): test_delete_webhook(request_type=dict) +def test_delete_webhook_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 = WebhooksClient( + 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_webhook), "__call__") as call: + client.delete_webhook() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == webhook.DeleteWebhookRequest() + + @pytest.mark.asyncio async def test_delete_webhook_async( transport: str = "grpc_asyncio", request_type=webhook.DeleteWebhookRequest @@ -1606,7 +1689,7 @@ def test_transport_get_channel(): @pytest.mark.parametrize( "transport_class", - [transports.WebhooksGrpcTransport, transports.WebhooksGrpcAsyncIOTransport], + [transports.WebhooksGrpcTransport, transports.WebhooksGrpcAsyncIOTransport,], ) def test_transport_adc(transport_class): # Test default credentials are used if not provided. @@ -1719,6 +1802,51 @@ def test_webhooks_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [transports.WebhooksGrpcTransport, transports.WebhooksGrpcAsyncIOTransport], +) +def test_webhooks_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/dialogflow", + ), + 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_webhooks_host_no_port(): client = WebhooksClient( credentials=credentials.AnonymousCredentials(), @@ -1740,7 +1868,7 @@ def test_webhooks_host_with_port(): def test_webhooks_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.WebhooksGrpcTransport( @@ -1752,7 +1880,7 @@ def test_webhooks_grpc_transport_channel(): def test_webhooks_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.WebhooksGrpcAsyncIOTransport( @@ -1763,6 +1891,8 @@ def test_webhooks_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.WebhooksGrpcTransport, transports.WebhooksGrpcAsyncIOTransport], @@ -1772,7 +1902,7 @@ def test_webhooks_transport_channel_mtls_with_client_cert_source(transport_class "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 @@ -1813,6 +1943,8 @@ def test_webhooks_transport_channel_mtls_with_client_cert_source(transport_class 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.WebhooksGrpcTransport, transports.WebhooksGrpcAsyncIOTransport], @@ -1825,7 +1957,7 @@ def test_webhooks_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/dialogflowcx_v3beta1/__init__.py b/tests/unit/gapic/dialogflowcx_v3beta1/__init__.py index 8b137891..42ffdf2b 100644 --- a/tests/unit/gapic/dialogflowcx_v3beta1/__init__.py +++ b/tests/unit/gapic/dialogflowcx_v3beta1/__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/dialogflowcx_v3beta1/test_agents.py b/tests/unit/gapic/dialogflowcx_v3beta1/test_agents.py index 857e7c8e..2bfea055 100644 --- a/tests/unit/gapic/dialogflowcx_v3beta1/test_agents.py +++ b/tests/unit/gapic/dialogflowcx_v3beta1/test_agents.py @@ -41,6 +41,7 @@ from google.cloud.dialogflowcx_v3beta1.services.agents import transports from google.cloud.dialogflowcx_v3beta1.types import agent from google.cloud.dialogflowcx_v3beta1.types import agent as gcdc_agent +from google.cloud.dialogflowcx_v3beta1.types import flow from google.longrunning import operations_pb2 from google.oauth2 import service_account from google.protobuf import field_mask_pb2 as field_mask # type: ignore @@ -85,7 +86,22 @@ def test__get_default_mtls_endpoint(): assert AgentsClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi -@pytest.mark.parametrize("client_class", [AgentsClient, AgentsAsyncClient]) +@pytest.mark.parametrize("client_class", [AgentsClient, AgentsAsyncClient,]) +def test_agents_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 == "dialogflow.googleapis.com:443" + + +@pytest.mark.parametrize("client_class", [AgentsClient, AgentsAsyncClient,]) def test_agents_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() with mock.patch.object( @@ -94,16 +110,21 @@ def test_agents_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 == "dialogflow.googleapis.com:443" def test_agents_client_get_transport_class(): transport = AgentsClient.get_transport_class() - assert transport == transports.AgentsGrpcTransport + available_transports = [ + transports.AgentsGrpcTransport, + ] + assert transport in available_transports transport = AgentsClient.get_transport_class("grpc") assert transport == transports.AgentsGrpcTransport @@ -144,7 +165,7 @@ def test_agents_client_client_options(client_class, transport_class, transport_n 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, ) @@ -160,7 +181,7 @@ def test_agents_client_client_options(client_class, transport_class, transport_n 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, ) @@ -176,7 +197,7 @@ def test_agents_client_client_options(client_class, transport_class, transport_n 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, ) @@ -204,7 +225,7 @@ def test_agents_client_client_options(client_class, transport_class, transport_n 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, ) @@ -251,29 +272,25 @@ def test_agents_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. @@ -282,66 +299,53 @@ def test_agents_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", @@ -363,7 +367,7 @@ def test_agents_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, ) @@ -389,7 +393,7 @@ def test_agents_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, ) @@ -406,7 +410,7 @@ def test_agents_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, ) @@ -447,6 +451,22 @@ def test_list_agents_from_dict(): test_list_agents(request_type=dict) +def test_list_agents_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 = AgentsClient( + 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_agents), "__call__") as call: + client.list_agents() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == agent.ListAgentsRequest() + + @pytest.mark.asyncio async def test_list_agents_async( transport: str = "grpc_asyncio", request_type=agent.ListAgentsRequest @@ -729,6 +749,7 @@ def test_get_agent(transport: str = "grpc", request_type=agent.GetAgentRequest): description="description_value", avatar_uri="avatar_uri_value", start_flow="start_flow_value", + security_settings="security_settings_value", enable_stackdriver_logging=True, enable_spell_correction=True, ) @@ -759,6 +780,8 @@ def test_get_agent(transport: str = "grpc", request_type=agent.GetAgentRequest): assert response.start_flow == "start_flow_value" + assert response.security_settings == "security_settings_value" + assert response.enable_stackdriver_logging is True assert response.enable_spell_correction is True @@ -768,6 +791,22 @@ def test_get_agent_from_dict(): test_get_agent(request_type=dict) +def test_get_agent_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 = AgentsClient( + 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_agent), "__call__") as call: + client.get_agent() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == agent.GetAgentRequest() + + @pytest.mark.asyncio async def test_get_agent_async( transport: str = "grpc_asyncio", request_type=agent.GetAgentRequest @@ -792,6 +831,7 @@ async def test_get_agent_async( description="description_value", avatar_uri="avatar_uri_value", start_flow="start_flow_value", + security_settings="security_settings_value", enable_stackdriver_logging=True, enable_spell_correction=True, ) @@ -822,6 +862,8 @@ async def test_get_agent_async( assert response.start_flow == "start_flow_value" + assert response.security_settings == "security_settings_value" + assert response.enable_stackdriver_logging is True assert response.enable_spell_correction is True @@ -968,6 +1010,7 @@ def test_create_agent( description="description_value", avatar_uri="avatar_uri_value", start_flow="start_flow_value", + security_settings="security_settings_value", enable_stackdriver_logging=True, enable_spell_correction=True, ) @@ -998,6 +1041,8 @@ def test_create_agent( assert response.start_flow == "start_flow_value" + assert response.security_settings == "security_settings_value" + assert response.enable_stackdriver_logging is True assert response.enable_spell_correction is True @@ -1007,6 +1052,22 @@ def test_create_agent_from_dict(): test_create_agent(request_type=dict) +def test_create_agent_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 = AgentsClient( + 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_agent), "__call__") as call: + client.create_agent() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_agent.CreateAgentRequest() + + @pytest.mark.asyncio async def test_create_agent_async( transport: str = "grpc_asyncio", request_type=gcdc_agent.CreateAgentRequest @@ -1031,6 +1092,7 @@ async def test_create_agent_async( description="description_value", avatar_uri="avatar_uri_value", start_flow="start_flow_value", + security_settings="security_settings_value", enable_stackdriver_logging=True, enable_spell_correction=True, ) @@ -1061,6 +1123,8 @@ async def test_create_agent_async( assert response.start_flow == "start_flow_value" + assert response.security_settings == "security_settings_value" + assert response.enable_stackdriver_logging is True assert response.enable_spell_correction is True @@ -1219,6 +1283,7 @@ def test_update_agent( description="description_value", avatar_uri="avatar_uri_value", start_flow="start_flow_value", + security_settings="security_settings_value", enable_stackdriver_logging=True, enable_spell_correction=True, ) @@ -1249,6 +1314,8 @@ def test_update_agent( assert response.start_flow == "start_flow_value" + assert response.security_settings == "security_settings_value" + assert response.enable_stackdriver_logging is True assert response.enable_spell_correction is True @@ -1258,6 +1325,22 @@ def test_update_agent_from_dict(): test_update_agent(request_type=dict) +def test_update_agent_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 = AgentsClient( + 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_agent), "__call__") as call: + client.update_agent() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_agent.UpdateAgentRequest() + + @pytest.mark.asyncio async def test_update_agent_async( transport: str = "grpc_asyncio", request_type=gcdc_agent.UpdateAgentRequest @@ -1282,6 +1365,7 @@ async def test_update_agent_async( description="description_value", avatar_uri="avatar_uri_value", start_flow="start_flow_value", + security_settings="security_settings_value", enable_stackdriver_logging=True, enable_spell_correction=True, ) @@ -1312,6 +1396,8 @@ async def test_update_agent_async( assert response.start_flow == "start_flow_value" + assert response.security_settings == "security_settings_value" + assert response.enable_stackdriver_logging is True assert response.enable_spell_correction is True @@ -1480,6 +1566,22 @@ def test_delete_agent_from_dict(): test_delete_agent(request_type=dict) +def test_delete_agent_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 = AgentsClient( + 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_agent), "__call__") as call: + client.delete_agent() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == agent.DeleteAgentRequest() + + @pytest.mark.asyncio async def test_delete_agent_async( transport: str = "grpc_asyncio", request_type=agent.DeleteAgentRequest @@ -1658,6 +1760,22 @@ def test_export_agent_from_dict(): test_export_agent(request_type=dict) +def test_export_agent_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 = AgentsClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.export_agent), "__call__") as call: + client.export_agent() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == agent.ExportAgentRequest() + + @pytest.mark.asyncio async def test_export_agent_async( transport: str = "grpc_asyncio", request_type=agent.ExportAgentRequest @@ -1775,6 +1893,22 @@ def test_restore_agent_from_dict(): test_restore_agent(request_type=dict) +def test_restore_agent_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 = AgentsClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.restore_agent), "__call__") as call: + client.restore_agent() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == agent.RestoreAgentRequest() + + @pytest.mark.asyncio async def test_restore_agent_async( transport: str = "grpc_asyncio", request_type=agent.RestoreAgentRequest @@ -1862,6 +1996,367 @@ async def test_restore_agent_field_headers_async(): assert ("x-goog-request-params", "name=name/value",) in kw["metadata"] +def test_validate_agent( + transport: str = "grpc", request_type=agent.ValidateAgentRequest +): + client = AgentsClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.validate_agent), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = agent.AgentValidationResult(name="name_value",) + + response = client.validate_agent(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0] == agent.ValidateAgentRequest() + + # Establish that the response is the type that we expect. + + assert isinstance(response, agent.AgentValidationResult) + + assert response.name == "name_value" + + +def test_validate_agent_from_dict(): + test_validate_agent(request_type=dict) + + +def test_validate_agent_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 = AgentsClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.validate_agent), "__call__") as call: + client.validate_agent() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == agent.ValidateAgentRequest() + + +@pytest.mark.asyncio +async def test_validate_agent_async( + transport: str = "grpc_asyncio", request_type=agent.ValidateAgentRequest +): + client = AgentsAsyncClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.validate_agent), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + agent.AgentValidationResult(name="name_value",) + ) + + response = await client.validate_agent(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0] == agent.ValidateAgentRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, agent.AgentValidationResult) + + assert response.name == "name_value" + + +@pytest.mark.asyncio +async def test_validate_agent_async_from_dict(): + await test_validate_agent_async(request_type=dict) + + +def test_validate_agent_field_headers(): + client = AgentsClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = agent.ValidateAgentRequest() + request.name = "name/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.validate_agent), "__call__") as call: + call.return_value = agent.AgentValidationResult() + + client.validate_agent(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "name=name/value",) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_validate_agent_field_headers_async(): + client = AgentsAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = agent.ValidateAgentRequest() + request.name = "name/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.validate_agent), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + agent.AgentValidationResult() + ) + + await client.validate_agent(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "name=name/value",) in kw["metadata"] + + +def test_get_agent_validation_result( + transport: str = "grpc", request_type=agent.GetAgentValidationResultRequest +): + client = AgentsClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_agent_validation_result), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = agent.AgentValidationResult(name="name_value",) + + response = client.get_agent_validation_result(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0] == agent.GetAgentValidationResultRequest() + + # Establish that the response is the type that we expect. + + assert isinstance(response, agent.AgentValidationResult) + + assert response.name == "name_value" + + +def test_get_agent_validation_result_from_dict(): + test_get_agent_validation_result(request_type=dict) + + +def test_get_agent_validation_result_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 = AgentsClient( + 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_agent_validation_result), "__call__" + ) as call: + client.get_agent_validation_result() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == agent.GetAgentValidationResultRequest() + + +@pytest.mark.asyncio +async def test_get_agent_validation_result_async( + transport: str = "grpc_asyncio", request_type=agent.GetAgentValidationResultRequest +): + client = AgentsAsyncClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_agent_validation_result), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + agent.AgentValidationResult(name="name_value",) + ) + + response = await client.get_agent_validation_result(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0] == agent.GetAgentValidationResultRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, agent.AgentValidationResult) + + assert response.name == "name_value" + + +@pytest.mark.asyncio +async def test_get_agent_validation_result_async_from_dict(): + await test_get_agent_validation_result_async(request_type=dict) + + +def test_get_agent_validation_result_field_headers(): + client = AgentsClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = agent.GetAgentValidationResultRequest() + request.name = "name/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_agent_validation_result), "__call__" + ) as call: + call.return_value = agent.AgentValidationResult() + + client.get_agent_validation_result(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "name=name/value",) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_get_agent_validation_result_field_headers_async(): + client = AgentsAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = agent.GetAgentValidationResultRequest() + request.name = "name/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_agent_validation_result), "__call__" + ) as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + agent.AgentValidationResult() + ) + + await client.get_agent_validation_result(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "name=name/value",) in kw["metadata"] + + +def test_get_agent_validation_result_flattened(): + client = AgentsClient(credentials=credentials.AnonymousCredentials(),) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_agent_validation_result), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = agent.AgentValidationResult() + + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.get_agent_validation_result(name="name_value",) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0].name == "name_value" + + +def test_get_agent_validation_result_flattened_error(): + client = AgentsClient(credentials=credentials.AnonymousCredentials(),) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.get_agent_validation_result( + agent.GetAgentValidationResultRequest(), name="name_value", + ) + + +@pytest.mark.asyncio +async def test_get_agent_validation_result_flattened_async(): + client = AgentsAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_agent_validation_result), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = agent.AgentValidationResult() + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + agent.AgentValidationResult() + ) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.get_agent_validation_result(name="name_value",) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0].name == "name_value" + + +@pytest.mark.asyncio +async def test_get_agent_validation_result_flattened_error_async(): + client = AgentsAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.get_agent_validation_result( + agent.GetAgentValidationResultRequest(), name="name_value", + ) + + def test_credentials_transport_error(): # It is an error to provide credentials and a transport instance. transport = transports.AgentsGrpcTransport( @@ -1918,7 +2413,7 @@ def test_transport_get_channel(): @pytest.mark.parametrize( "transport_class", - [transports.AgentsGrpcTransport, transports.AgentsGrpcAsyncIOTransport], + [transports.AgentsGrpcTransport, transports.AgentsGrpcAsyncIOTransport,], ) def test_transport_adc(transport_class): # Test default credentials are used if not provided. @@ -1963,6 +2458,8 @@ def test_agents_base_transport(): "delete_agent", "export_agent", "restore_agent", + "validate_agent", + "get_agent_validation_result", ) for method in methods: with pytest.raises(NotImplementedError): @@ -2038,6 +2535,51 @@ def test_agents_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [transports.AgentsGrpcTransport, transports.AgentsGrpcAsyncIOTransport], +) +def test_agents_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/dialogflow", + ), + 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_agents_host_no_port(): client = AgentsClient( credentials=credentials.AnonymousCredentials(), @@ -2059,7 +2601,7 @@ def test_agents_host_with_port(): def test_agents_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.AgentsGrpcTransport( @@ -2071,7 +2613,7 @@ def test_agents_grpc_transport_channel(): def test_agents_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.AgentsGrpcAsyncIOTransport( @@ -2082,6 +2624,8 @@ def test_agents_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.AgentsGrpcTransport, transports.AgentsGrpcAsyncIOTransport], @@ -2091,7 +2635,7 @@ def test_agents_transport_channel_mtls_with_client_cert_source(transport_class): "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 @@ -2132,6 +2676,8 @@ def test_agents_transport_channel_mtls_with_client_cert_source(transport_class): 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.AgentsGrpcTransport, transports.AgentsGrpcAsyncIOTransport], @@ -2144,7 +2690,7 @@ def test_agents_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 @@ -2227,11 +2773,36 @@ def test_parse_agent_path(): assert expected == actual -def test_flow_path(): +def test_agent_validation_result_path(): project = "cuttlefish" location = "mussel" agent = "winkle" - flow = "nautilus" + + expected = "projects/{project}/locations/{location}/agents/{agent}/validationResult".format( + project=project, location=location, agent=agent, + ) + actual = AgentsClient.agent_validation_result_path(project, location, agent) + assert expected == actual + + +def test_parse_agent_validation_result_path(): + expected = { + "project": "nautilus", + "location": "scallop", + "agent": "abalone", + } + path = AgentsClient.agent_validation_result_path(**expected) + + # Check that the path construction is reversible. + actual = AgentsClient.parse_agent_validation_result_path(path) + assert expected == actual + + +def test_flow_path(): + project = "squid" + location = "clam" + agent = "whelk" + flow = "octopus" expected = "projects/{project}/locations/{location}/agents/{agent}/flows/{flow}".format( project=project, location=location, agent=agent, flow=flow, @@ -2242,10 +2813,10 @@ def test_flow_path(): def test_parse_flow_path(): expected = { - "project": "scallop", - "location": "abalone", - "agent": "squid", - "flow": "clam", + "project": "oyster", + "location": "nudibranch", + "agent": "cuttlefish", + "flow": "mussel", } path = AgentsClient.flow_path(**expected) @@ -2254,8 +2825,60 @@ def test_parse_flow_path(): assert expected == actual +def test_flow_validation_result_path(): + project = "winkle" + location = "nautilus" + agent = "scallop" + flow = "abalone" + + expected = "projects/{project}/locations/{location}/agents/{agent}/flows/{flow}/validationResult".format( + project=project, location=location, agent=agent, flow=flow, + ) + actual = AgentsClient.flow_validation_result_path(project, location, agent, flow) + assert expected == actual + + +def test_parse_flow_validation_result_path(): + expected = { + "project": "squid", + "location": "clam", + "agent": "whelk", + "flow": "octopus", + } + path = AgentsClient.flow_validation_result_path(**expected) + + # Check that the path construction is reversible. + actual = AgentsClient.parse_flow_validation_result_path(path) + assert expected == actual + + +def test_security_settings_path(): + project = "oyster" + location = "nudibranch" + security_settings = "cuttlefish" + + expected = "projects/{project}/locations/{location}/securitySettings/{security_settings}".format( + project=project, location=location, security_settings=security_settings, + ) + actual = AgentsClient.security_settings_path(project, location, security_settings) + assert expected == actual + + +def test_parse_security_settings_path(): + expected = { + "project": "mussel", + "location": "winkle", + "security_settings": "nautilus", + } + path = AgentsClient.security_settings_path(**expected) + + # Check that the path construction is reversible. + actual = AgentsClient.parse_security_settings_path(path) + assert expected == actual + + def test_common_billing_account_path(): - billing_account = "whelk" + billing_account = "scallop" expected = "billingAccounts/{billing_account}".format( billing_account=billing_account, @@ -2266,7 +2889,7 @@ def test_common_billing_account_path(): def test_parse_common_billing_account_path(): expected = { - "billing_account": "octopus", + "billing_account": "abalone", } path = AgentsClient.common_billing_account_path(**expected) @@ -2276,7 +2899,7 @@ def test_parse_common_billing_account_path(): def test_common_folder_path(): - folder = "oyster" + folder = "squid" expected = "folders/{folder}".format(folder=folder,) actual = AgentsClient.common_folder_path(folder) @@ -2285,7 +2908,7 @@ def test_common_folder_path(): def test_parse_common_folder_path(): expected = { - "folder": "nudibranch", + "folder": "clam", } path = AgentsClient.common_folder_path(**expected) @@ -2295,7 +2918,7 @@ def test_parse_common_folder_path(): def test_common_organization_path(): - organization = "cuttlefish" + organization = "whelk" expected = "organizations/{organization}".format(organization=organization,) actual = AgentsClient.common_organization_path(organization) @@ -2304,7 +2927,7 @@ def test_common_organization_path(): def test_parse_common_organization_path(): expected = { - "organization": "mussel", + "organization": "octopus", } path = AgentsClient.common_organization_path(**expected) @@ -2314,7 +2937,7 @@ def test_parse_common_organization_path(): def test_common_project_path(): - project = "winkle" + project = "oyster" expected = "projects/{project}".format(project=project,) actual = AgentsClient.common_project_path(project) @@ -2323,7 +2946,7 @@ def test_common_project_path(): def test_parse_common_project_path(): expected = { - "project": "nautilus", + "project": "nudibranch", } path = AgentsClient.common_project_path(**expected) @@ -2333,8 +2956,8 @@ def test_parse_common_project_path(): def test_common_location_path(): - project = "scallop" - location = "abalone" + project = "cuttlefish" + location = "mussel" expected = "projects/{project}/locations/{location}".format( project=project, location=location, @@ -2345,8 +2968,8 @@ def test_common_location_path(): def test_parse_common_location_path(): expected = { - "project": "squid", - "location": "clam", + "project": "winkle", + "location": "nautilus", } path = AgentsClient.common_location_path(**expected) diff --git a/tests/unit/gapic/dialogflowcx_v3beta1/test_entity_types.py b/tests/unit/gapic/dialogflowcx_v3beta1/test_entity_types.py index 84b2a6ae..db575e44 100644 --- a/tests/unit/gapic/dialogflowcx_v3beta1/test_entity_types.py +++ b/tests/unit/gapic/dialogflowcx_v3beta1/test_entity_types.py @@ -85,7 +85,22 @@ def test__get_default_mtls_endpoint(): assert EntityTypesClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi -@pytest.mark.parametrize("client_class", [EntityTypesClient, EntityTypesAsyncClient]) +@pytest.mark.parametrize("client_class", [EntityTypesClient, EntityTypesAsyncClient,]) +def test_entity_types_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 == "dialogflow.googleapis.com:443" + + +@pytest.mark.parametrize("client_class", [EntityTypesClient, EntityTypesAsyncClient,]) def test_entity_types_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() with mock.patch.object( @@ -94,16 +109,21 @@ def test_entity_types_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 == "dialogflow.googleapis.com:443" def test_entity_types_client_get_transport_class(): transport = EntityTypesClient.get_transport_class() - assert transport == transports.EntityTypesGrpcTransport + available_transports = [ + transports.EntityTypesGrpcTransport, + ] + assert transport in available_transports transport = EntityTypesClient.get_transport_class("grpc") assert transport == transports.EntityTypesGrpcTransport @@ -152,7 +172,7 @@ def test_entity_types_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, ) @@ -168,7 +188,7 @@ def test_entity_types_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, ) @@ -184,7 +204,7 @@ def test_entity_types_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, ) @@ -212,7 +232,7 @@ def test_entity_types_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, ) @@ -261,29 +281,25 @@ def test_entity_types_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. @@ -292,66 +308,53 @@ def test_entity_types_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", @@ -377,7 +380,7 @@ def test_entity_types_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, ) @@ -407,7 +410,7 @@ def test_entity_types_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, ) @@ -424,7 +427,7 @@ def test_entity_types_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, ) @@ -469,6 +472,24 @@ def test_list_entity_types_from_dict(): test_list_entity_types(request_type=dict) +def test_list_entity_types_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 = EntityTypesClient( + 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_entity_types), "__call__" + ) as call: + client.list_entity_types() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == entity_type.ListEntityTypesRequest() + + @pytest.mark.asyncio async def test_list_entity_types_async( transport: str = "grpc_asyncio", request_type=entity_type.ListEntityTypesRequest @@ -811,6 +832,7 @@ def test_get_entity_type( kind=entity_type.EntityType.Kind.KIND_MAP, auto_expansion_mode=entity_type.EntityType.AutoExpansionMode.AUTO_EXPANSION_MODE_DEFAULT, enable_fuzzy_extraction=True, + redact=True, ) response = client.get_entity_type(request) @@ -838,11 +860,29 @@ def test_get_entity_type( assert response.enable_fuzzy_extraction is True + assert response.redact is True + def test_get_entity_type_from_dict(): test_get_entity_type(request_type=dict) +def test_get_entity_type_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 = EntityTypesClient( + 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_entity_type), "__call__") as call: + client.get_entity_type() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == entity_type.GetEntityTypeRequest() + + @pytest.mark.asyncio async def test_get_entity_type_async( transport: str = "grpc_asyncio", request_type=entity_type.GetEntityTypeRequest @@ -865,6 +905,7 @@ async def test_get_entity_type_async( kind=entity_type.EntityType.Kind.KIND_MAP, auto_expansion_mode=entity_type.EntityType.AutoExpansionMode.AUTO_EXPANSION_MODE_DEFAULT, enable_fuzzy_extraction=True, + redact=True, ) ) @@ -892,6 +933,8 @@ async def test_get_entity_type_async( assert response.enable_fuzzy_extraction is True + assert response.redact is True + @pytest.mark.asyncio async def test_get_entity_type_async_from_dict(): @@ -1038,6 +1081,7 @@ def test_create_entity_type( kind=gcdc_entity_type.EntityType.Kind.KIND_MAP, auto_expansion_mode=gcdc_entity_type.EntityType.AutoExpansionMode.AUTO_EXPANSION_MODE_DEFAULT, enable_fuzzy_extraction=True, + redact=True, ) response = client.create_entity_type(request) @@ -1065,11 +1109,31 @@ def test_create_entity_type( assert response.enable_fuzzy_extraction is True + assert response.redact is True + def test_create_entity_type_from_dict(): test_create_entity_type(request_type=dict) +def test_create_entity_type_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 = EntityTypesClient( + 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_entity_type), "__call__" + ) as call: + client.create_entity_type() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_entity_type.CreateEntityTypeRequest() + + @pytest.mark.asyncio async def test_create_entity_type_async( transport: str = "grpc_asyncio", @@ -1095,6 +1159,7 @@ async def test_create_entity_type_async( kind=gcdc_entity_type.EntityType.Kind.KIND_MAP, auto_expansion_mode=gcdc_entity_type.EntityType.AutoExpansionMode.AUTO_EXPANSION_MODE_DEFAULT, enable_fuzzy_extraction=True, + redact=True, ) ) @@ -1122,6 +1187,8 @@ async def test_create_entity_type_async( assert response.enable_fuzzy_extraction is True + assert response.redact is True + @pytest.mark.asyncio async def test_create_entity_type_async_from_dict(): @@ -1290,6 +1357,7 @@ def test_update_entity_type( kind=gcdc_entity_type.EntityType.Kind.KIND_MAP, auto_expansion_mode=gcdc_entity_type.EntityType.AutoExpansionMode.AUTO_EXPANSION_MODE_DEFAULT, enable_fuzzy_extraction=True, + redact=True, ) response = client.update_entity_type(request) @@ -1317,11 +1385,31 @@ def test_update_entity_type( assert response.enable_fuzzy_extraction is True + assert response.redact is True + def test_update_entity_type_from_dict(): test_update_entity_type(request_type=dict) +def test_update_entity_type_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 = EntityTypesClient( + 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_entity_type), "__call__" + ) as call: + client.update_entity_type() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_entity_type.UpdateEntityTypeRequest() + + @pytest.mark.asyncio async def test_update_entity_type_async( transport: str = "grpc_asyncio", @@ -1347,6 +1435,7 @@ async def test_update_entity_type_async( kind=gcdc_entity_type.EntityType.Kind.KIND_MAP, auto_expansion_mode=gcdc_entity_type.EntityType.AutoExpansionMode.AUTO_EXPANSION_MODE_DEFAULT, enable_fuzzy_extraction=True, + redact=True, ) ) @@ -1374,6 +1463,8 @@ async def test_update_entity_type_async( assert response.enable_fuzzy_extraction is True + assert response.redact is True + @pytest.mark.asyncio async def test_update_entity_type_async_from_dict(): @@ -1558,6 +1649,24 @@ def test_delete_entity_type_from_dict(): test_delete_entity_type(request_type=dict) +def test_delete_entity_type_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 = EntityTypesClient( + 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_entity_type), "__call__" + ) as call: + client.delete_entity_type() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == entity_type.DeleteEntityTypeRequest() + + @pytest.mark.asyncio async def test_delete_entity_type_async( transport: str = "grpc_asyncio", request_type=entity_type.DeleteEntityTypeRequest @@ -1772,7 +1881,7 @@ def test_transport_get_channel(): @pytest.mark.parametrize( "transport_class", - [transports.EntityTypesGrpcTransport, transports.EntityTypesGrpcAsyncIOTransport], + [transports.EntityTypesGrpcTransport, transports.EntityTypesGrpcAsyncIOTransport,], ) def test_transport_adc(transport_class): # Test default credentials are used if not provided. @@ -1885,6 +1994,51 @@ def test_entity_types_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [transports.EntityTypesGrpcTransport, transports.EntityTypesGrpcAsyncIOTransport], +) +def test_entity_types_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/dialogflow", + ), + 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_entity_types_host_no_port(): client = EntityTypesClient( credentials=credentials.AnonymousCredentials(), @@ -1906,7 +2060,7 @@ def test_entity_types_host_with_port(): def test_entity_types_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.EntityTypesGrpcTransport( @@ -1918,7 +2072,7 @@ def test_entity_types_grpc_transport_channel(): def test_entity_types_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.EntityTypesGrpcAsyncIOTransport( @@ -1929,6 +2083,8 @@ def test_entity_types_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.EntityTypesGrpcTransport, transports.EntityTypesGrpcAsyncIOTransport], @@ -1938,7 +2094,7 @@ def test_entity_types_transport_channel_mtls_with_client_cert_source(transport_c "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 @@ -1979,6 +2135,8 @@ def test_entity_types_transport_channel_mtls_with_client_cert_source(transport_c 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.EntityTypesGrpcTransport, transports.EntityTypesGrpcAsyncIOTransport], @@ -1991,7 +2149,7 @@ def test_entity_types_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/dialogflowcx_v3beta1/test_environments.py b/tests/unit/gapic/dialogflowcx_v3beta1/test_environments.py index ba4b446e..5a7045e1 100644 --- a/tests/unit/gapic/dialogflowcx_v3beta1/test_environments.py +++ b/tests/unit/gapic/dialogflowcx_v3beta1/test_environments.py @@ -91,7 +91,22 @@ def test__get_default_mtls_endpoint(): assert EnvironmentsClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi -@pytest.mark.parametrize("client_class", [EnvironmentsClient, EnvironmentsAsyncClient]) +@pytest.mark.parametrize("client_class", [EnvironmentsClient, EnvironmentsAsyncClient,]) +def test_environments_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 == "dialogflow.googleapis.com:443" + + +@pytest.mark.parametrize("client_class", [EnvironmentsClient, EnvironmentsAsyncClient,]) def test_environments_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() with mock.patch.object( @@ -100,16 +115,21 @@ def test_environments_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 == "dialogflow.googleapis.com:443" def test_environments_client_get_transport_class(): transport = EnvironmentsClient.get_transport_class() - assert transport == transports.EnvironmentsGrpcTransport + available_transports = [ + transports.EnvironmentsGrpcTransport, + ] + assert transport in available_transports transport = EnvironmentsClient.get_transport_class("grpc") assert transport == transports.EnvironmentsGrpcTransport @@ -158,7 +178,7 @@ def test_environments_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 +194,7 @@ def test_environments_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 +210,7 @@ def test_environments_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 +238,7 @@ def test_environments_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, ) @@ -267,29 +287,25 @@ def test_environments_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. @@ -298,66 +314,53 @@ def test_environments_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", @@ -383,7 +386,7 @@ def test_environments_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, ) @@ -413,7 +416,7 @@ def test_environments_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, ) @@ -430,7 +433,7 @@ def test_environments_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, ) @@ -475,6 +478,24 @@ def test_list_environments_from_dict(): test_list_environments(request_type=dict) +def test_list_environments_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 = EnvironmentsClient( + 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_environments), "__call__" + ) as call: + client.list_environments() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == environment.ListEnvironmentsRequest() + + @pytest.mark.asyncio async def test_list_environments_async( transport: str = "grpc_asyncio", request_type=environment.ListEnvironmentsRequest @@ -840,6 +861,22 @@ def test_get_environment_from_dict(): test_get_environment(request_type=dict) +def test_get_environment_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 = EnvironmentsClient( + 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_environment), "__call__") as call: + client.get_environment() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == environment.GetEnvironmentRequest() + + @pytest.mark.asyncio async def test_get_environment_async( transport: str = "grpc_asyncio", request_type=environment.GetEnvironmentRequest @@ -1038,6 +1075,24 @@ def test_create_environment_from_dict(): test_create_environment(request_type=dict) +def test_create_environment_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 = EnvironmentsClient( + 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_environment), "__call__" + ) as call: + client.create_environment() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_environment.CreateEnvironmentRequest() + + @pytest.mark.asyncio async def test_create_environment_async( transport: str = "grpc_asyncio", @@ -1251,6 +1306,24 @@ def test_update_environment_from_dict(): test_update_environment(request_type=dict) +def test_update_environment_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 = EnvironmentsClient( + 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_environment), "__call__" + ) as call: + client.update_environment() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_environment.UpdateEnvironmentRequest() + + @pytest.mark.asyncio async def test_update_environment_async( transport: str = "grpc_asyncio", @@ -1468,6 +1541,24 @@ def test_delete_environment_from_dict(): test_delete_environment(request_type=dict) +def test_delete_environment_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 = EnvironmentsClient( + 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_environment), "__call__" + ) as call: + client.delete_environment() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == environment.DeleteEnvironmentRequest() + + @pytest.mark.asyncio async def test_delete_environment_async( transport: str = "grpc_asyncio", request_type=environment.DeleteEnvironmentRequest @@ -1665,6 +1756,24 @@ def test_lookup_environment_history_from_dict(): test_lookup_environment_history(request_type=dict) +def test_lookup_environment_history_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = EnvironmentsClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.lookup_environment_history), "__call__" + ) as call: + client.lookup_environment_history() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == environment.LookupEnvironmentHistoryRequest() + + @pytest.mark.asyncio async def test_lookup_environment_history_async( transport: str = "grpc_asyncio", @@ -2044,7 +2153,10 @@ def test_transport_get_channel(): @pytest.mark.parametrize( "transport_class", - [transports.EnvironmentsGrpcTransport, transports.EnvironmentsGrpcAsyncIOTransport], + [ + transports.EnvironmentsGrpcTransport, + transports.EnvironmentsGrpcAsyncIOTransport, + ], ) def test_transport_adc(transport_class): # Test default credentials are used if not provided. @@ -2163,6 +2275,51 @@ def test_environments_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [transports.EnvironmentsGrpcTransport, transports.EnvironmentsGrpcAsyncIOTransport], +) +def test_environments_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/dialogflow", + ), + 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_environments_host_no_port(): client = EnvironmentsClient( credentials=credentials.AnonymousCredentials(), @@ -2184,7 +2341,7 @@ def test_environments_host_with_port(): def test_environments_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.EnvironmentsGrpcTransport( @@ -2196,7 +2353,7 @@ def test_environments_grpc_transport_channel(): def test_environments_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.EnvironmentsGrpcAsyncIOTransport( @@ -2207,6 +2364,8 @@ def test_environments_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.EnvironmentsGrpcTransport, transports.EnvironmentsGrpcAsyncIOTransport], @@ -2216,7 +2375,7 @@ def test_environments_transport_channel_mtls_with_client_cert_source(transport_c "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 +2416,8 @@ def test_environments_transport_channel_mtls_with_client_cert_source(transport_c 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.EnvironmentsGrpcTransport, transports.EnvironmentsGrpcAsyncIOTransport], @@ -2269,7 +2430,7 @@ def test_environments_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/dialogflowcx_v3beta1/test_experiments.py b/tests/unit/gapic/dialogflowcx_v3beta1/test_experiments.py index 2f9feb9e..f153fb3e 100644 --- a/tests/unit/gapic/dialogflowcx_v3beta1/test_experiments.py +++ b/tests/unit/gapic/dialogflowcx_v3beta1/test_experiments.py @@ -87,7 +87,22 @@ def test__get_default_mtls_endpoint(): assert ExperimentsClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi -@pytest.mark.parametrize("client_class", [ExperimentsClient, ExperimentsAsyncClient]) +@pytest.mark.parametrize("client_class", [ExperimentsClient, ExperimentsAsyncClient,]) +def test_experiments_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 == "dialogflow.googleapis.com:443" + + +@pytest.mark.parametrize("client_class", [ExperimentsClient, ExperimentsAsyncClient,]) def test_experiments_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() with mock.patch.object( @@ -96,16 +111,21 @@ def test_experiments_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 == "dialogflow.googleapis.com:443" def test_experiments_client_get_transport_class(): transport = ExperimentsClient.get_transport_class() - assert transport == transports.ExperimentsGrpcTransport + available_transports = [ + transports.ExperimentsGrpcTransport, + ] + assert transport in available_transports transport = ExperimentsClient.get_transport_class("grpc") assert transport == transports.ExperimentsGrpcTransport @@ -154,7 +174,7 @@ def test_experiments_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, ) @@ -170,7 +190,7 @@ def test_experiments_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, ) @@ -186,7 +206,7 @@ def test_experiments_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, ) @@ -214,7 +234,7 @@ def test_experiments_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, ) @@ -263,29 +283,25 @@ def test_experiments_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. @@ -294,66 +310,53 @@ def test_experiments_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", @@ -379,7 +382,7 @@ def test_experiments_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, ) @@ -409,7 +412,7 @@ def test_experiments_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, ) @@ -426,7 +429,7 @@ def test_experiments_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, ) @@ -469,6 +472,22 @@ def test_list_experiments_from_dict(): test_list_experiments(request_type=dict) +def test_list_experiments_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 = ExperimentsClient( + 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_experiments), "__call__") as call: + client.list_experiments() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == experiment.ListExperimentsRequest() + + @pytest.mark.asyncio async def test_list_experiments_async( transport: str = "grpc_asyncio", request_type=experiment.ListExperimentsRequest @@ -809,6 +828,22 @@ def test_get_experiment_from_dict(): test_get_experiment(request_type=dict) +def test_get_experiment_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 = ExperimentsClient( + 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_experiment), "__call__") as call: + client.get_experiment() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == experiment.GetExperimentRequest() + + @pytest.mark.asyncio async def test_get_experiment_async( transport: str = "grpc_asyncio", request_type=experiment.GetExperimentRequest @@ -1024,6 +1059,24 @@ def test_create_experiment_from_dict(): test_create_experiment(request_type=dict) +def test_create_experiment_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 = ExperimentsClient( + 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_experiment), "__call__" + ) as call: + client.create_experiment() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_experiment.CreateExperimentRequest() + + @pytest.mark.asyncio async def test_create_experiment_async( transport: str = "grpc_asyncio", @@ -1264,6 +1317,24 @@ def test_update_experiment_from_dict(): test_update_experiment(request_type=dict) +def test_update_experiment_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 = ExperimentsClient( + 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_experiment), "__call__" + ) as call: + client.update_experiment() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_experiment.UpdateExperimentRequest() + + @pytest.mark.asyncio async def test_update_experiment_async( transport: str = "grpc_asyncio", @@ -1494,6 +1565,24 @@ def test_delete_experiment_from_dict(): test_delete_experiment(request_type=dict) +def test_delete_experiment_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 = ExperimentsClient( + 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_experiment), "__call__" + ) as call: + client.delete_experiment() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == experiment.DeleteExperimentRequest() + + @pytest.mark.asyncio async def test_delete_experiment_async( transport: str = "grpc_asyncio", request_type=experiment.DeleteExperimentRequest @@ -1698,6 +1787,22 @@ def test_start_experiment_from_dict(): test_start_experiment(request_type=dict) +def test_start_experiment_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 = ExperimentsClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.start_experiment), "__call__") as call: + client.start_experiment() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == experiment.StartExperimentRequest() + + @pytest.mark.asyncio async def test_start_experiment_async( transport: str = "grpc_asyncio", request_type=experiment.StartExperimentRequest @@ -1911,6 +2016,22 @@ def test_stop_experiment_from_dict(): test_stop_experiment(request_type=dict) +def test_stop_experiment_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 = ExperimentsClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.stop_experiment), "__call__") as call: + client.stop_experiment() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == experiment.StopExperimentRequest() + + @pytest.mark.asyncio async def test_stop_experiment_async( transport: str = "grpc_asyncio", request_type=experiment.StopExperimentRequest @@ -2134,7 +2255,7 @@ def test_transport_get_channel(): @pytest.mark.parametrize( "transport_class", - [transports.ExperimentsGrpcTransport, transports.ExperimentsGrpcAsyncIOTransport], + [transports.ExperimentsGrpcTransport, transports.ExperimentsGrpcAsyncIOTransport,], ) def test_transport_adc(transport_class): # Test default credentials are used if not provided. @@ -2249,6 +2370,51 @@ def test_experiments_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [transports.ExperimentsGrpcTransport, transports.ExperimentsGrpcAsyncIOTransport], +) +def test_experiments_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/dialogflow", + ), + 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_experiments_host_no_port(): client = ExperimentsClient( credentials=credentials.AnonymousCredentials(), @@ -2270,7 +2436,7 @@ def test_experiments_host_with_port(): def test_experiments_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.ExperimentsGrpcTransport( @@ -2282,7 +2448,7 @@ def test_experiments_grpc_transport_channel(): def test_experiments_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.ExperimentsGrpcAsyncIOTransport( @@ -2293,6 +2459,8 @@ def test_experiments_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.ExperimentsGrpcTransport, transports.ExperimentsGrpcAsyncIOTransport], @@ -2302,7 +2470,7 @@ def test_experiments_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 @@ -2343,6 +2511,8 @@ def test_experiments_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.ExperimentsGrpcTransport, transports.ExperimentsGrpcAsyncIOTransport], @@ -2355,7 +2525,7 @@ def test_experiments_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/dialogflowcx_v3beta1/test_flows.py b/tests/unit/gapic/dialogflowcx_v3beta1/test_flows.py index b32e81fd..a3fc79d3 100644 --- a/tests/unit/gapic/dialogflowcx_v3beta1/test_flows.py +++ b/tests/unit/gapic/dialogflowcx_v3beta1/test_flows.py @@ -44,10 +44,12 @@ from google.cloud.dialogflowcx_v3beta1.types import fulfillment from google.cloud.dialogflowcx_v3beta1.types import page from google.cloud.dialogflowcx_v3beta1.types import response_message +from google.cloud.dialogflowcx_v3beta1.types import validation_message from google.longrunning import operations_pb2 from google.oauth2 import service_account from google.protobuf import field_mask_pb2 as field_mask # type: ignore from google.protobuf import struct_pb2 as struct # type: ignore +from google.protobuf import timestamp_pb2 as timestamp # type: ignore def client_cert_source_callback(): @@ -88,7 +90,22 @@ def test__get_default_mtls_endpoint(): assert FlowsClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi -@pytest.mark.parametrize("client_class", [FlowsClient, FlowsAsyncClient]) +@pytest.mark.parametrize("client_class", [FlowsClient, FlowsAsyncClient,]) +def test_flows_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 == "dialogflow.googleapis.com:443" + + +@pytest.mark.parametrize("client_class", [FlowsClient, FlowsAsyncClient,]) def test_flows_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() with mock.patch.object( @@ -97,16 +114,21 @@ def test_flows_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 == "dialogflow.googleapis.com:443" def test_flows_client_get_transport_class(): transport = FlowsClient.get_transport_class() - assert transport == transports.FlowsGrpcTransport + available_transports = [ + transports.FlowsGrpcTransport, + ] + assert transport in available_transports transport = FlowsClient.get_transport_class("grpc") assert transport == transports.FlowsGrpcTransport @@ -147,7 +169,7 @@ def test_flows_client_client_options(client_class, transport_class, transport_na 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, ) @@ -163,7 +185,7 @@ def test_flows_client_client_options(client_class, transport_class, transport_na 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, ) @@ -179,7 +201,7 @@ def test_flows_client_client_options(client_class, transport_class, transport_na 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, ) @@ -207,7 +229,7 @@ def test_flows_client_client_options(client_class, transport_class, transport_na 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, ) @@ -254,29 +276,25 @@ def test_flows_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. @@ -285,66 +303,53 @@ def test_flows_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", @@ -366,7 +371,7 @@ def test_flows_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, ) @@ -392,7 +397,7 @@ def test_flows_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, ) @@ -409,7 +414,7 @@ def test_flows_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, ) @@ -456,6 +461,22 @@ def test_create_flow_from_dict(): test_create_flow(request_type=dict) +def test_create_flow_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 = FlowsClient( + 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_flow), "__call__") as call: + client.create_flow() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_flow.CreateFlowRequest() + + @pytest.mark.asyncio async def test_create_flow_async( transport: str = "grpc_asyncio", request_type=gcdc_flow.CreateFlowRequest @@ -658,6 +679,22 @@ def test_delete_flow_from_dict(): test_delete_flow(request_type=dict) +def test_delete_flow_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 = FlowsClient( + 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_flow), "__call__") as call: + client.delete_flow() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == flow.DeleteFlowRequest() + + @pytest.mark.asyncio async def test_delete_flow_async( transport: str = "grpc_asyncio", request_type=flow.DeleteFlowRequest @@ -841,6 +878,22 @@ def test_list_flows_from_dict(): test_list_flows(request_type=dict) +def test_list_flows_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 = FlowsClient( + 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_flows), "__call__") as call: + client.list_flows() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == flow.ListFlowsRequest() + + @pytest.mark.asyncio async def test_list_flows_async( transport: str = "grpc_asyncio", request_type=flow.ListFlowsRequest @@ -1140,6 +1193,22 @@ def test_get_flow_from_dict(): test_get_flow(request_type=dict) +def test_get_flow_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 = FlowsClient( + 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_flow), "__call__") as call: + client.get_flow() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == flow.GetFlowRequest() + + @pytest.mark.asyncio async def test_get_flow_async( transport: str = "grpc_asyncio", request_type=flow.GetFlowRequest @@ -1341,6 +1410,22 @@ def test_update_flow_from_dict(): test_update_flow(request_type=dict) +def test_update_flow_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 = FlowsClient( + 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_flow), "__call__") as call: + client.update_flow() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_flow.UpdateFlowRequest() + + @pytest.mark.asyncio async def test_update_flow_async( transport: str = "grpc_asyncio", request_type=gcdc_flow.UpdateFlowRequest @@ -1545,6 +1630,22 @@ def test_train_flow_from_dict(): test_train_flow(request_type=dict) +def test_train_flow_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 = FlowsClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.train_flow), "__call__") as call: + client.train_flow() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == flow.TrainFlowRequest() + + @pytest.mark.asyncio async def test_train_flow_async( transport: str = "grpc_asyncio", request_type=flow.TrainFlowRequest @@ -1699,6 +1800,365 @@ async def test_train_flow_flattened_error_async(): ) +def test_validate_flow(transport: str = "grpc", request_type=flow.ValidateFlowRequest): + client = FlowsClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.validate_flow), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = flow.FlowValidationResult(name="name_value",) + + response = client.validate_flow(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0] == flow.ValidateFlowRequest() + + # Establish that the response is the type that we expect. + + assert isinstance(response, flow.FlowValidationResult) + + assert response.name == "name_value" + + +def test_validate_flow_from_dict(): + test_validate_flow(request_type=dict) + + +def test_validate_flow_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 = FlowsClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.validate_flow), "__call__") as call: + client.validate_flow() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == flow.ValidateFlowRequest() + + +@pytest.mark.asyncio +async def test_validate_flow_async( + transport: str = "grpc_asyncio", request_type=flow.ValidateFlowRequest +): + client = FlowsAsyncClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.validate_flow), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + flow.FlowValidationResult(name="name_value",) + ) + + response = await client.validate_flow(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0] == flow.ValidateFlowRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, flow.FlowValidationResult) + + assert response.name == "name_value" + + +@pytest.mark.asyncio +async def test_validate_flow_async_from_dict(): + await test_validate_flow_async(request_type=dict) + + +def test_validate_flow_field_headers(): + client = FlowsClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = flow.ValidateFlowRequest() + request.name = "name/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.validate_flow), "__call__") as call: + call.return_value = flow.FlowValidationResult() + + client.validate_flow(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "name=name/value",) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_validate_flow_field_headers_async(): + client = FlowsAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = flow.ValidateFlowRequest() + request.name = "name/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.validate_flow), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + flow.FlowValidationResult() + ) + + await client.validate_flow(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "name=name/value",) in kw["metadata"] + + +def test_get_flow_validation_result( + transport: str = "grpc", request_type=flow.GetFlowValidationResultRequest +): + client = FlowsClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_flow_validation_result), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = flow.FlowValidationResult(name="name_value",) + + response = client.get_flow_validation_result(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0] == flow.GetFlowValidationResultRequest() + + # Establish that the response is the type that we expect. + + assert isinstance(response, flow.FlowValidationResult) + + assert response.name == "name_value" + + +def test_get_flow_validation_result_from_dict(): + test_get_flow_validation_result(request_type=dict) + + +def test_get_flow_validation_result_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 = FlowsClient( + 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_flow_validation_result), "__call__" + ) as call: + client.get_flow_validation_result() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == flow.GetFlowValidationResultRequest() + + +@pytest.mark.asyncio +async def test_get_flow_validation_result_async( + transport: str = "grpc_asyncio", request_type=flow.GetFlowValidationResultRequest +): + client = FlowsAsyncClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_flow_validation_result), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + flow.FlowValidationResult(name="name_value",) + ) + + response = await client.get_flow_validation_result(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0] == flow.GetFlowValidationResultRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, flow.FlowValidationResult) + + assert response.name == "name_value" + + +@pytest.mark.asyncio +async def test_get_flow_validation_result_async_from_dict(): + await test_get_flow_validation_result_async(request_type=dict) + + +def test_get_flow_validation_result_field_headers(): + client = FlowsClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = flow.GetFlowValidationResultRequest() + request.name = "name/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_flow_validation_result), "__call__" + ) as call: + call.return_value = flow.FlowValidationResult() + + client.get_flow_validation_result(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "name=name/value",) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_get_flow_validation_result_field_headers_async(): + client = FlowsAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = flow.GetFlowValidationResultRequest() + request.name = "name/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_flow_validation_result), "__call__" + ) as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + flow.FlowValidationResult() + ) + + await client.get_flow_validation_result(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "name=name/value",) in kw["metadata"] + + +def test_get_flow_validation_result_flattened(): + client = FlowsClient(credentials=credentials.AnonymousCredentials(),) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_flow_validation_result), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = flow.FlowValidationResult() + + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.get_flow_validation_result(name="name_value",) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0].name == "name_value" + + +def test_get_flow_validation_result_flattened_error(): + client = FlowsClient(credentials=credentials.AnonymousCredentials(),) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.get_flow_validation_result( + flow.GetFlowValidationResultRequest(), name="name_value", + ) + + +@pytest.mark.asyncio +async def test_get_flow_validation_result_flattened_async(): + client = FlowsAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.get_flow_validation_result), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = flow.FlowValidationResult() + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + flow.FlowValidationResult() + ) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.get_flow_validation_result(name="name_value",) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0].name == "name_value" + + +@pytest.mark.asyncio +async def test_get_flow_validation_result_flattened_error_async(): + client = FlowsAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.get_flow_validation_result( + flow.GetFlowValidationResultRequest(), name="name_value", + ) + + def test_credentials_transport_error(): # It is an error to provide credentials and a transport instance. transport = transports.FlowsGrpcTransport( @@ -1755,7 +2215,7 @@ def test_transport_get_channel(): @pytest.mark.parametrize( "transport_class", - [transports.FlowsGrpcTransport, transports.FlowsGrpcAsyncIOTransport], + [transports.FlowsGrpcTransport, transports.FlowsGrpcAsyncIOTransport,], ) def test_transport_adc(transport_class): # Test default credentials are used if not provided. @@ -1799,6 +2259,8 @@ def test_flows_base_transport(): "get_flow", "update_flow", "train_flow", + "validate_flow", + "get_flow_validation_result", ) for method in methods: with pytest.raises(NotImplementedError): @@ -1874,6 +2336,51 @@ def test_flows_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [transports.FlowsGrpcTransport, transports.FlowsGrpcAsyncIOTransport], +) +def test_flows_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/dialogflow", + ), + 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_flows_host_no_port(): client = FlowsClient( credentials=credentials.AnonymousCredentials(), @@ -1895,7 +2402,7 @@ def test_flows_host_with_port(): def test_flows_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.FlowsGrpcTransport(host="squid.clam.whelk", channel=channel,) @@ -1905,7 +2412,7 @@ def test_flows_grpc_transport_channel(): def test_flows_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.FlowsGrpcAsyncIOTransport( @@ -1916,6 +2423,8 @@ def test_flows_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.FlowsGrpcTransport, transports.FlowsGrpcAsyncIOTransport], @@ -1925,7 +2434,7 @@ def test_flows_transport_channel_mtls_with_client_cert_source(transport_class): "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 @@ -1966,6 +2475,8 @@ def test_flows_transport_channel_mtls_with_client_cert_source(transport_class): 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.FlowsGrpcTransport, transports.FlowsGrpcAsyncIOTransport], @@ -1978,7 +2489,7 @@ def test_flows_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 @@ -2063,11 +2574,38 @@ def test_parse_flow_path(): assert expected == actual -def test_intent_path(): +def test_flow_validation_result_path(): project = "winkle" location = "nautilus" agent = "scallop" - intent = "abalone" + flow = "abalone" + + expected = "projects/{project}/locations/{location}/agents/{agent}/flows/{flow}/validationResult".format( + project=project, location=location, agent=agent, flow=flow, + ) + actual = FlowsClient.flow_validation_result_path(project, location, agent, flow) + assert expected == actual + + +def test_parse_flow_validation_result_path(): + expected = { + "project": "squid", + "location": "clam", + "agent": "whelk", + "flow": "octopus", + } + path = FlowsClient.flow_validation_result_path(**expected) + + # Check that the path construction is reversible. + actual = FlowsClient.parse_flow_validation_result_path(path) + assert expected == actual + + +def test_intent_path(): + project = "oyster" + location = "nudibranch" + agent = "cuttlefish" + intent = "mussel" expected = "projects/{project}/locations/{location}/agents/{agent}/intents/{intent}".format( project=project, location=location, agent=agent, intent=intent, @@ -2078,10 +2616,10 @@ def test_intent_path(): def test_parse_intent_path(): expected = { - "project": "squid", - "location": "clam", - "agent": "whelk", - "intent": "octopus", + "project": "winkle", + "location": "nautilus", + "agent": "scallop", + "intent": "abalone", } path = FlowsClient.intent_path(**expected) @@ -2091,11 +2629,11 @@ def test_parse_intent_path(): def test_page_path(): - project = "oyster" - location = "nudibranch" - agent = "cuttlefish" - flow = "mussel" - page = "winkle" + project = "squid" + location = "clam" + agent = "whelk" + flow = "octopus" + page = "oyster" expected = "projects/{project}/locations/{location}/agents/{agent}/flows/{flow}/pages/{page}".format( project=project, location=location, agent=agent, flow=flow, page=page, @@ -2106,11 +2644,11 @@ def test_page_path(): def test_parse_page_path(): expected = { - "project": "nautilus", - "location": "scallop", - "agent": "abalone", - "flow": "squid", - "page": "clam", + "project": "nudibranch", + "location": "cuttlefish", + "agent": "mussel", + "flow": "winkle", + "page": "nautilus", } path = FlowsClient.page_path(**expected) @@ -2120,10 +2658,10 @@ def test_parse_page_path(): def test_webhook_path(): - project = "whelk" - location = "octopus" - agent = "oyster" - webhook = "nudibranch" + project = "scallop" + location = "abalone" + agent = "squid" + webhook = "clam" expected = "projects/{project}/locations/{location}/agents/{agent}/webhooks/{webhook}".format( project=project, location=location, agent=agent, webhook=webhook, @@ -2134,10 +2672,10 @@ def test_webhook_path(): def test_parse_webhook_path(): expected = { - "project": "cuttlefish", - "location": "mussel", - "agent": "winkle", - "webhook": "nautilus", + "project": "whelk", + "location": "octopus", + "agent": "oyster", + "webhook": "nudibranch", } path = FlowsClient.webhook_path(**expected) @@ -2147,7 +2685,7 @@ def test_parse_webhook_path(): def test_common_billing_account_path(): - billing_account = "scallop" + billing_account = "cuttlefish" expected = "billingAccounts/{billing_account}".format( billing_account=billing_account, @@ -2158,7 +2696,7 @@ def test_common_billing_account_path(): def test_parse_common_billing_account_path(): expected = { - "billing_account": "abalone", + "billing_account": "mussel", } path = FlowsClient.common_billing_account_path(**expected) @@ -2168,7 +2706,7 @@ def test_parse_common_billing_account_path(): def test_common_folder_path(): - folder = "squid" + folder = "winkle" expected = "folders/{folder}".format(folder=folder,) actual = FlowsClient.common_folder_path(folder) @@ -2177,7 +2715,7 @@ def test_common_folder_path(): def test_parse_common_folder_path(): expected = { - "folder": "clam", + "folder": "nautilus", } path = FlowsClient.common_folder_path(**expected) @@ -2187,7 +2725,7 @@ def test_parse_common_folder_path(): def test_common_organization_path(): - organization = "whelk" + organization = "scallop" expected = "organizations/{organization}".format(organization=organization,) actual = FlowsClient.common_organization_path(organization) @@ -2196,7 +2734,7 @@ def test_common_organization_path(): def test_parse_common_organization_path(): expected = { - "organization": "octopus", + "organization": "abalone", } path = FlowsClient.common_organization_path(**expected) @@ -2206,7 +2744,7 @@ def test_parse_common_organization_path(): def test_common_project_path(): - project = "oyster" + project = "squid" expected = "projects/{project}".format(project=project,) actual = FlowsClient.common_project_path(project) @@ -2215,7 +2753,7 @@ def test_common_project_path(): def test_parse_common_project_path(): expected = { - "project": "nudibranch", + "project": "clam", } path = FlowsClient.common_project_path(**expected) @@ -2225,8 +2763,8 @@ def test_parse_common_project_path(): def test_common_location_path(): - project = "cuttlefish" - location = "mussel" + project = "whelk" + location = "octopus" expected = "projects/{project}/locations/{location}".format( project=project, location=location, @@ -2237,8 +2775,8 @@ def test_common_location_path(): def test_parse_common_location_path(): expected = { - "project": "winkle", - "location": "nautilus", + "project": "oyster", + "location": "nudibranch", } path = FlowsClient.common_location_path(**expected) diff --git a/tests/unit/gapic/dialogflowcx_v3beta1/test_intents.py b/tests/unit/gapic/dialogflowcx_v3beta1/test_intents.py index 4bfab502..38f590c6 100644 --- a/tests/unit/gapic/dialogflowcx_v3beta1/test_intents.py +++ b/tests/unit/gapic/dialogflowcx_v3beta1/test_intents.py @@ -80,7 +80,22 @@ def test__get_default_mtls_endpoint(): assert IntentsClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi -@pytest.mark.parametrize("client_class", [IntentsClient, IntentsAsyncClient]) +@pytest.mark.parametrize("client_class", [IntentsClient, IntentsAsyncClient,]) +def test_intents_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 == "dialogflow.googleapis.com:443" + + +@pytest.mark.parametrize("client_class", [IntentsClient, IntentsAsyncClient,]) def test_intents_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() with mock.patch.object( @@ -89,16 +104,21 @@ def test_intents_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 == "dialogflow.googleapis.com:443" def test_intents_client_get_transport_class(): transport = IntentsClient.get_transport_class() - assert transport == transports.IntentsGrpcTransport + available_transports = [ + transports.IntentsGrpcTransport, + ] + assert transport in available_transports transport = IntentsClient.get_transport_class("grpc") assert transport == transports.IntentsGrpcTransport @@ -139,7 +159,7 @@ def test_intents_client_client_options(client_class, transport_class, transport_ 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, ) @@ -155,7 +175,7 @@ def test_intents_client_client_options(client_class, transport_class, transport_ 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, ) @@ -171,7 +191,7 @@ def test_intents_client_client_options(client_class, transport_class, transport_ 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, ) @@ -199,7 +219,7 @@ def test_intents_client_client_options(client_class, transport_class, transport_ 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, ) @@ -246,29 +266,25 @@ def test_intents_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. @@ -277,66 +293,53 @@ def test_intents_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", @@ -358,7 +361,7 @@ def test_intents_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, ) @@ -384,7 +387,7 @@ def test_intents_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, ) @@ -401,7 +404,7 @@ def test_intents_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, ) @@ -442,6 +445,22 @@ def test_list_intents_from_dict(): test_list_intents(request_type=dict) +def test_list_intents_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 = IntentsClient( + 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_intents), "__call__") as call: + client.list_intents() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == intent.ListIntentsRequest() + + @pytest.mark.asyncio async def test_list_intents_async( transport: str = "grpc_asyncio", request_type=intent.ListIntentsRequest @@ -759,6 +778,22 @@ def test_get_intent_from_dict(): test_get_intent(request_type=dict) +def test_get_intent_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 = IntentsClient( + 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_intent), "__call__") as call: + client.get_intent() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == intent.GetIntentRequest() + + @pytest.mark.asyncio async def test_get_intent_async( transport: str = "grpc_asyncio", request_type=intent.GetIntentRequest @@ -974,6 +1009,22 @@ def test_create_intent_from_dict(): test_create_intent(request_type=dict) +def test_create_intent_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 = IntentsClient( + 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_intent), "__call__") as call: + client.create_intent() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_intent.CreateIntentRequest() + + @pytest.mark.asyncio async def test_create_intent_async( transport: str = "grpc_asyncio", request_type=gcdc_intent.CreateIntentRequest @@ -1201,6 +1252,22 @@ def test_update_intent_from_dict(): test_update_intent(request_type=dict) +def test_update_intent_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 = IntentsClient( + 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_intent), "__call__") as call: + client.update_intent() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_intent.UpdateIntentRequest() + + @pytest.mark.asyncio async def test_update_intent_async( transport: str = "grpc_asyncio", request_type=gcdc_intent.UpdateIntentRequest @@ -1413,6 +1480,22 @@ def test_delete_intent_from_dict(): test_delete_intent(request_type=dict) +def test_delete_intent_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 = IntentsClient( + 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_intent), "__call__") as call: + client.delete_intent() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == intent.DeleteIntentRequest() + + @pytest.mark.asyncio async def test_delete_intent_async( transport: str = "grpc_asyncio", request_type=intent.DeleteIntentRequest @@ -1617,7 +1700,7 @@ def test_transport_get_channel(): @pytest.mark.parametrize( "transport_class", - [transports.IntentsGrpcTransport, transports.IntentsGrpcAsyncIOTransport], + [transports.IntentsGrpcTransport, transports.IntentsGrpcAsyncIOTransport,], ) def test_transport_adc(transport_class): # Test default credentials are used if not provided. @@ -1730,6 +1813,51 @@ def test_intents_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [transports.IntentsGrpcTransport, transports.IntentsGrpcAsyncIOTransport], +) +def test_intents_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/dialogflow", + ), + 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_intents_host_no_port(): client = IntentsClient( credentials=credentials.AnonymousCredentials(), @@ -1751,7 +1879,7 @@ def test_intents_host_with_port(): def test_intents_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.IntentsGrpcTransport( @@ -1763,7 +1891,7 @@ def test_intents_grpc_transport_channel(): def test_intents_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.IntentsGrpcAsyncIOTransport( @@ -1774,6 +1902,8 @@ def test_intents_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.IntentsGrpcTransport, transports.IntentsGrpcAsyncIOTransport], @@ -1783,7 +1913,7 @@ def test_intents_transport_channel_mtls_with_client_cert_source(transport_class) "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 @@ -1824,6 +1954,8 @@ def test_intents_transport_channel_mtls_with_client_cert_source(transport_class) 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.IntentsGrpcTransport, transports.IntentsGrpcAsyncIOTransport], @@ -1836,7 +1968,7 @@ def test_intents_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/dialogflowcx_v3beta1/test_pages.py b/tests/unit/gapic/dialogflowcx_v3beta1/test_pages.py index dc622e71..cf613997 100644 --- a/tests/unit/gapic/dialogflowcx_v3beta1/test_pages.py +++ b/tests/unit/gapic/dialogflowcx_v3beta1/test_pages.py @@ -83,7 +83,22 @@ def test__get_default_mtls_endpoint(): assert PagesClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi -@pytest.mark.parametrize("client_class", [PagesClient, PagesAsyncClient]) +@pytest.mark.parametrize("client_class", [PagesClient, PagesAsyncClient,]) +def test_pages_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 == "dialogflow.googleapis.com:443" + + +@pytest.mark.parametrize("client_class", [PagesClient, PagesAsyncClient,]) def test_pages_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() with mock.patch.object( @@ -92,16 +107,21 @@ def test_pages_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 == "dialogflow.googleapis.com:443" def test_pages_client_get_transport_class(): transport = PagesClient.get_transport_class() - assert transport == transports.PagesGrpcTransport + available_transports = [ + transports.PagesGrpcTransport, + ] + assert transport in available_transports transport = PagesClient.get_transport_class("grpc") assert transport == transports.PagesGrpcTransport @@ -142,7 +162,7 @@ def test_pages_client_client_options(client_class, transport_class, transport_na 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, ) @@ -158,7 +178,7 @@ def test_pages_client_client_options(client_class, transport_class, transport_na 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, ) @@ -174,7 +194,7 @@ def test_pages_client_client_options(client_class, transport_class, transport_na 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, ) @@ -202,7 +222,7 @@ def test_pages_client_client_options(client_class, transport_class, transport_na 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, ) @@ -249,29 +269,25 @@ def test_pages_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. @@ -280,66 +296,53 @@ def test_pages_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", @@ -361,7 +364,7 @@ def test_pages_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, ) @@ -387,7 +390,7 @@ def test_pages_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, ) @@ -404,7 +407,7 @@ def test_pages_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, ) @@ -445,6 +448,22 @@ def test_list_pages_from_dict(): test_list_pages(request_type=dict) +def test_list_pages_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 = PagesClient( + 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_pages), "__call__") as call: + client.list_pages() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == page.ListPagesRequest() + + @pytest.mark.asyncio async def test_list_pages_async( transport: str = "grpc_asyncio", request_type=page.ListPagesRequest @@ -744,6 +763,22 @@ def test_get_page_from_dict(): test_get_page(request_type=dict) +def test_get_page_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 = PagesClient( + 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_page), "__call__") as call: + client.get_page() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == page.GetPageRequest() + + @pytest.mark.asyncio async def test_get_page_async( transport: str = "grpc_asyncio", request_type=page.GetPageRequest @@ -945,6 +980,22 @@ def test_create_page_from_dict(): test_create_page(request_type=dict) +def test_create_page_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 = PagesClient( + 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_page), "__call__") as call: + client.create_page() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_page.CreatePageRequest() + + @pytest.mark.asyncio async def test_create_page_async( transport: str = "grpc_asyncio", request_type=gcdc_page.CreatePageRequest @@ -1158,6 +1209,22 @@ def test_update_page_from_dict(): test_update_page(request_type=dict) +def test_update_page_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 = PagesClient( + 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_page), "__call__") as call: + client.update_page() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_page.UpdatePageRequest() + + @pytest.mark.asyncio async def test_update_page_async( transport: str = "grpc_asyncio", request_type=gcdc_page.UpdatePageRequest @@ -1362,6 +1429,22 @@ def test_delete_page_from_dict(): test_delete_page(request_type=dict) +def test_delete_page_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 = PagesClient( + 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_page), "__call__") as call: + client.delete_page() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == page.DeletePageRequest() + + @pytest.mark.asyncio async def test_delete_page_async( transport: str = "grpc_asyncio", request_type=page.DeletePageRequest @@ -1566,7 +1649,7 @@ def test_transport_get_channel(): @pytest.mark.parametrize( "transport_class", - [transports.PagesGrpcTransport, transports.PagesGrpcAsyncIOTransport], + [transports.PagesGrpcTransport, transports.PagesGrpcAsyncIOTransport,], ) def test_transport_adc(transport_class): # Test default credentials are used if not provided. @@ -1679,6 +1762,51 @@ def test_pages_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [transports.PagesGrpcTransport, transports.PagesGrpcAsyncIOTransport], +) +def test_pages_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/dialogflow", + ), + 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_pages_host_no_port(): client = PagesClient( credentials=credentials.AnonymousCredentials(), @@ -1700,7 +1828,7 @@ def test_pages_host_with_port(): def test_pages_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.PagesGrpcTransport(host="squid.clam.whelk", channel=channel,) @@ -1710,7 +1838,7 @@ def test_pages_grpc_transport_channel(): def test_pages_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.PagesGrpcAsyncIOTransport( @@ -1721,6 +1849,8 @@ def test_pages_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.PagesGrpcTransport, transports.PagesGrpcAsyncIOTransport], @@ -1730,7 +1860,7 @@ def test_pages_transport_channel_mtls_with_client_cert_source(transport_class): "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 @@ -1771,6 +1901,8 @@ def test_pages_transport_channel_mtls_with_client_cert_source(transport_class): 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.PagesGrpcTransport, transports.PagesGrpcAsyncIOTransport], @@ -1783,7 +1915,7 @@ def test_pages_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/dialogflowcx_v3beta1/test_security_settings_service.py b/tests/unit/gapic/dialogflowcx_v3beta1/test_security_settings_service.py index 42abad67..11ac3d07 100644 --- a/tests/unit/gapic/dialogflowcx_v3beta1/test_security_settings_service.py +++ b/tests/unit/gapic/dialogflowcx_v3beta1/test_security_settings_service.py @@ -96,7 +96,24 @@ def test__get_default_mtls_endpoint(): @pytest.mark.parametrize( - "client_class", [SecuritySettingsServiceClient, SecuritySettingsServiceAsyncClient] + "client_class", [SecuritySettingsServiceClient, SecuritySettingsServiceAsyncClient,] +) +def test_security_settings_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 == "dialogflow.googleapis.com:443" + + +@pytest.mark.parametrize( + "client_class", [SecuritySettingsServiceClient, SecuritySettingsServiceAsyncClient,] ) def test_security_settings_service_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() @@ -106,16 +123,21 @@ def test_security_settings_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 == "dialogflow.googleapis.com:443" def test_security_settings_service_client_get_transport_class(): transport = SecuritySettingsServiceClient.get_transport_class() - assert transport == transports.SecuritySettingsServiceGrpcTransport + available_transports = [ + transports.SecuritySettingsServiceGrpcTransport, + ] + assert transport in available_transports transport = SecuritySettingsServiceClient.get_transport_class("grpc") assert transport == transports.SecuritySettingsServiceGrpcTransport @@ -170,7 +192,7 @@ def test_security_settings_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, ) @@ -186,7 +208,7 @@ def test_security_settings_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, ) @@ -202,7 +224,7 @@ def test_security_settings_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, ) @@ -230,7 +252,7 @@ def test_security_settings_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, ) @@ -291,29 +313,25 @@ def test_security_settings_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. @@ -322,66 +340,53 @@ def test_security_settings_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", @@ -411,7 +416,7 @@ def test_security_settings_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, ) @@ -445,7 +450,7 @@ def test_security_settings_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, ) @@ -464,7 +469,7 @@ def test_security_settings_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, ) @@ -536,6 +541,24 @@ def test_create_security_settings_from_dict(): test_create_security_settings(request_type=dict) +def test_create_security_settings_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 = SecuritySettingsServiceClient( + 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_security_settings), "__call__" + ) as call: + client.create_security_settings() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_security_settings.CreateSecuritySettingsRequest() + + @pytest.mark.asyncio async def test_create_security_settings_async( transport: str = "grpc_asyncio", @@ -833,6 +856,24 @@ def test_get_security_settings_from_dict(): test_get_security_settings(request_type=dict) +def test_get_security_settings_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 = SecuritySettingsServiceClient( + 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_security_settings), "__call__" + ) as call: + client.get_security_settings() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == security_settings.GetSecuritySettingsRequest() + + @pytest.mark.asyncio async def test_get_security_settings_async( transport: str = "grpc_asyncio", @@ -1105,6 +1146,24 @@ def test_update_security_settings_from_dict(): test_update_security_settings(request_type=dict) +def test_update_security_settings_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 = SecuritySettingsServiceClient( + 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_security_settings), "__call__" + ) as call: + client.update_security_settings() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_security_settings.UpdateSecuritySettingsRequest() + + @pytest.mark.asyncio async def test_update_security_settings_async( transport: str = "grpc_asyncio", @@ -1382,6 +1441,24 @@ def test_list_security_settings_from_dict(): test_list_security_settings(request_type=dict) +def test_list_security_settings_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 = SecuritySettingsServiceClient( + 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_security_settings), "__call__" + ) as call: + client.list_security_settings() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == security_settings.ListSecuritySettingsRequest() + + @pytest.mark.asyncio async def test_list_security_settings_async( transport: str = "grpc_asyncio", @@ -1776,6 +1853,24 @@ def test_delete_security_settings_from_dict(): test_delete_security_settings(request_type=dict) +def test_delete_security_settings_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 = SecuritySettingsServiceClient( + 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_security_settings), "__call__" + ) as call: + client.delete_security_settings() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == security_settings.DeleteSecuritySettingsRequest() + + @pytest.mark.asyncio async def test_delete_security_settings_async( transport: str = "grpc_asyncio", @@ -2123,6 +2218,56 @@ def test_security_settings_service_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [ + transports.SecuritySettingsServiceGrpcTransport, + transports.SecuritySettingsServiceGrpcAsyncIOTransport, + ], +) +def test_security_settings_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/dialogflow", + ), + 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_security_settings_service_host_no_port(): client = SecuritySettingsServiceClient( credentials=credentials.AnonymousCredentials(), @@ -2144,7 +2289,7 @@ def test_security_settings_service_host_with_port(): def test_security_settings_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.SecuritySettingsServiceGrpcTransport( @@ -2156,7 +2301,7 @@ def test_security_settings_service_grpc_transport_channel(): def test_security_settings_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.SecuritySettingsServiceGrpcAsyncIOTransport( @@ -2167,6 +2312,8 @@ def test_security_settings_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", [ @@ -2181,7 +2328,7 @@ def test_security_settings_service_transport_channel_mtls_with_client_cert_sourc "grpc.ssl_channel_credentials", autospec=True ) as grpc_ssl_channel_cred: with mock.patch.object( - transport_class, "create_channel", autospec=True + transport_class, "create_channel" ) as grpc_create_channel: mock_ssl_cred = mock.Mock() grpc_ssl_channel_cred.return_value = mock_ssl_cred @@ -2222,6 +2369,8 @@ def test_security_settings_service_transport_channel_mtls_with_client_cert_sourc assert transport._ssl_channel_credentials == mock_ssl_cred +# Remove this test when deprecated arguments (api_mtls_endpoint, client_cert_source) are +# removed from grpc/grpc_asyncio transport constructor. @pytest.mark.parametrize( "transport_class", [ @@ -2237,7 +2386,7 @@ def test_security_settings_service_transport_channel_mtls_with_adc(transport_cla ssl_credentials=mock.PropertyMock(return_value=mock_ssl_cred), ): with mock.patch.object( - transport_class, "create_channel", autospec=True + transport_class, "create_channel" ) as grpc_create_channel: mock_grpc_channel = mock.Mock() grpc_create_channel.return_value = mock_grpc_channel diff --git a/tests/unit/gapic/dialogflowcx_v3beta1/test_session_entity_types.py b/tests/unit/gapic/dialogflowcx_v3beta1/test_session_entity_types.py index 1b7c818e..4e0c8993 100644 --- a/tests/unit/gapic/dialogflowcx_v3beta1/test_session_entity_types.py +++ b/tests/unit/gapic/dialogflowcx_v3beta1/test_session_entity_types.py @@ -95,7 +95,24 @@ def test__get_default_mtls_endpoint(): @pytest.mark.parametrize( - "client_class", [SessionEntityTypesClient, SessionEntityTypesAsyncClient] + "client_class", [SessionEntityTypesClient, SessionEntityTypesAsyncClient,] +) +def test_session_entity_types_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 == "dialogflow.googleapis.com:443" + + +@pytest.mark.parametrize( + "client_class", [SessionEntityTypesClient, SessionEntityTypesAsyncClient,] ) def test_session_entity_types_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() @@ -105,16 +122,21 @@ def test_session_entity_types_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 == "dialogflow.googleapis.com:443" def test_session_entity_types_client_get_transport_class(): transport = SessionEntityTypesClient.get_transport_class() - assert transport == transports.SessionEntityTypesGrpcTransport + available_transports = [ + transports.SessionEntityTypesGrpcTransport, + ] + assert transport in available_transports transport = SessionEntityTypesClient.get_transport_class("grpc") assert transport == transports.SessionEntityTypesGrpcTransport @@ -165,7 +187,7 @@ def test_session_entity_types_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 +203,7 @@ def test_session_entity_types_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 +219,7 @@ def test_session_entity_types_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 +247,7 @@ def test_session_entity_types_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, ) @@ -286,29 +308,25 @@ def test_session_entity_types_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. @@ -317,66 +335,53 @@ def test_session_entity_types_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", @@ -402,7 +407,7 @@ def test_session_entity_types_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, ) @@ -432,7 +437,7 @@ def test_session_entity_types_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, ) @@ -451,7 +456,7 @@ def test_session_entity_types_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, ) @@ -497,6 +502,24 @@ def test_list_session_entity_types_from_dict(): test_list_session_entity_types(request_type=dict) +def test_list_session_entity_types_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 = SessionEntityTypesClient( + 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_session_entity_types), "__call__" + ) as call: + client.list_session_entity_types() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == session_entity_type.ListSessionEntityTypesRequest() + + @pytest.mark.asyncio async def test_list_session_entity_types_async( transport: str = "grpc_asyncio", @@ -896,6 +919,24 @@ def test_get_session_entity_type_from_dict(): test_get_session_entity_type(request_type=dict) +def test_get_session_entity_type_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 = SessionEntityTypesClient( + 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_session_entity_type), "__call__" + ) as call: + client.get_session_entity_type() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == session_entity_type.GetSessionEntityTypeRequest() + + @pytest.mark.asyncio async def test_get_session_entity_type_async( transport: str = "grpc_asyncio", @@ -1123,6 +1164,24 @@ def test_create_session_entity_type_from_dict(): test_create_session_entity_type(request_type=dict) +def test_create_session_entity_type_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 = SessionEntityTypesClient( + 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_session_entity_type), "__call__" + ) as call: + client.create_session_entity_type() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_session_entity_type.CreateSessionEntityTypeRequest() + + @pytest.mark.asyncio async def test_create_session_entity_type_async( transport: str = "grpc_asyncio", @@ -1380,6 +1439,24 @@ def test_update_session_entity_type_from_dict(): test_update_session_entity_type(request_type=dict) +def test_update_session_entity_type_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 = SessionEntityTypesClient( + 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_session_entity_type), "__call__" + ) as call: + client.update_session_entity_type() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_session_entity_type.UpdateSessionEntityTypeRequest() + + @pytest.mark.asyncio async def test_update_session_entity_type_async( transport: str = "grpc_asyncio", @@ -1632,6 +1709,24 @@ def test_delete_session_entity_type_from_dict(): test_delete_session_entity_type(request_type=dict) +def test_delete_session_entity_type_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 = SessionEntityTypesClient( + 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_session_entity_type), "__call__" + ) as call: + client.delete_session_entity_type() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == session_entity_type.DeleteSessionEntityTypeRequest() + + @pytest.mark.asyncio async def test_delete_session_entity_type_async( transport: str = "grpc_asyncio", @@ -1969,6 +2064,56 @@ def test_session_entity_types_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [ + transports.SessionEntityTypesGrpcTransport, + transports.SessionEntityTypesGrpcAsyncIOTransport, + ], +) +def test_session_entity_types_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/dialogflow", + ), + 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_session_entity_types_host_no_port(): client = SessionEntityTypesClient( credentials=credentials.AnonymousCredentials(), @@ -1990,7 +2135,7 @@ def test_session_entity_types_host_with_port(): def test_session_entity_types_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.SessionEntityTypesGrpcTransport( @@ -2002,7 +2147,7 @@ def test_session_entity_types_grpc_transport_channel(): def test_session_entity_types_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.SessionEntityTypesGrpcAsyncIOTransport( @@ -2013,6 +2158,8 @@ def test_session_entity_types_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", [ @@ -2027,7 +2174,7 @@ def test_session_entity_types_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 @@ -2068,6 +2215,8 @@ def test_session_entity_types_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", [ @@ -2083,7 +2232,7 @@ def test_session_entity_types_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/dialogflowcx_v3beta1/test_sessions.py b/tests/unit/gapic/dialogflowcx_v3beta1/test_sessions.py index 3091acbe..5cc69e9a 100644 --- a/tests/unit/gapic/dialogflowcx_v3beta1/test_sessions.py +++ b/tests/unit/gapic/dialogflowcx_v3beta1/test_sessions.py @@ -85,7 +85,22 @@ def test__get_default_mtls_endpoint(): assert SessionsClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi -@pytest.mark.parametrize("client_class", [SessionsClient, SessionsAsyncClient]) +@pytest.mark.parametrize("client_class", [SessionsClient, SessionsAsyncClient,]) +def test_sessions_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 == "dialogflow.googleapis.com:443" + + +@pytest.mark.parametrize("client_class", [SessionsClient, SessionsAsyncClient,]) def test_sessions_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() with mock.patch.object( @@ -94,16 +109,21 @@ def test_sessions_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 == "dialogflow.googleapis.com:443" def test_sessions_client_get_transport_class(): transport = SessionsClient.get_transport_class() - assert transport == transports.SessionsGrpcTransport + available_transports = [ + transports.SessionsGrpcTransport, + ] + assert transport in available_transports transport = SessionsClient.get_transport_class("grpc") assert transport == transports.SessionsGrpcTransport @@ -146,7 +166,7 @@ def test_sessions_client_client_options(client_class, transport_class, transport 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, ) @@ -162,7 +182,7 @@ def test_sessions_client_client_options(client_class, transport_class, transport 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, ) @@ -178,7 +198,7 @@ def test_sessions_client_client_options(client_class, transport_class, transport 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, ) @@ -206,7 +226,7 @@ def test_sessions_client_client_options(client_class, transport_class, transport 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, ) @@ -255,29 +275,25 @@ def test_sessions_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. @@ -286,66 +302,53 @@ def test_sessions_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", @@ -367,7 +370,7 @@ def test_sessions_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, ) @@ -393,7 +396,7 @@ def test_sessions_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, ) @@ -410,7 +413,7 @@ def test_sessions_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, ) @@ -455,6 +458,22 @@ def test_detect_intent_from_dict(): test_detect_intent(request_type=dict) +def test_detect_intent_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 = SessionsClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.detect_intent), "__call__") as call: + client.detect_intent() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == session.DetectIntentRequest() + + @pytest.mark.asyncio async def test_detect_intent_async( transport: str = "grpc_asyncio", request_type=session.DetectIntentRequest @@ -658,6 +677,22 @@ def test_match_intent_from_dict(): test_match_intent(request_type=dict) +def test_match_intent_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 = SessionsClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.match_intent), "__call__") as call: + client.match_intent() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == session.MatchIntentRequest() + + @pytest.mark.asyncio async def test_match_intent_async( transport: str = "grpc_asyncio", request_type=session.MatchIntentRequest @@ -784,6 +819,22 @@ def test_fulfill_intent_from_dict(): test_fulfill_intent(request_type=dict) +def test_fulfill_intent_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 = SessionsClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.fulfill_intent), "__call__") as call: + client.fulfill_intent() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == session.FulfillIntentRequest() + + @pytest.mark.asyncio async def test_fulfill_intent_async( transport: str = "grpc_asyncio", request_type=session.FulfillIntentRequest @@ -939,7 +990,7 @@ def test_transport_get_channel(): @pytest.mark.parametrize( "transport_class", - [transports.SessionsGrpcTransport, transports.SessionsGrpcAsyncIOTransport], + [transports.SessionsGrpcTransport, transports.SessionsGrpcAsyncIOTransport,], ) def test_transport_adc(transport_class): # Test default credentials are used if not provided. @@ -1051,6 +1102,51 @@ def test_sessions_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [transports.SessionsGrpcTransport, transports.SessionsGrpcAsyncIOTransport], +) +def test_sessions_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/dialogflow", + ), + 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_sessions_host_no_port(): client = SessionsClient( credentials=credentials.AnonymousCredentials(), @@ -1072,7 +1168,7 @@ def test_sessions_host_with_port(): def test_sessions_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.SessionsGrpcTransport( @@ -1084,7 +1180,7 @@ def test_sessions_grpc_transport_channel(): def test_sessions_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.SessionsGrpcAsyncIOTransport( @@ -1095,6 +1191,8 @@ def test_sessions_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.SessionsGrpcTransport, transports.SessionsGrpcAsyncIOTransport], @@ -1104,7 +1202,7 @@ def test_sessions_transport_channel_mtls_with_client_cert_source(transport_class "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 @@ -1145,6 +1243,8 @@ def test_sessions_transport_channel_mtls_with_client_cert_source(transport_class 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.SessionsGrpcTransport, transports.SessionsGrpcAsyncIOTransport], @@ -1157,7 +1257,7 @@ def test_sessions_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/dialogflowcx_v3beta1/test_test_cases.py b/tests/unit/gapic/dialogflowcx_v3beta1/test_test_cases.py new file mode 100644 index 00000000..efe04685 --- /dev/null +++ b/tests/unit/gapic/dialogflowcx_v3beta1/test_test_cases.py @@ -0,0 +1,3630 @@ +# -*- 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. +# + +import os +import mock + +import grpc +from grpc.experimental import aio +import math +import pytest +from proto.marshal.rules.dates import DurationRule, TimestampRule + +from google import auth +from google.api_core import client_options +from google.api_core import exceptions +from google.api_core import future +from google.api_core import gapic_v1 +from google.api_core import grpc_helpers +from google.api_core import grpc_helpers_async +from google.api_core import operation_async # type: ignore +from google.api_core import operations_v1 +from google.auth import credentials +from google.auth.exceptions import MutualTLSChannelError +from google.cloud.dialogflowcx_v3beta1.services.test_cases import TestCasesAsyncClient +from google.cloud.dialogflowcx_v3beta1.services.test_cases import TestCasesClient +from google.cloud.dialogflowcx_v3beta1.services.test_cases import pagers +from google.cloud.dialogflowcx_v3beta1.services.test_cases import transports +from google.cloud.dialogflowcx_v3beta1.types import audio_config +from google.cloud.dialogflowcx_v3beta1.types import fulfillment +from google.cloud.dialogflowcx_v3beta1.types import intent +from google.cloud.dialogflowcx_v3beta1.types import page +from google.cloud.dialogflowcx_v3beta1.types import response_message +from google.cloud.dialogflowcx_v3beta1.types import session +from google.cloud.dialogflowcx_v3beta1.types import test_case +from google.cloud.dialogflowcx_v3beta1.types import test_case as gcdc_test_case +from google.longrunning import operations_pb2 +from google.oauth2 import service_account +from google.protobuf import any_pb2 as gp_any # type: ignore +from google.protobuf import field_mask_pb2 as field_mask # type: ignore +from google.protobuf import struct_pb2 as struct # type: ignore +from google.protobuf import timestamp_pb2 as timestamp # type: ignore +from google.rpc import status_pb2 as status # type: ignore + + +def client_cert_source_callback(): + return b"cert bytes", b"key bytes" + + +# If default endpoint is localhost, then default mtls endpoint will be the same. +# This method modifies the default endpoint so the client can produce a different +# mtls endpoint for endpoint testing purposes. +def modify_default_endpoint(client): + return ( + "foo.googleapis.com" + if ("localhost" in client.DEFAULT_ENDPOINT) + else client.DEFAULT_ENDPOINT + ) + + +def test__get_default_mtls_endpoint(): + api_endpoint = "example.googleapis.com" + api_mtls_endpoint = "example.mtls.googleapis.com" + sandbox_endpoint = "example.sandbox.googleapis.com" + sandbox_mtls_endpoint = "example.mtls.sandbox.googleapis.com" + non_googleapi = "api.example.com" + + assert TestCasesClient._get_default_mtls_endpoint(None) is None + assert TestCasesClient._get_default_mtls_endpoint(api_endpoint) == api_mtls_endpoint + assert ( + TestCasesClient._get_default_mtls_endpoint(api_mtls_endpoint) + == api_mtls_endpoint + ) + assert ( + TestCasesClient._get_default_mtls_endpoint(sandbox_endpoint) + == sandbox_mtls_endpoint + ) + assert ( + TestCasesClient._get_default_mtls_endpoint(sandbox_mtls_endpoint) + == sandbox_mtls_endpoint + ) + assert TestCasesClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi + + +@pytest.mark.parametrize("client_class", [TestCasesClient, TestCasesAsyncClient,]) +def test_test_cases_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 == "dialogflow.googleapis.com:443" + + +@pytest.mark.parametrize("client_class", [TestCasesClient, TestCasesAsyncClient,]) +def test_test_cases_client_from_service_account_file(client_class): + creds = credentials.AnonymousCredentials() + with mock.patch.object( + service_account.Credentials, "from_service_account_file" + ) as factory: + factory.return_value = creds + client = client_class.from_service_account_file("dummy/file/path.json") + 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 == "dialogflow.googleapis.com:443" + + +def test_test_cases_client_get_transport_class(): + transport = TestCasesClient.get_transport_class() + available_transports = [ + transports.TestCasesGrpcTransport, + ] + assert transport in available_transports + + transport = TestCasesClient.get_transport_class("grpc") + assert transport == transports.TestCasesGrpcTransport + + +@pytest.mark.parametrize( + "client_class,transport_class,transport_name", + [ + (TestCasesClient, transports.TestCasesGrpcTransport, "grpc"), + ( + TestCasesAsyncClient, + transports.TestCasesGrpcAsyncIOTransport, + "grpc_asyncio", + ), + ], +) +@mock.patch.object( + TestCasesClient, "DEFAULT_ENDPOINT", modify_default_endpoint(TestCasesClient) +) +@mock.patch.object( + TestCasesAsyncClient, + "DEFAULT_ENDPOINT", + modify_default_endpoint(TestCasesAsyncClient), +) +def test_test_cases_client_client_options( + client_class, transport_class, transport_name +): + # Check that if channel is provided we won't create a new one. + with mock.patch.object(TestCasesClient, "get_transport_class") as gtc: + transport = transport_class(credentials=credentials.AnonymousCredentials()) + client = client_class(transport=transport) + gtc.assert_not_called() + + # Check that if channel is provided via str we will create a new one. + with mock.patch.object(TestCasesClient, "get_transport_class") as gtc: + client = client_class(transport=transport_name) + gtc.assert_called() + + # Check the case api_endpoint is provided. + options = client_options.ClientOptions(api_endpoint="squid.clam.whelk") + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(client_options=options) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host="squid.clam.whelk", + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) + + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT is + # "never". + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}): + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class() + 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, + ) + + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT is + # "always". + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}): + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class() + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_MTLS_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) + + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT has + # unsupported value. + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "Unsupported"}): + with pytest.raises(MutualTLSChannelError): + client = client_class() + + # Check the case GOOGLE_API_USE_CLIENT_CERTIFICATE has unsupported value. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"} + ): + with pytest.raises(ValueError): + client = client_class() + + # Check the case quota_project_id is provided + options = client_options.ClientOptions(quota_project_id="octopus") + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(client_options=options) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id="octopus", + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) + + +@pytest.mark.parametrize( + "client_class,transport_class,transport_name,use_client_cert_env", + [ + (TestCasesClient, transports.TestCasesGrpcTransport, "grpc", "true"), + ( + TestCasesAsyncClient, + transports.TestCasesGrpcAsyncIOTransport, + "grpc_asyncio", + "true", + ), + (TestCasesClient, transports.TestCasesGrpcTransport, "grpc", "false"), + ( + TestCasesAsyncClient, + transports.TestCasesGrpcAsyncIOTransport, + "grpc_asyncio", + "false", + ), + ], +) +@mock.patch.object( + TestCasesClient, "DEFAULT_ENDPOINT", modify_default_endpoint(TestCasesClient) +) +@mock.patch.object( + TestCasesAsyncClient, + "DEFAULT_ENDPOINT", + modify_default_endpoint(TestCasesAsyncClient), +) +@mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "auto"}) +def test_test_cases_client_mtls_env_auto( + client_class, transport_class, transport_name, use_client_cert_env +): + # This tests the endpoint autoswitch behavior. Endpoint is autoswitched to the default + # mtls endpoint, if GOOGLE_API_USE_CLIENT_CERTIFICATE is "true" and client cert exists. + + # Check the case client_cert_source is provided. Whether client cert is used depends on + # GOOGLE_API_USE_CLIENT_CERTIFICATE value. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env} + ): + options = client_options.ClientOptions( + client_cert_source=client_cert_source_callback + ) + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(client_options=options) + + if use_client_cert_env == "false": + expected_client_cert_source = None + expected_host = client.DEFAULT_ENDPOINT + else: + expected_client_cert_source = client_cert_source_callback + expected_host = client.DEFAULT_MTLS_ENDPOINT + + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=expected_host, + scopes=None, + client_cert_source_for_mtls=expected_client_cert_source, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) + + # Check the case ADC client cert is provided. Whether client cert is used depends on + # GOOGLE_API_USE_CLIENT_CERTIFICATE value. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env} + ): + with mock.patch.object(transport_class, "__init__") as patched: + with mock.patch( + "google.auth.transport.mtls.has_default_client_cert_source", + return_value=True, + ): + with mock.patch( + "google.auth.transport.mtls.default_client_cert_source", + return_value=client_cert_source_callback, + ): + if use_client_cert_env == "false": + expected_host = client.DEFAULT_ENDPOINT + expected_client_cert_source = None + else: + expected_host = client.DEFAULT_MTLS_ENDPOINT + expected_client_cert_source = client_cert_source_callback + + patched.return_value = None + client = client_class() + 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 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", + [ + (TestCasesClient, transports.TestCasesGrpcTransport, "grpc"), + ( + TestCasesAsyncClient, + transports.TestCasesGrpcAsyncIOTransport, + "grpc_asyncio", + ), + ], +) +def test_test_cases_client_client_options_scopes( + client_class, transport_class, transport_name +): + # Check the case scopes are provided. + options = client_options.ClientOptions(scopes=["1", "2"],) + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(client_options=options) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=["1", "2"], + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) + + +@pytest.mark.parametrize( + "client_class,transport_class,transport_name", + [ + (TestCasesClient, transports.TestCasesGrpcTransport, "grpc"), + ( + TestCasesAsyncClient, + transports.TestCasesGrpcAsyncIOTransport, + "grpc_asyncio", + ), + ], +) +def test_test_cases_client_client_options_credentials_file( + client_class, transport_class, transport_name +): + # Check the case credentials file is provided. + options = client_options.ClientOptions(credentials_file="credentials.json") + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(client_options=options) + patched.assert_called_once_with( + credentials=None, + credentials_file="credentials.json", + host=client.DEFAULT_ENDPOINT, + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) + + +def test_test_cases_client_client_options_from_dict(): + with mock.patch( + "google.cloud.dialogflowcx_v3beta1.services.test_cases.transports.TestCasesGrpcTransport.__init__" + ) as grpc_transport: + grpc_transport.return_value = None + client = TestCasesClient(client_options={"api_endpoint": "squid.clam.whelk"}) + grpc_transport.assert_called_once_with( + credentials=None, + credentials_file=None, + host="squid.clam.whelk", + scopes=None, + client_cert_source_for_mtls=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) + + +def test_list_test_cases( + transport: str = "grpc", request_type=test_case.ListTestCasesRequest +): + client = TestCasesClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_test_cases), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = test_case.ListTestCasesResponse( + next_page_token="next_page_token_value", + ) + + response = client.list_test_cases(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.ListTestCasesRequest() + + # Establish that the response is the type that we expect. + + assert isinstance(response, pagers.ListTestCasesPager) + + assert response.next_page_token == "next_page_token_value" + + +def test_list_test_cases_from_dict(): + test_list_test_cases(request_type=dict) + + +def test_list_test_cases_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 = TestCasesClient( + 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_test_cases), "__call__") as call: + client.list_test_cases() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.ListTestCasesRequest() + + +@pytest.mark.asyncio +async def test_list_test_cases_async( + transport: str = "grpc_asyncio", request_type=test_case.ListTestCasesRequest +): + client = TestCasesAsyncClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_test_cases), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + test_case.ListTestCasesResponse(next_page_token="next_page_token_value",) + ) + + response = await client.list_test_cases(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.ListTestCasesRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListTestCasesAsyncPager) + + assert response.next_page_token == "next_page_token_value" + + +@pytest.mark.asyncio +async def test_list_test_cases_async_from_dict(): + await test_list_test_cases_async(request_type=dict) + + +def test_list_test_cases_field_headers(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = test_case.ListTestCasesRequest() + request.parent = "parent/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_test_cases), "__call__") as call: + call.return_value = test_case.ListTestCasesResponse() + + client.list_test_cases(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "parent=parent/value",) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_list_test_cases_field_headers_async(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = test_case.ListTestCasesRequest() + request.parent = "parent/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_test_cases), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + test_case.ListTestCasesResponse() + ) + + await client.list_test_cases(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "parent=parent/value",) in kw["metadata"] + + +def test_list_test_cases_flattened(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials(),) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_test_cases), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = test_case.ListTestCasesResponse() + + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.list_test_cases(parent="parent_value",) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0].parent == "parent_value" + + +def test_list_test_cases_flattened_error(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials(),) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_test_cases( + test_case.ListTestCasesRequest(), parent="parent_value", + ) + + +@pytest.mark.asyncio +async def test_list_test_cases_flattened_async(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_test_cases), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = test_case.ListTestCasesResponse() + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + test_case.ListTestCasesResponse() + ) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.list_test_cases(parent="parent_value",) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0].parent == "parent_value" + + +@pytest.mark.asyncio +async def test_list_test_cases_flattened_error_async(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.list_test_cases( + test_case.ListTestCasesRequest(), parent="parent_value", + ) + + +def test_list_test_cases_pager(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials,) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_test_cases), "__call__") as call: + # Set the response to a series of pages. + call.side_effect = ( + test_case.ListTestCasesResponse( + test_cases=[ + test_case.TestCase(), + test_case.TestCase(), + test_case.TestCase(), + ], + next_page_token="abc", + ), + test_case.ListTestCasesResponse(test_cases=[], next_page_token="def",), + test_case.ListTestCasesResponse( + test_cases=[test_case.TestCase(),], next_page_token="ghi", + ), + test_case.ListTestCasesResponse( + test_cases=[test_case.TestCase(), test_case.TestCase(),], + ), + RuntimeError, + ) + + metadata = () + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", ""),)), + ) + pager = client.list_test_cases(request={}) + + assert pager._metadata == metadata + + results = [i for i in pager] + assert len(results) == 6 + assert all(isinstance(i, test_case.TestCase) for i in results) + + +def test_list_test_cases_pages(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials,) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.list_test_cases), "__call__") as call: + # Set the response to a series of pages. + call.side_effect = ( + test_case.ListTestCasesResponse( + test_cases=[ + test_case.TestCase(), + test_case.TestCase(), + test_case.TestCase(), + ], + next_page_token="abc", + ), + test_case.ListTestCasesResponse(test_cases=[], next_page_token="def",), + test_case.ListTestCasesResponse( + test_cases=[test_case.TestCase(),], next_page_token="ghi", + ), + test_case.ListTestCasesResponse( + test_cases=[test_case.TestCase(), test_case.TestCase(),], + ), + RuntimeError, + ) + pages = list(client.list_test_cases(request={}).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + +@pytest.mark.asyncio +async def test_list_test_cases_async_pager(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials,) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_test_cases), "__call__", new_callable=mock.AsyncMock + ) as call: + # Set the response to a series of pages. + call.side_effect = ( + test_case.ListTestCasesResponse( + test_cases=[ + test_case.TestCase(), + test_case.TestCase(), + test_case.TestCase(), + ], + next_page_token="abc", + ), + test_case.ListTestCasesResponse(test_cases=[], next_page_token="def",), + test_case.ListTestCasesResponse( + test_cases=[test_case.TestCase(),], next_page_token="ghi", + ), + test_case.ListTestCasesResponse( + test_cases=[test_case.TestCase(), test_case.TestCase(),], + ), + RuntimeError, + ) + async_pager = await client.list_test_cases(request={},) + assert async_pager.next_page_token == "abc" + responses = [] + async for response in async_pager: + responses.append(response) + + assert len(responses) == 6 + assert all(isinstance(i, test_case.TestCase) for i in responses) + + +@pytest.mark.asyncio +async def test_list_test_cases_async_pages(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials,) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_test_cases), "__call__", new_callable=mock.AsyncMock + ) as call: + # Set the response to a series of pages. + call.side_effect = ( + test_case.ListTestCasesResponse( + test_cases=[ + test_case.TestCase(), + test_case.TestCase(), + test_case.TestCase(), + ], + next_page_token="abc", + ), + test_case.ListTestCasesResponse(test_cases=[], next_page_token="def",), + test_case.ListTestCasesResponse( + test_cases=[test_case.TestCase(),], next_page_token="ghi", + ), + test_case.ListTestCasesResponse( + test_cases=[test_case.TestCase(), test_case.TestCase(),], + ), + RuntimeError, + ) + pages = [] + async for page_ in (await client.list_test_cases(request={})).pages: + pages.append(page_) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + +def test_batch_delete_test_cases( + transport: str = "grpc", request_type=test_case.BatchDeleteTestCasesRequest +): + client = TestCasesClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.batch_delete_test_cases), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = None + + response = client.batch_delete_test_cases(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.BatchDeleteTestCasesRequest() + + # Establish that the response is the type that we expect. + assert response is None + + +def test_batch_delete_test_cases_from_dict(): + test_batch_delete_test_cases(request_type=dict) + + +def test_batch_delete_test_cases_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 = TestCasesClient( + 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_test_cases), "__call__" + ) as call: + client.batch_delete_test_cases() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.BatchDeleteTestCasesRequest() + + +@pytest.mark.asyncio +async def test_batch_delete_test_cases_async( + transport: str = "grpc_asyncio", request_type=test_case.BatchDeleteTestCasesRequest +): + client = TestCasesAsyncClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.batch_delete_test_cases), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + + response = await client.batch_delete_test_cases(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.BatchDeleteTestCasesRequest() + + # Establish that the response is the type that we expect. + assert response is None + + +@pytest.mark.asyncio +async def test_batch_delete_test_cases_async_from_dict(): + await test_batch_delete_test_cases_async(request_type=dict) + + +def test_batch_delete_test_cases_field_headers(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = test_case.BatchDeleteTestCasesRequest() + request.parent = "parent/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.batch_delete_test_cases), "__call__" + ) as call: + call.return_value = None + + client.batch_delete_test_cases(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "parent=parent/value",) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_batch_delete_test_cases_field_headers_async(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = test_case.BatchDeleteTestCasesRequest() + request.parent = "parent/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.batch_delete_test_cases), "__call__" + ) as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + + await client.batch_delete_test_cases(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "parent=parent/value",) in kw["metadata"] + + +def test_batch_delete_test_cases_flattened(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials(),) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.batch_delete_test_cases), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = None + + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.batch_delete_test_cases(parent="parent_value",) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0].parent == "parent_value" + + +def test_batch_delete_test_cases_flattened_error(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials(),) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.batch_delete_test_cases( + test_case.BatchDeleteTestCasesRequest(), parent="parent_value", + ) + + +@pytest.mark.asyncio +async def test_batch_delete_test_cases_flattened_async(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.batch_delete_test_cases), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = None + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.batch_delete_test_cases(parent="parent_value",) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0].parent == "parent_value" + + +@pytest.mark.asyncio +async def test_batch_delete_test_cases_flattened_error_async(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.batch_delete_test_cases( + test_case.BatchDeleteTestCasesRequest(), parent="parent_value", + ) + + +def test_get_test_case( + transport: str = "grpc", request_type=test_case.GetTestCaseRequest +): + client = TestCasesClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_test_case), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = test_case.TestCase( + name="name_value", + tags=["tags_value"], + display_name="display_name_value", + notes="notes_value", + ) + + response = client.get_test_case(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.GetTestCaseRequest() + + # Establish that the response is the type that we expect. + + assert isinstance(response, test_case.TestCase) + + assert response.name == "name_value" + + assert response.tags == ["tags_value"] + + assert response.display_name == "display_name_value" + + assert response.notes == "notes_value" + + +def test_get_test_case_from_dict(): + test_get_test_case(request_type=dict) + + +def test_get_test_case_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 = TestCasesClient( + 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_test_case), "__call__") as call: + client.get_test_case() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.GetTestCaseRequest() + + +@pytest.mark.asyncio +async def test_get_test_case_async( + transport: str = "grpc_asyncio", request_type=test_case.GetTestCaseRequest +): + client = TestCasesAsyncClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_test_case), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + test_case.TestCase( + name="name_value", + tags=["tags_value"], + display_name="display_name_value", + notes="notes_value", + ) + ) + + response = await client.get_test_case(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.GetTestCaseRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, test_case.TestCase) + + assert response.name == "name_value" + + assert response.tags == ["tags_value"] + + assert response.display_name == "display_name_value" + + assert response.notes == "notes_value" + + +@pytest.mark.asyncio +async def test_get_test_case_async_from_dict(): + await test_get_test_case_async(request_type=dict) + + +def test_get_test_case_field_headers(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = test_case.GetTestCaseRequest() + request.name = "name/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_test_case), "__call__") as call: + call.return_value = test_case.TestCase() + + client.get_test_case(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "name=name/value",) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_get_test_case_field_headers_async(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = test_case.GetTestCaseRequest() + request.name = "name/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_test_case), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(test_case.TestCase()) + + await client.get_test_case(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "name=name/value",) in kw["metadata"] + + +def test_get_test_case_flattened(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials(),) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_test_case), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = test_case.TestCase() + + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.get_test_case(name="name_value",) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0].name == "name_value" + + +def test_get_test_case_flattened_error(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials(),) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.get_test_case( + test_case.GetTestCaseRequest(), name="name_value", + ) + + +@pytest.mark.asyncio +async def test_get_test_case_flattened_async(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.get_test_case), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = test_case.TestCase() + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(test_case.TestCase()) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.get_test_case(name="name_value",) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0].name == "name_value" + + +@pytest.mark.asyncio +async def test_get_test_case_flattened_error_async(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.get_test_case( + test_case.GetTestCaseRequest(), name="name_value", + ) + + +def test_create_test_case( + transport: str = "grpc", request_type=gcdc_test_case.CreateTestCaseRequest +): + client = TestCasesClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.create_test_case), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = gcdc_test_case.TestCase( + name="name_value", + tags=["tags_value"], + display_name="display_name_value", + notes="notes_value", + ) + + response = client.create_test_case(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_test_case.CreateTestCaseRequest() + + # Establish that the response is the type that we expect. + + assert isinstance(response, gcdc_test_case.TestCase) + + assert response.name == "name_value" + + assert response.tags == ["tags_value"] + + assert response.display_name == "display_name_value" + + assert response.notes == "notes_value" + + +def test_create_test_case_from_dict(): + test_create_test_case(request_type=dict) + + +def test_create_test_case_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 = TestCasesClient( + 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_test_case), "__call__") as call: + client.create_test_case() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_test_case.CreateTestCaseRequest() + + +@pytest.mark.asyncio +async def test_create_test_case_async( + transport: str = "grpc_asyncio", request_type=gcdc_test_case.CreateTestCaseRequest +): + client = TestCasesAsyncClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.create_test_case), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + gcdc_test_case.TestCase( + name="name_value", + tags=["tags_value"], + display_name="display_name_value", + notes="notes_value", + ) + ) + + response = await client.create_test_case(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_test_case.CreateTestCaseRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_test_case.TestCase) + + assert response.name == "name_value" + + assert response.tags == ["tags_value"] + + assert response.display_name == "display_name_value" + + assert response.notes == "notes_value" + + +@pytest.mark.asyncio +async def test_create_test_case_async_from_dict(): + await test_create_test_case_async(request_type=dict) + + +def test_create_test_case_field_headers(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = gcdc_test_case.CreateTestCaseRequest() + request.parent = "parent/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.create_test_case), "__call__") as call: + call.return_value = gcdc_test_case.TestCase() + + client.create_test_case(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "parent=parent/value",) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_create_test_case_field_headers_async(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = gcdc_test_case.CreateTestCaseRequest() + request.parent = "parent/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.create_test_case), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + gcdc_test_case.TestCase() + ) + + await client.create_test_case(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "parent=parent/value",) in kw["metadata"] + + +def test_create_test_case_flattened(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials(),) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.create_test_case), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = gcdc_test_case.TestCase() + + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.create_test_case( + parent="parent_value", test_case=gcdc_test_case.TestCase(name="name_value"), + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0].parent == "parent_value" + + assert args[0].test_case == gcdc_test_case.TestCase(name="name_value") + + +def test_create_test_case_flattened_error(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials(),) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.create_test_case( + gcdc_test_case.CreateTestCaseRequest(), + parent="parent_value", + test_case=gcdc_test_case.TestCase(name="name_value"), + ) + + +@pytest.mark.asyncio +async def test_create_test_case_flattened_async(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.create_test_case), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = gcdc_test_case.TestCase() + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + gcdc_test_case.TestCase() + ) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.create_test_case( + parent="parent_value", test_case=gcdc_test_case.TestCase(name="name_value"), + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0].parent == "parent_value" + + assert args[0].test_case == gcdc_test_case.TestCase(name="name_value") + + +@pytest.mark.asyncio +async def test_create_test_case_flattened_error_async(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.create_test_case( + gcdc_test_case.CreateTestCaseRequest(), + parent="parent_value", + test_case=gcdc_test_case.TestCase(name="name_value"), + ) + + +def test_update_test_case( + transport: str = "grpc", request_type=gcdc_test_case.UpdateTestCaseRequest +): + client = TestCasesClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.update_test_case), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = gcdc_test_case.TestCase( + name="name_value", + tags=["tags_value"], + display_name="display_name_value", + notes="notes_value", + ) + + response = client.update_test_case(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_test_case.UpdateTestCaseRequest() + + # Establish that the response is the type that we expect. + + assert isinstance(response, gcdc_test_case.TestCase) + + assert response.name == "name_value" + + assert response.tags == ["tags_value"] + + assert response.display_name == "display_name_value" + + assert response.notes == "notes_value" + + +def test_update_test_case_from_dict(): + test_update_test_case(request_type=dict) + + +def test_update_test_case_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 = TestCasesClient( + 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_test_case), "__call__") as call: + client.update_test_case() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_test_case.UpdateTestCaseRequest() + + +@pytest.mark.asyncio +async def test_update_test_case_async( + transport: str = "grpc_asyncio", request_type=gcdc_test_case.UpdateTestCaseRequest +): + client = TestCasesAsyncClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.update_test_case), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + gcdc_test_case.TestCase( + name="name_value", + tags=["tags_value"], + display_name="display_name_value", + notes="notes_value", + ) + ) + + response = await client.update_test_case(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_test_case.UpdateTestCaseRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, gcdc_test_case.TestCase) + + assert response.name == "name_value" + + assert response.tags == ["tags_value"] + + assert response.display_name == "display_name_value" + + assert response.notes == "notes_value" + + +@pytest.mark.asyncio +async def test_update_test_case_async_from_dict(): + await test_update_test_case_async(request_type=dict) + + +def test_update_test_case_field_headers(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = gcdc_test_case.UpdateTestCaseRequest() + request.test_case.name = "test_case.name/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.update_test_case), "__call__") as call: + call.return_value = gcdc_test_case.TestCase() + + client.update_test_case(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "test_case.name=test_case.name/value",) in kw[ + "metadata" + ] + + +@pytest.mark.asyncio +async def test_update_test_case_field_headers_async(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = gcdc_test_case.UpdateTestCaseRequest() + request.test_case.name = "test_case.name/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.update_test_case), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + gcdc_test_case.TestCase() + ) + + await client.update_test_case(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "test_case.name=test_case.name/value",) in kw[ + "metadata" + ] + + +def test_update_test_case_flattened(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials(),) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.update_test_case), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = gcdc_test_case.TestCase() + + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.update_test_case( + test_case=gcdc_test_case.TestCase(name="name_value"), + update_mask=field_mask.FieldMask(paths=["paths_value"]), + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0].test_case == gcdc_test_case.TestCase(name="name_value") + + assert args[0].update_mask == field_mask.FieldMask(paths=["paths_value"]) + + +def test_update_test_case_flattened_error(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials(),) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.update_test_case( + gcdc_test_case.UpdateTestCaseRequest(), + test_case=gcdc_test_case.TestCase(name="name_value"), + update_mask=field_mask.FieldMask(paths=["paths_value"]), + ) + + +@pytest.mark.asyncio +async def test_update_test_case_flattened_async(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.update_test_case), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = gcdc_test_case.TestCase() + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + gcdc_test_case.TestCase() + ) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.update_test_case( + test_case=gcdc_test_case.TestCase(name="name_value"), + update_mask=field_mask.FieldMask(paths=["paths_value"]), + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0].test_case == gcdc_test_case.TestCase(name="name_value") + + assert args[0].update_mask == field_mask.FieldMask(paths=["paths_value"]) + + +@pytest.mark.asyncio +async def test_update_test_case_flattened_error_async(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.update_test_case( + gcdc_test_case.UpdateTestCaseRequest(), + test_case=gcdc_test_case.TestCase(name="name_value"), + update_mask=field_mask.FieldMask(paths=["paths_value"]), + ) + + +def test_run_test_case( + transport: str = "grpc", request_type=test_case.RunTestCaseRequest +): + client = TestCasesClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.run_test_case), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation(name="operations/spam") + + response = client.run_test_case(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.RunTestCaseRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, future.Future) + + +def test_run_test_case_from_dict(): + test_run_test_case(request_type=dict) + + +def test_run_test_case_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 = TestCasesClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.run_test_case), "__call__") as call: + client.run_test_case() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.RunTestCaseRequest() + + +@pytest.mark.asyncio +async def test_run_test_case_async( + transport: str = "grpc_asyncio", request_type=test_case.RunTestCaseRequest +): + client = TestCasesAsyncClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.run_test_case), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation(name="operations/spam") + ) + + response = await client.run_test_case(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.RunTestCaseRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, future.Future) + + +@pytest.mark.asyncio +async def test_run_test_case_async_from_dict(): + await test_run_test_case_async(request_type=dict) + + +def test_run_test_case_field_headers(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = test_case.RunTestCaseRequest() + request.name = "name/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.run_test_case), "__call__") as call: + call.return_value = operations_pb2.Operation(name="operations/op") + + client.run_test_case(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "name=name/value",) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_run_test_case_field_headers_async(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = test_case.RunTestCaseRequest() + request.name = "name/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.run_test_case), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation(name="operations/op") + ) + + await client.run_test_case(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "name=name/value",) in kw["metadata"] + + +def test_batch_run_test_cases( + transport: str = "grpc", request_type=test_case.BatchRunTestCasesRequest +): + client = TestCasesClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.batch_run_test_cases), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation(name="operations/spam") + + response = client.batch_run_test_cases(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.BatchRunTestCasesRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, future.Future) + + +def test_batch_run_test_cases_from_dict(): + test_batch_run_test_cases(request_type=dict) + + +def test_batch_run_test_cases_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 = TestCasesClient( + 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_run_test_cases), "__call__" + ) as call: + client.batch_run_test_cases() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.BatchRunTestCasesRequest() + + +@pytest.mark.asyncio +async def test_batch_run_test_cases_async( + transport: str = "grpc_asyncio", request_type=test_case.BatchRunTestCasesRequest +): + client = TestCasesAsyncClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.batch_run_test_cases), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation(name="operations/spam") + ) + + response = await client.batch_run_test_cases(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.BatchRunTestCasesRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, future.Future) + + +@pytest.mark.asyncio +async def test_batch_run_test_cases_async_from_dict(): + await test_batch_run_test_cases_async(request_type=dict) + + +def test_batch_run_test_cases_field_headers(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = test_case.BatchRunTestCasesRequest() + request.parent = "parent/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.batch_run_test_cases), "__call__" + ) as call: + call.return_value = operations_pb2.Operation(name="operations/op") + + client.batch_run_test_cases(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "parent=parent/value",) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_batch_run_test_cases_field_headers_async(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = test_case.BatchRunTestCasesRequest() + request.parent = "parent/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.batch_run_test_cases), "__call__" + ) as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation(name="operations/op") + ) + + await client.batch_run_test_cases(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "parent=parent/value",) in kw["metadata"] + + +def test_calculate_coverage( + transport: str = "grpc", request_type=test_case.CalculateCoverageRequest +): + client = TestCasesClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.calculate_coverage), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = test_case.CalculateCoverageResponse( + agent="agent_value", + intent_coverage=test_case.IntentCoverage( + intents=[test_case.IntentCoverage.Intent(intent="intent_value")] + ), + ) + + response = client.calculate_coverage(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.CalculateCoverageRequest() + + # Establish that the response is the type that we expect. + + assert isinstance(response, test_case.CalculateCoverageResponse) + + assert response.agent == "agent_value" + + +def test_calculate_coverage_from_dict(): + test_calculate_coverage(request_type=dict) + + +def test_calculate_coverage_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 = TestCasesClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.calculate_coverage), "__call__" + ) as call: + client.calculate_coverage() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.CalculateCoverageRequest() + + +@pytest.mark.asyncio +async def test_calculate_coverage_async( + transport: str = "grpc_asyncio", request_type=test_case.CalculateCoverageRequest +): + client = TestCasesAsyncClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.calculate_coverage), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + test_case.CalculateCoverageResponse(agent="agent_value",) + ) + + response = await client.calculate_coverage(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.CalculateCoverageRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, test_case.CalculateCoverageResponse) + + assert response.agent == "agent_value" + + +@pytest.mark.asyncio +async def test_calculate_coverage_async_from_dict(): + await test_calculate_coverage_async(request_type=dict) + + +def test_calculate_coverage_field_headers(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = test_case.CalculateCoverageRequest() + request.agent = "agent/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.calculate_coverage), "__call__" + ) as call: + call.return_value = test_case.CalculateCoverageResponse() + + client.calculate_coverage(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "agent=agent/value",) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_calculate_coverage_field_headers_async(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = test_case.CalculateCoverageRequest() + request.agent = "agent/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.calculate_coverage), "__call__" + ) as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + test_case.CalculateCoverageResponse() + ) + + await client.calculate_coverage(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "agent=agent/value",) in kw["metadata"] + + +def test_import_test_cases( + transport: str = "grpc", request_type=test_case.ImportTestCasesRequest +): + client = TestCasesClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.import_test_cases), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation(name="operations/spam") + + response = client.import_test_cases(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.ImportTestCasesRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, future.Future) + + +def test_import_test_cases_from_dict(): + test_import_test_cases(request_type=dict) + + +def test_import_test_cases_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 = TestCasesClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.import_test_cases), "__call__" + ) as call: + client.import_test_cases() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.ImportTestCasesRequest() + + +@pytest.mark.asyncio +async def test_import_test_cases_async( + transport: str = "grpc_asyncio", request_type=test_case.ImportTestCasesRequest +): + client = TestCasesAsyncClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.import_test_cases), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation(name="operations/spam") + ) + + response = await client.import_test_cases(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.ImportTestCasesRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, future.Future) + + +@pytest.mark.asyncio +async def test_import_test_cases_async_from_dict(): + await test_import_test_cases_async(request_type=dict) + + +def test_import_test_cases_field_headers(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = test_case.ImportTestCasesRequest() + request.parent = "parent/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.import_test_cases), "__call__" + ) as call: + call.return_value = operations_pb2.Operation(name="operations/op") + + client.import_test_cases(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "parent=parent/value",) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_import_test_cases_field_headers_async(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = test_case.ImportTestCasesRequest() + request.parent = "parent/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.import_test_cases), "__call__" + ) as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation(name="operations/op") + ) + + await client.import_test_cases(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "parent=parent/value",) in kw["metadata"] + + +def test_export_test_cases( + transport: str = "grpc", request_type=test_case.ExportTestCasesRequest +): + client = TestCasesClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.export_test_cases), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation(name="operations/spam") + + response = client.export_test_cases(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.ExportTestCasesRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, future.Future) + + +def test_export_test_cases_from_dict(): + test_export_test_cases(request_type=dict) + + +def test_export_test_cases_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 = TestCasesClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.export_test_cases), "__call__" + ) as call: + client.export_test_cases() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.ExportTestCasesRequest() + + +@pytest.mark.asyncio +async def test_export_test_cases_async( + transport: str = "grpc_asyncio", request_type=test_case.ExportTestCasesRequest +): + client = TestCasesAsyncClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.export_test_cases), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation(name="operations/spam") + ) + + response = await client.export_test_cases(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.ExportTestCasesRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, future.Future) + + +@pytest.mark.asyncio +async def test_export_test_cases_async_from_dict(): + await test_export_test_cases_async(request_type=dict) + + +def test_export_test_cases_field_headers(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = test_case.ExportTestCasesRequest() + request.parent = "parent/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.export_test_cases), "__call__" + ) as call: + call.return_value = operations_pb2.Operation(name="operations/op") + + client.export_test_cases(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "parent=parent/value",) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_export_test_cases_field_headers_async(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = test_case.ExportTestCasesRequest() + request.parent = "parent/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.export_test_cases), "__call__" + ) as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation(name="operations/op") + ) + + await client.export_test_cases(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "parent=parent/value",) in kw["metadata"] + + +def test_list_test_case_results( + transport: str = "grpc", request_type=test_case.ListTestCaseResultsRequest +): + client = TestCasesClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_test_case_results), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = test_case.ListTestCaseResultsResponse( + next_page_token="next_page_token_value", + ) + + response = client.list_test_case_results(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.ListTestCaseResultsRequest() + + # Establish that the response is the type that we expect. + + assert isinstance(response, pagers.ListTestCaseResultsPager) + + assert response.next_page_token == "next_page_token_value" + + +def test_list_test_case_results_from_dict(): + test_list_test_case_results(request_type=dict) + + +def test_list_test_case_results_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 = TestCasesClient( + 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_test_case_results), "__call__" + ) as call: + client.list_test_case_results() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.ListTestCaseResultsRequest() + + +@pytest.mark.asyncio +async def test_list_test_case_results_async( + transport: str = "grpc_asyncio", request_type=test_case.ListTestCaseResultsRequest +): + client = TestCasesAsyncClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_test_case_results), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + test_case.ListTestCaseResultsResponse( + next_page_token="next_page_token_value", + ) + ) + + response = await client.list_test_case_results(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0] == test_case.ListTestCaseResultsRequest() + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListTestCaseResultsAsyncPager) + + assert response.next_page_token == "next_page_token_value" + + +@pytest.mark.asyncio +async def test_list_test_case_results_async_from_dict(): + await test_list_test_case_results_async(request_type=dict) + + +def test_list_test_case_results_field_headers(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = test_case.ListTestCaseResultsRequest() + request.parent = "parent/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_test_case_results), "__call__" + ) as call: + call.return_value = test_case.ListTestCaseResultsResponse() + + client.list_test_case_results(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "parent=parent/value",) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_list_test_case_results_field_headers_async(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = test_case.ListTestCaseResultsRequest() + request.parent = "parent/value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_test_case_results), "__call__" + ) as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + test_case.ListTestCaseResultsResponse() + ) + + await client.list_test_case_results(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "parent=parent/value",) in kw["metadata"] + + +def test_list_test_case_results_flattened(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials(),) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_test_case_results), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = test_case.ListTestCaseResultsResponse() + + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.list_test_case_results(parent="parent_value",) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + + assert args[0].parent == "parent_value" + + +def test_list_test_case_results_flattened_error(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials(),) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.list_test_case_results( + test_case.ListTestCaseResultsRequest(), parent="parent_value", + ) + + +@pytest.mark.asyncio +async def test_list_test_case_results_flattened_async(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_test_case_results), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = test_case.ListTestCaseResultsResponse() + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + test_case.ListTestCaseResultsResponse() + ) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.list_test_case_results(parent="parent_value",) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + + assert args[0].parent == "parent_value" + + +@pytest.mark.asyncio +async def test_list_test_case_results_flattened_error_async(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials(),) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.list_test_case_results( + test_case.ListTestCaseResultsRequest(), parent="parent_value", + ) + + +def test_list_test_case_results_pager(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials,) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_test_case_results), "__call__" + ) as call: + # Set the response to a series of pages. + call.side_effect = ( + test_case.ListTestCaseResultsResponse( + test_case_results=[ + test_case.TestCaseResult(), + test_case.TestCaseResult(), + test_case.TestCaseResult(), + ], + next_page_token="abc", + ), + test_case.ListTestCaseResultsResponse( + test_case_results=[], next_page_token="def", + ), + test_case.ListTestCaseResultsResponse( + test_case_results=[test_case.TestCaseResult(),], next_page_token="ghi", + ), + test_case.ListTestCaseResultsResponse( + test_case_results=[ + test_case.TestCaseResult(), + test_case.TestCaseResult(), + ], + ), + RuntimeError, + ) + + metadata = () + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", ""),)), + ) + pager = client.list_test_case_results(request={}) + + assert pager._metadata == metadata + + results = [i for i in pager] + assert len(results) == 6 + assert all(isinstance(i, test_case.TestCaseResult) for i in results) + + +def test_list_test_case_results_pages(): + client = TestCasesClient(credentials=credentials.AnonymousCredentials,) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_test_case_results), "__call__" + ) as call: + # Set the response to a series of pages. + call.side_effect = ( + test_case.ListTestCaseResultsResponse( + test_case_results=[ + test_case.TestCaseResult(), + test_case.TestCaseResult(), + test_case.TestCaseResult(), + ], + next_page_token="abc", + ), + test_case.ListTestCaseResultsResponse( + test_case_results=[], next_page_token="def", + ), + test_case.ListTestCaseResultsResponse( + test_case_results=[test_case.TestCaseResult(),], next_page_token="ghi", + ), + test_case.ListTestCaseResultsResponse( + test_case_results=[ + test_case.TestCaseResult(), + test_case.TestCaseResult(), + ], + ), + RuntimeError, + ) + pages = list(client.list_test_case_results(request={}).pages) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + +@pytest.mark.asyncio +async def test_list_test_case_results_async_pager(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials,) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_test_case_results), + "__call__", + new_callable=mock.AsyncMock, + ) as call: + # Set the response to a series of pages. + call.side_effect = ( + test_case.ListTestCaseResultsResponse( + test_case_results=[ + test_case.TestCaseResult(), + test_case.TestCaseResult(), + test_case.TestCaseResult(), + ], + next_page_token="abc", + ), + test_case.ListTestCaseResultsResponse( + test_case_results=[], next_page_token="def", + ), + test_case.ListTestCaseResultsResponse( + test_case_results=[test_case.TestCaseResult(),], next_page_token="ghi", + ), + test_case.ListTestCaseResultsResponse( + test_case_results=[ + test_case.TestCaseResult(), + test_case.TestCaseResult(), + ], + ), + RuntimeError, + ) + async_pager = await client.list_test_case_results(request={},) + assert async_pager.next_page_token == "abc" + responses = [] + async for response in async_pager: + responses.append(response) + + assert len(responses) == 6 + assert all(isinstance(i, test_case.TestCaseResult) for i in responses) + + +@pytest.mark.asyncio +async def test_list_test_case_results_async_pages(): + client = TestCasesAsyncClient(credentials=credentials.AnonymousCredentials,) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.list_test_case_results), + "__call__", + new_callable=mock.AsyncMock, + ) as call: + # Set the response to a series of pages. + call.side_effect = ( + test_case.ListTestCaseResultsResponse( + test_case_results=[ + test_case.TestCaseResult(), + test_case.TestCaseResult(), + test_case.TestCaseResult(), + ], + next_page_token="abc", + ), + test_case.ListTestCaseResultsResponse( + test_case_results=[], next_page_token="def", + ), + test_case.ListTestCaseResultsResponse( + test_case_results=[test_case.TestCaseResult(),], next_page_token="ghi", + ), + test_case.ListTestCaseResultsResponse( + test_case_results=[ + test_case.TestCaseResult(), + test_case.TestCaseResult(), + ], + ), + RuntimeError, + ) + pages = [] + async for page_ in (await client.list_test_case_results(request={})).pages: + pages.append(page_) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.TestCasesGrpcTransport( + credentials=credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = TestCasesClient( + credentials=credentials.AnonymousCredentials(), transport=transport, + ) + + # It is an error to provide a credentials file and a transport instance. + transport = transports.TestCasesGrpcTransport( + credentials=credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = TestCasesClient( + client_options={"credentials_file": "credentials.json"}, + transport=transport, + ) + + # It is an error to provide scopes and a transport instance. + transport = transports.TestCasesGrpcTransport( + credentials=credentials.AnonymousCredentials(), + ) + with pytest.raises(ValueError): + client = TestCasesClient( + client_options={"scopes": ["1", "2"]}, transport=transport, + ) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.TestCasesGrpcTransport( + credentials=credentials.AnonymousCredentials(), + ) + client = TestCasesClient(transport=transport) + assert client.transport is transport + + +def test_transport_get_channel(): + # A client may be instantiated with a custom transport instance. + transport = transports.TestCasesGrpcTransport( + credentials=credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + transport = transports.TestCasesGrpcAsyncIOTransport( + credentials=credentials.AnonymousCredentials(), + ) + channel = transport.grpc_channel + assert channel + + +@pytest.mark.parametrize( + "transport_class", + [transports.TestCasesGrpcTransport, transports.TestCasesGrpcAsyncIOTransport,], +) +def test_transport_adc(transport_class): + # Test default credentials are used if not provided. + with mock.patch.object(auth, "default") as adc: + adc.return_value = (credentials.AnonymousCredentials(), None) + transport_class() + adc.assert_called_once() + + +def test_transport_grpc_default(): + # A client should use the gRPC transport by default. + client = TestCasesClient(credentials=credentials.AnonymousCredentials(),) + assert isinstance(client.transport, transports.TestCasesGrpcTransport,) + + +def test_test_cases_base_transport_error(): + # Passing both a credentials object and credentials_file should raise an error + with pytest.raises(exceptions.DuplicateCredentialArgs): + transport = transports.TestCasesTransport( + credentials=credentials.AnonymousCredentials(), + credentials_file="credentials.json", + ) + + +def test_test_cases_base_transport(): + # Instantiate the base transport. + with mock.patch( + "google.cloud.dialogflowcx_v3beta1.services.test_cases.transports.TestCasesTransport.__init__" + ) as Transport: + Transport.return_value = None + transport = transports.TestCasesTransport( + credentials=credentials.AnonymousCredentials(), + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + "list_test_cases", + "batch_delete_test_cases", + "get_test_case", + "create_test_case", + "update_test_case", + "run_test_case", + "batch_run_test_cases", + "calculate_coverage", + "import_test_cases", + "export_test_cases", + "list_test_case_results", + ) + for method in methods: + with pytest.raises(NotImplementedError): + getattr(transport, method)(request=object()) + + # Additionally, the LRO client (a property) should + # also raise NotImplementedError + with pytest.raises(NotImplementedError): + transport.operations_client + + +def test_test_cases_base_transport_with_credentials_file(): + # Instantiate the base transport with a credentials file + with mock.patch.object( + auth, "load_credentials_from_file" + ) as load_creds, mock.patch( + "google.cloud.dialogflowcx_v3beta1.services.test_cases.transports.TestCasesTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + load_creds.return_value = (credentials.AnonymousCredentials(), None) + transport = transports.TestCasesTransport( + credentials_file="credentials.json", quota_project_id="octopus", + ) + load_creds.assert_called_once_with( + "credentials.json", + scopes=( + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/dialogflow", + ), + quota_project_id="octopus", + ) + + +def test_test_cases_base_transport_with_adc(): + # Test the default credentials are used if credentials and credentials_file are None. + with mock.patch.object(auth, "default") as adc, mock.patch( + "google.cloud.dialogflowcx_v3beta1.services.test_cases.transports.TestCasesTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + adc.return_value = (credentials.AnonymousCredentials(), None) + transport = transports.TestCasesTransport() + adc.assert_called_once() + + +def test_test_cases_auth_adc(): + # If no credentials are provided, we should use ADC credentials. + with mock.patch.object(auth, "default") as adc: + adc.return_value = (credentials.AnonymousCredentials(), None) + TestCasesClient() + adc.assert_called_once_with( + scopes=( + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/dialogflow", + ), + quota_project_id=None, + ) + + +def test_test_cases_transport_auth_adc(): + # If credentials and host are not provided, the transport class should use + # ADC credentials. + with mock.patch.object(auth, "default") as adc: + adc.return_value = (credentials.AnonymousCredentials(), None) + transports.TestCasesGrpcTransport( + host="squid.clam.whelk", quota_project_id="octopus" + ) + adc.assert_called_once_with( + scopes=( + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/dialogflow", + ), + quota_project_id="octopus", + ) + + +@pytest.mark.parametrize( + "transport_class", + [transports.TestCasesGrpcTransport, transports.TestCasesGrpcAsyncIOTransport], +) +def test_test_cases_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/dialogflow", + ), + 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_test_cases_host_no_port(): + client = TestCasesClient( + credentials=credentials.AnonymousCredentials(), + client_options=client_options.ClientOptions( + api_endpoint="dialogflow.googleapis.com" + ), + ) + assert client.transport._host == "dialogflow.googleapis.com:443" + + +def test_test_cases_host_with_port(): + client = TestCasesClient( + credentials=credentials.AnonymousCredentials(), + client_options=client_options.ClientOptions( + api_endpoint="dialogflow.googleapis.com:8000" + ), + ) + assert client.transport._host == "dialogflow.googleapis.com:8000" + + +def test_test_cases_grpc_transport_channel(): + channel = grpc.secure_channel("http://localhost/", grpc.local_channel_credentials()) + + # Check that channel is used if provided. + transport = transports.TestCasesGrpcTransport( + host="squid.clam.whelk", channel=channel, + ) + assert transport.grpc_channel == channel + assert transport._host == "squid.clam.whelk:443" + assert transport._ssl_channel_credentials == None + + +def test_test_cases_grpc_asyncio_transport_channel(): + channel = aio.secure_channel("http://localhost/", grpc.local_channel_credentials()) + + # Check that channel is used if provided. + transport = transports.TestCasesGrpcAsyncIOTransport( + host="squid.clam.whelk", channel=channel, + ) + assert transport.grpc_channel == channel + assert transport._host == "squid.clam.whelk:443" + assert transport._ssl_channel_credentials == None + + +# Remove this test when deprecated arguments (api_mtls_endpoint, client_cert_source) are +# removed from grpc/grpc_asyncio transport constructor. +@pytest.mark.parametrize( + "transport_class", + [transports.TestCasesGrpcTransport, transports.TestCasesGrpcAsyncIOTransport], +) +def test_test_cases_transport_channel_mtls_with_client_cert_source(transport_class): + with mock.patch( + "grpc.ssl_channel_credentials", autospec=True + ) as grpc_ssl_channel_cred: + with mock.patch.object( + transport_class, "create_channel" + ) as grpc_create_channel: + mock_ssl_cred = mock.Mock() + grpc_ssl_channel_cred.return_value = mock_ssl_cred + + mock_grpc_channel = mock.Mock() + grpc_create_channel.return_value = mock_grpc_channel + + cred = credentials.AnonymousCredentials() + with pytest.warns(DeprecationWarning): + with mock.patch.object(auth, "default") as adc: + adc.return_value = (cred, None) + transport = transport_class( + host="squid.clam.whelk", + api_mtls_endpoint="mtls.squid.clam.whelk", + client_cert_source=client_cert_source_callback, + ) + adc.assert_called_once() + + grpc_ssl_channel_cred.assert_called_once_with( + certificate_chain=b"cert bytes", private_key=b"key bytes" + ) + grpc_create_channel.assert_called_once_with( + "mtls.squid.clam.whelk:443", + credentials=cred, + credentials_file=None, + scopes=( + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/dialogflow", + ), + ssl_credentials=mock_ssl_cred, + quota_project_id=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + assert transport.grpc_channel == mock_grpc_channel + assert transport._ssl_channel_credentials == mock_ssl_cred + + +# Remove this test when deprecated arguments (api_mtls_endpoint, client_cert_source) are +# removed from grpc/grpc_asyncio transport constructor. +@pytest.mark.parametrize( + "transport_class", + [transports.TestCasesGrpcTransport, transports.TestCasesGrpcAsyncIOTransport], +) +def test_test_cases_transport_channel_mtls_with_adc(transport_class): + mock_ssl_cred = mock.Mock() + with mock.patch.multiple( + "google.auth.transport.grpc.SslCredentials", + __init__=mock.Mock(return_value=None), + ssl_credentials=mock.PropertyMock(return_value=mock_ssl_cred), + ): + with mock.patch.object( + transport_class, "create_channel" + ) as grpc_create_channel: + mock_grpc_channel = mock.Mock() + grpc_create_channel.return_value = mock_grpc_channel + mock_cred = mock.Mock() + + with pytest.warns(DeprecationWarning): + transport = transport_class( + host="squid.clam.whelk", + credentials=mock_cred, + api_mtls_endpoint="mtls.squid.clam.whelk", + client_cert_source=None, + ) + + grpc_create_channel.assert_called_once_with( + "mtls.squid.clam.whelk:443", + credentials=mock_cred, + credentials_file=None, + scopes=( + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/dialogflow", + ), + ssl_credentials=mock_ssl_cred, + quota_project_id=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + assert transport.grpc_channel == mock_grpc_channel + + +def test_test_cases_grpc_lro_client(): + client = TestCasesClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + transport = client.transport + + # Ensure that we have a api-core operations client. + assert isinstance(transport.operations_client, operations_v1.OperationsClient,) + + # Ensure that subsequent calls to the property send the exact same object. + assert transport.operations_client is transport.operations_client + + +def test_test_cases_grpc_lro_async_client(): + client = TestCasesAsyncClient( + credentials=credentials.AnonymousCredentials(), transport="grpc_asyncio", + ) + transport = client.transport + + # Ensure that we have a api-core operations client. + assert isinstance(transport.operations_client, operations_v1.OperationsAsyncClient,) + + # Ensure that subsequent calls to the property send the exact same object. + assert transport.operations_client is transport.operations_client + + +def test_agent_path(): + project = "squid" + location = "clam" + agent = "whelk" + + expected = "projects/{project}/locations/{location}/agents/{agent}".format( + project=project, location=location, agent=agent, + ) + actual = TestCasesClient.agent_path(project, location, agent) + assert expected == actual + + +def test_parse_agent_path(): + expected = { + "project": "octopus", + "location": "oyster", + "agent": "nudibranch", + } + path = TestCasesClient.agent_path(**expected) + + # Check that the path construction is reversible. + actual = TestCasesClient.parse_agent_path(path) + assert expected == actual + + +def test_entity_type_path(): + project = "cuttlefish" + location = "mussel" + agent = "winkle" + entity_type = "nautilus" + + expected = "projects/{project}/locations/{location}/agents/{agent}/entityTypes/{entity_type}".format( + project=project, location=location, agent=agent, entity_type=entity_type, + ) + actual = TestCasesClient.entity_type_path(project, location, agent, entity_type) + assert expected == actual + + +def test_parse_entity_type_path(): + expected = { + "project": "scallop", + "location": "abalone", + "agent": "squid", + "entity_type": "clam", + } + path = TestCasesClient.entity_type_path(**expected) + + # Check that the path construction is reversible. + actual = TestCasesClient.parse_entity_type_path(path) + assert expected == actual + + +def test_environment_path(): + project = "whelk" + location = "octopus" + agent = "oyster" + environment = "nudibranch" + + expected = "projects/{project}/locations/{location}/agents/{agent}/environments/{environment}".format( + project=project, location=location, agent=agent, environment=environment, + ) + actual = TestCasesClient.environment_path(project, location, agent, environment) + assert expected == actual + + +def test_parse_environment_path(): + expected = { + "project": "cuttlefish", + "location": "mussel", + "agent": "winkle", + "environment": "nautilus", + } + path = TestCasesClient.environment_path(**expected) + + # Check that the path construction is reversible. + actual = TestCasesClient.parse_environment_path(path) + assert expected == actual + + +def test_flow_path(): + project = "scallop" + location = "abalone" + agent = "squid" + flow = "clam" + + expected = "projects/{project}/locations/{location}/agents/{agent}/flows/{flow}".format( + project=project, location=location, agent=agent, flow=flow, + ) + actual = TestCasesClient.flow_path(project, location, agent, flow) + assert expected == actual + + +def test_parse_flow_path(): + expected = { + "project": "whelk", + "location": "octopus", + "agent": "oyster", + "flow": "nudibranch", + } + path = TestCasesClient.flow_path(**expected) + + # Check that the path construction is reversible. + actual = TestCasesClient.parse_flow_path(path) + assert expected == actual + + +def test_intent_path(): + project = "cuttlefish" + location = "mussel" + agent = "winkle" + intent = "nautilus" + + expected = "projects/{project}/locations/{location}/agents/{agent}/intents/{intent}".format( + project=project, location=location, agent=agent, intent=intent, + ) + actual = TestCasesClient.intent_path(project, location, agent, intent) + assert expected == actual + + +def test_parse_intent_path(): + expected = { + "project": "scallop", + "location": "abalone", + "agent": "squid", + "intent": "clam", + } + path = TestCasesClient.intent_path(**expected) + + # Check that the path construction is reversible. + actual = TestCasesClient.parse_intent_path(path) + assert expected == actual + + +def test_page_path(): + project = "whelk" + location = "octopus" + agent = "oyster" + flow = "nudibranch" + page = "cuttlefish" + + expected = "projects/{project}/locations/{location}/agents/{agent}/flows/{flow}/pages/{page}".format( + project=project, location=location, agent=agent, flow=flow, page=page, + ) + actual = TestCasesClient.page_path(project, location, agent, flow, page) + assert expected == actual + + +def test_parse_page_path(): + expected = { + "project": "mussel", + "location": "winkle", + "agent": "nautilus", + "flow": "scallop", + "page": "abalone", + } + path = TestCasesClient.page_path(**expected) + + # Check that the path construction is reversible. + actual = TestCasesClient.parse_page_path(path) + assert expected == actual + + +def test_test_case_path(): + project = "squid" + location = "clam" + agent = "whelk" + test_case = "octopus" + + expected = "projects/{project}/locations/{location}/agents/{agent}/testCases/{test_case}".format( + project=project, location=location, agent=agent, test_case=test_case, + ) + actual = TestCasesClient.test_case_path(project, location, agent, test_case) + assert expected == actual + + +def test_parse_test_case_path(): + expected = { + "project": "oyster", + "location": "nudibranch", + "agent": "cuttlefish", + "test_case": "mussel", + } + path = TestCasesClient.test_case_path(**expected) + + # Check that the path construction is reversible. + actual = TestCasesClient.parse_test_case_path(path) + assert expected == actual + + +def test_test_case_result_path(): + project = "winkle" + location = "nautilus" + agent = "scallop" + test_case = "abalone" + result = "squid" + + expected = "projects/{project}/locations/{location}/agents/{agent}/testCases/{test_case}/results/{result}".format( + project=project, + location=location, + agent=agent, + test_case=test_case, + result=result, + ) + actual = TestCasesClient.test_case_result_path( + project, location, agent, test_case, result + ) + assert expected == actual + + +def test_parse_test_case_result_path(): + expected = { + "project": "clam", + "location": "whelk", + "agent": "octopus", + "test_case": "oyster", + "result": "nudibranch", + } + path = TestCasesClient.test_case_result_path(**expected) + + # Check that the path construction is reversible. + actual = TestCasesClient.parse_test_case_result_path(path) + assert expected == actual + + +def test_transition_route_group_path(): + project = "cuttlefish" + location = "mussel" + agent = "winkle" + flow = "nautilus" + transition_route_group = "scallop" + + expected = "projects/{project}/locations/{location}/agents/{agent}/flows/{flow}/transitionRouteGroups/{transition_route_group}".format( + project=project, + location=location, + agent=agent, + flow=flow, + transition_route_group=transition_route_group, + ) + actual = TestCasesClient.transition_route_group_path( + project, location, agent, flow, transition_route_group + ) + assert expected == actual + + +def test_parse_transition_route_group_path(): + expected = { + "project": "abalone", + "location": "squid", + "agent": "clam", + "flow": "whelk", + "transition_route_group": "octopus", + } + path = TestCasesClient.transition_route_group_path(**expected) + + # Check that the path construction is reversible. + actual = TestCasesClient.parse_transition_route_group_path(path) + assert expected == actual + + +def test_webhook_path(): + project = "oyster" + location = "nudibranch" + agent = "cuttlefish" + webhook = "mussel" + + expected = "projects/{project}/locations/{location}/agents/{agent}/webhooks/{webhook}".format( + project=project, location=location, agent=agent, webhook=webhook, + ) + actual = TestCasesClient.webhook_path(project, location, agent, webhook) + assert expected == actual + + +def test_parse_webhook_path(): + expected = { + "project": "winkle", + "location": "nautilus", + "agent": "scallop", + "webhook": "abalone", + } + path = TestCasesClient.webhook_path(**expected) + + # Check that the path construction is reversible. + actual = TestCasesClient.parse_webhook_path(path) + assert expected == actual + + +def test_common_billing_account_path(): + billing_account = "squid" + + expected = "billingAccounts/{billing_account}".format( + billing_account=billing_account, + ) + actual = TestCasesClient.common_billing_account_path(billing_account) + assert expected == actual + + +def test_parse_common_billing_account_path(): + expected = { + "billing_account": "clam", + } + path = TestCasesClient.common_billing_account_path(**expected) + + # Check that the path construction is reversible. + actual = TestCasesClient.parse_common_billing_account_path(path) + assert expected == actual + + +def test_common_folder_path(): + folder = "whelk" + + expected = "folders/{folder}".format(folder=folder,) + actual = TestCasesClient.common_folder_path(folder) + assert expected == actual + + +def test_parse_common_folder_path(): + expected = { + "folder": "octopus", + } + path = TestCasesClient.common_folder_path(**expected) + + # Check that the path construction is reversible. + actual = TestCasesClient.parse_common_folder_path(path) + assert expected == actual + + +def test_common_organization_path(): + organization = "oyster" + + expected = "organizations/{organization}".format(organization=organization,) + actual = TestCasesClient.common_organization_path(organization) + assert expected == actual + + +def test_parse_common_organization_path(): + expected = { + "organization": "nudibranch", + } + path = TestCasesClient.common_organization_path(**expected) + + # Check that the path construction is reversible. + actual = TestCasesClient.parse_common_organization_path(path) + assert expected == actual + + +def test_common_project_path(): + project = "cuttlefish" + + expected = "projects/{project}".format(project=project,) + actual = TestCasesClient.common_project_path(project) + assert expected == actual + + +def test_parse_common_project_path(): + expected = { + "project": "mussel", + } + path = TestCasesClient.common_project_path(**expected) + + # Check that the path construction is reversible. + actual = TestCasesClient.parse_common_project_path(path) + assert expected == actual + + +def test_common_location_path(): + project = "winkle" + location = "nautilus" + + expected = "projects/{project}/locations/{location}".format( + project=project, location=location, + ) + actual = TestCasesClient.common_location_path(project, location) + assert expected == actual + + +def test_parse_common_location_path(): + expected = { + "project": "scallop", + "location": "abalone", + } + path = TestCasesClient.common_location_path(**expected) + + # Check that the path construction is reversible. + actual = TestCasesClient.parse_common_location_path(path) + assert expected == actual + + +def test_client_withDEFAULT_CLIENT_INFO(): + client_info = gapic_v1.client_info.ClientInfo() + + with mock.patch.object( + transports.TestCasesTransport, "_prep_wrapped_messages" + ) as prep: + client = TestCasesClient( + credentials=credentials.AnonymousCredentials(), client_info=client_info, + ) + prep.assert_called_once_with(client_info) + + with mock.patch.object( + transports.TestCasesTransport, "_prep_wrapped_messages" + ) as prep: + transport_class = TestCasesClient.get_transport_class() + transport = transport_class( + credentials=credentials.AnonymousCredentials(), client_info=client_info, + ) + prep.assert_called_once_with(client_info) diff --git a/tests/unit/gapic/dialogflowcx_v3beta1/test_transition_route_groups.py b/tests/unit/gapic/dialogflowcx_v3beta1/test_transition_route_groups.py index bf09edfe..36bc1431 100644 --- a/tests/unit/gapic/dialogflowcx_v3beta1/test_transition_route_groups.py +++ b/tests/unit/gapic/dialogflowcx_v3beta1/test_transition_route_groups.py @@ -100,7 +100,24 @@ def test__get_default_mtls_endpoint(): @pytest.mark.parametrize( - "client_class", [TransitionRouteGroupsClient, TransitionRouteGroupsAsyncClient] + "client_class", [TransitionRouteGroupsClient, TransitionRouteGroupsAsyncClient,] +) +def test_transition_route_groups_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 == "dialogflow.googleapis.com:443" + + +@pytest.mark.parametrize( + "client_class", [TransitionRouteGroupsClient, TransitionRouteGroupsAsyncClient,] ) def test_transition_route_groups_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() @@ -110,16 +127,21 @@ def test_transition_route_groups_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 == "dialogflow.googleapis.com:443" def test_transition_route_groups_client_get_transport_class(): transport = TransitionRouteGroupsClient.get_transport_class() - assert transport == transports.TransitionRouteGroupsGrpcTransport + available_transports = [ + transports.TransitionRouteGroupsGrpcTransport, + ] + assert transport in available_transports transport = TransitionRouteGroupsClient.get_transport_class("grpc") assert transport == transports.TransitionRouteGroupsGrpcTransport @@ -174,7 +196,7 @@ def test_transition_route_groups_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, ) @@ -190,7 +212,7 @@ def test_transition_route_groups_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, ) @@ -206,7 +228,7 @@ def test_transition_route_groups_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, ) @@ -234,7 +256,7 @@ def test_transition_route_groups_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, ) @@ -295,29 +317,25 @@ def test_transition_route_groups_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. @@ -326,66 +344,53 @@ def test_transition_route_groups_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", @@ -415,7 +420,7 @@ def test_transition_route_groups_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, ) @@ -449,7 +454,7 @@ def test_transition_route_groups_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, ) @@ -468,7 +473,7 @@ def test_transition_route_groups_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, ) @@ -514,6 +519,24 @@ def test_list_transition_route_groups_from_dict(): test_list_transition_route_groups(request_type=dict) +def test_list_transition_route_groups_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 = TransitionRouteGroupsClient( + 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_transition_route_groups), "__call__" + ) as call: + client.list_transition_route_groups() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == transition_route_group.ListTransitionRouteGroupsRequest() + + @pytest.mark.asyncio async def test_list_transition_route_groups_async( transport: str = "grpc_asyncio", @@ -928,6 +951,24 @@ def test_get_transition_route_group_from_dict(): test_get_transition_route_group(request_type=dict) +def test_get_transition_route_group_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 = TransitionRouteGroupsClient( + 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_transition_route_group), "__call__" + ) as call: + client.get_transition_route_group() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == transition_route_group.GetTransitionRouteGroupRequest() + + @pytest.mark.asyncio async def test_get_transition_route_group_async( transport: str = "grpc_asyncio", @@ -1155,6 +1196,26 @@ def test_create_transition_route_group_from_dict(): test_create_transition_route_group(request_type=dict) +def test_create_transition_route_group_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 = TransitionRouteGroupsClient( + 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_transition_route_group), "__call__" + ) as call: + client.create_transition_route_group() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert ( + args[0] == gcdc_transition_route_group.CreateTransitionRouteGroupRequest() + ) + + @pytest.mark.asyncio async def test_create_transition_route_group_async( transport: str = "grpc_asyncio", @@ -1414,6 +1475,26 @@ def test_update_transition_route_group_from_dict(): test_update_transition_route_group(request_type=dict) +def test_update_transition_route_group_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 = TransitionRouteGroupsClient( + 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_transition_route_group), "__call__" + ) as call: + client.update_transition_route_group() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert ( + args[0] == gcdc_transition_route_group.UpdateTransitionRouteGroupRequest() + ) + + @pytest.mark.asyncio async def test_update_transition_route_group_async( transport: str = "grpc_asyncio", @@ -1670,6 +1751,24 @@ def test_delete_transition_route_group_from_dict(): test_delete_transition_route_group(request_type=dict) +def test_delete_transition_route_group_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 = TransitionRouteGroupsClient( + 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_transition_route_group), "__call__" + ) as call: + client.delete_transition_route_group() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == transition_route_group.DeleteTransitionRouteGroupRequest() + + @pytest.mark.asyncio async def test_delete_transition_route_group_async( transport: str = "grpc_asyncio", @@ -2017,6 +2116,56 @@ def test_transition_route_groups_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [ + transports.TransitionRouteGroupsGrpcTransport, + transports.TransitionRouteGroupsGrpcAsyncIOTransport, + ], +) +def test_transition_route_groups_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/dialogflow", + ), + 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_transition_route_groups_host_no_port(): client = TransitionRouteGroupsClient( credentials=credentials.AnonymousCredentials(), @@ -2038,7 +2187,7 @@ def test_transition_route_groups_host_with_port(): def test_transition_route_groups_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.TransitionRouteGroupsGrpcTransport( @@ -2050,7 +2199,7 @@ def test_transition_route_groups_grpc_transport_channel(): def test_transition_route_groups_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.TransitionRouteGroupsGrpcAsyncIOTransport( @@ -2061,6 +2210,8 @@ def test_transition_route_groups_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", [ @@ -2075,7 +2226,7 @@ def test_transition_route_groups_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 @@ -2116,6 +2267,8 @@ def test_transition_route_groups_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", [ @@ -2131,7 +2284,7 @@ def test_transition_route_groups_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/dialogflowcx_v3beta1/test_versions.py b/tests/unit/gapic/dialogflowcx_v3beta1/test_versions.py index bcd78804..d940baa7 100644 --- a/tests/unit/gapic/dialogflowcx_v3beta1/test_versions.py +++ b/tests/unit/gapic/dialogflowcx_v3beta1/test_versions.py @@ -88,7 +88,22 @@ def test__get_default_mtls_endpoint(): assert VersionsClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi -@pytest.mark.parametrize("client_class", [VersionsClient, VersionsAsyncClient]) +@pytest.mark.parametrize("client_class", [VersionsClient, VersionsAsyncClient,]) +def test_versions_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 == "dialogflow.googleapis.com:443" + + +@pytest.mark.parametrize("client_class", [VersionsClient, VersionsAsyncClient,]) def test_versions_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() with mock.patch.object( @@ -97,16 +112,21 @@ def test_versions_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 == "dialogflow.googleapis.com:443" def test_versions_client_get_transport_class(): transport = VersionsClient.get_transport_class() - assert transport == transports.VersionsGrpcTransport + available_transports = [ + transports.VersionsGrpcTransport, + ] + assert transport in available_transports transport = VersionsClient.get_transport_class("grpc") assert transport == transports.VersionsGrpcTransport @@ -149,7 +169,7 @@ def test_versions_client_client_options(client_class, transport_class, transport 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_versions_client_client_options(client_class, transport_class, transport 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_versions_client_client_options(client_class, transport_class, transport 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_versions_client_client_options(client_class, transport_class, transport 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_versions_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_versions_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", @@ -370,7 +373,7 @@ def test_versions_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, ) @@ -396,7 +399,7 @@ def test_versions_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, ) @@ -413,7 +416,7 @@ def test_versions_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, ) @@ -456,6 +459,22 @@ def test_list_versions_from_dict(): test_list_versions(request_type=dict) +def test_list_versions_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 = VersionsClient( + 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_versions), "__call__") as call: + client.list_versions() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == version.ListVersionsRequest() + + @pytest.mark.asyncio async def test_list_versions_async( transport: str = "grpc_asyncio", request_type=version.ListVersionsRequest @@ -778,6 +797,22 @@ def test_get_version_from_dict(): test_get_version(request_type=dict) +def test_get_version_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 = VersionsClient( + 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_version), "__call__") as call: + client.get_version() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == version.GetVersionRequest() + + @pytest.mark.asyncio async def test_get_version_async( transport: str = "grpc_asyncio", request_type=version.GetVersionRequest @@ -973,6 +1008,22 @@ def test_create_version_from_dict(): test_create_version(request_type=dict) +def test_create_version_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 = VersionsClient( + 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_version), "__call__") as call: + client.create_version() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_version.CreateVersionRequest() + + @pytest.mark.asyncio async def test_create_version_async( transport: str = "grpc_asyncio", request_type=gcdc_version.CreateVersionRequest @@ -1185,6 +1236,22 @@ def test_update_version_from_dict(): test_update_version(request_type=dict) +def test_update_version_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 = VersionsClient( + 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_version), "__call__") as call: + client.update_version() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_version.UpdateVersionRequest() + + @pytest.mark.asyncio async def test_update_version_async( transport: str = "grpc_asyncio", request_type=gcdc_version.UpdateVersionRequest @@ -1402,6 +1469,22 @@ def test_delete_version_from_dict(): test_delete_version(request_type=dict) +def test_delete_version_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 = VersionsClient( + 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_version), "__call__") as call: + client.delete_version() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == version.DeleteVersionRequest() + + @pytest.mark.asyncio async def test_delete_version_async( transport: str = "grpc_asyncio", request_type=version.DeleteVersionRequest @@ -1580,6 +1663,22 @@ def test_load_version_from_dict(): test_load_version(request_type=dict) +def test_load_version_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 = VersionsClient( + credentials=credentials.AnonymousCredentials(), transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.load_version), "__call__") as call: + client.load_version() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == version.LoadVersionRequest() + + @pytest.mark.asyncio async def test_load_version_async( transport: str = "grpc_asyncio", request_type=version.LoadVersionRequest @@ -1790,7 +1889,7 @@ def test_transport_get_channel(): @pytest.mark.parametrize( "transport_class", - [transports.VersionsGrpcTransport, transports.VersionsGrpcAsyncIOTransport], + [transports.VersionsGrpcTransport, transports.VersionsGrpcAsyncIOTransport,], ) def test_transport_adc(transport_class): # Test default credentials are used if not provided. @@ -1909,6 +2008,51 @@ def test_versions_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [transports.VersionsGrpcTransport, transports.VersionsGrpcAsyncIOTransport], +) +def test_versions_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/dialogflow", + ), + 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_versions_host_no_port(): client = VersionsClient( credentials=credentials.AnonymousCredentials(), @@ -1930,7 +2074,7 @@ def test_versions_host_with_port(): def test_versions_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.VersionsGrpcTransport( @@ -1942,7 +2086,7 @@ def test_versions_grpc_transport_channel(): def test_versions_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.VersionsGrpcAsyncIOTransport( @@ -1953,6 +2097,8 @@ def test_versions_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.VersionsGrpcTransport, transports.VersionsGrpcAsyncIOTransport], @@ -1962,7 +2108,7 @@ def test_versions_transport_channel_mtls_with_client_cert_source(transport_class "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 @@ -2003,6 +2149,8 @@ def test_versions_transport_channel_mtls_with_client_cert_source(transport_class 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.VersionsGrpcTransport, transports.VersionsGrpcAsyncIOTransport], @@ -2015,7 +2163,7 @@ def test_versions_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/dialogflowcx_v3beta1/test_webhooks.py b/tests/unit/gapic/dialogflowcx_v3beta1/test_webhooks.py index f2a6462b..818a245c 100644 --- a/tests/unit/gapic/dialogflowcx_v3beta1/test_webhooks.py +++ b/tests/unit/gapic/dialogflowcx_v3beta1/test_webhooks.py @@ -82,7 +82,22 @@ def test__get_default_mtls_endpoint(): assert WebhooksClient._get_default_mtls_endpoint(non_googleapi) == non_googleapi -@pytest.mark.parametrize("client_class", [WebhooksClient, WebhooksAsyncClient]) +@pytest.mark.parametrize("client_class", [WebhooksClient, WebhooksAsyncClient,]) +def test_webhooks_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 == "dialogflow.googleapis.com:443" + + +@pytest.mark.parametrize("client_class", [WebhooksClient, WebhooksAsyncClient,]) def test_webhooks_client_from_service_account_file(client_class): creds = credentials.AnonymousCredentials() with mock.patch.object( @@ -91,16 +106,21 @@ def test_webhooks_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 == "dialogflow.googleapis.com:443" def test_webhooks_client_get_transport_class(): transport = WebhooksClient.get_transport_class() - assert transport == transports.WebhooksGrpcTransport + available_transports = [ + transports.WebhooksGrpcTransport, + ] + assert transport in available_transports transport = WebhooksClient.get_transport_class("grpc") assert transport == transports.WebhooksGrpcTransport @@ -143,7 +163,7 @@ def test_webhooks_client_client_options(client_class, transport_class, transport 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, ) @@ -159,7 +179,7 @@ def test_webhooks_client_client_options(client_class, transport_class, transport 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, ) @@ -175,7 +195,7 @@ def test_webhooks_client_client_options(client_class, transport_class, transport 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, ) @@ -203,7 +223,7 @@ def test_webhooks_client_client_options(client_class, transport_class, transport 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, ) @@ -252,29 +272,25 @@ def test_webhooks_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. @@ -283,66 +299,53 @@ def test_webhooks_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", @@ -364,7 +367,7 @@ def test_webhooks_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, ) @@ -390,7 +393,7 @@ def test_webhooks_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, ) @@ -407,7 +410,7 @@ def test_webhooks_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, ) @@ -450,6 +453,22 @@ def test_list_webhooks_from_dict(): test_list_webhooks(request_type=dict) +def test_list_webhooks_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 = WebhooksClient( + 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_webhooks), "__call__") as call: + client.list_webhooks() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == webhook.ListWebhooksRequest() + + @pytest.mark.asyncio async def test_list_webhooks_async( transport: str = "grpc_asyncio", request_type=webhook.ListWebhooksRequest @@ -770,6 +789,22 @@ def test_get_webhook_from_dict(): test_get_webhook(request_type=dict) +def test_get_webhook_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 = WebhooksClient( + 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_webhook), "__call__") as call: + client.get_webhook() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == webhook.GetWebhookRequest() + + @pytest.mark.asyncio async def test_get_webhook_async( transport: str = "grpc_asyncio", request_type=webhook.GetWebhookRequest @@ -972,6 +1007,22 @@ def test_create_webhook_from_dict(): test_create_webhook(request_type=dict) +def test_create_webhook_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 = WebhooksClient( + 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_webhook), "__call__") as call: + client.create_webhook() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_webhook.CreateWebhookRequest() + + @pytest.mark.asyncio async def test_create_webhook_async( transport: str = "grpc_asyncio", request_type=gcdc_webhook.CreateWebhookRequest @@ -1190,6 +1241,22 @@ def test_update_webhook_from_dict(): test_update_webhook(request_type=dict) +def test_update_webhook_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 = WebhooksClient( + 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_webhook), "__call__") as call: + client.update_webhook() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == gcdc_webhook.UpdateWebhookRequest() + + @pytest.mark.asyncio async def test_update_webhook_async( transport: str = "grpc_asyncio", request_type=gcdc_webhook.UpdateWebhookRequest @@ -1402,6 +1469,22 @@ def test_delete_webhook_from_dict(): test_delete_webhook(request_type=dict) +def test_delete_webhook_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 = WebhooksClient( + 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_webhook), "__call__") as call: + client.delete_webhook() + call.assert_called() + _, args, _ = call.mock_calls[0] + + assert args[0] == webhook.DeleteWebhookRequest() + + @pytest.mark.asyncio async def test_delete_webhook_async( transport: str = "grpc_asyncio", request_type=webhook.DeleteWebhookRequest @@ -1606,7 +1689,7 @@ def test_transport_get_channel(): @pytest.mark.parametrize( "transport_class", - [transports.WebhooksGrpcTransport, transports.WebhooksGrpcAsyncIOTransport], + [transports.WebhooksGrpcTransport, transports.WebhooksGrpcAsyncIOTransport,], ) def test_transport_adc(transport_class): # Test default credentials are used if not provided. @@ -1719,6 +1802,51 @@ def test_webhooks_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class", + [transports.WebhooksGrpcTransport, transports.WebhooksGrpcAsyncIOTransport], +) +def test_webhooks_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/dialogflow", + ), + 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_webhooks_host_no_port(): client = WebhooksClient( credentials=credentials.AnonymousCredentials(), @@ -1740,7 +1868,7 @@ def test_webhooks_host_with_port(): def test_webhooks_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.WebhooksGrpcTransport( @@ -1752,7 +1880,7 @@ def test_webhooks_grpc_transport_channel(): def test_webhooks_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.WebhooksGrpcAsyncIOTransport( @@ -1763,6 +1891,8 @@ def test_webhooks_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.WebhooksGrpcTransport, transports.WebhooksGrpcAsyncIOTransport], @@ -1772,7 +1902,7 @@ def test_webhooks_transport_channel_mtls_with_client_cert_source(transport_class "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 @@ -1813,6 +1943,8 @@ def test_webhooks_transport_channel_mtls_with_client_cert_source(transport_class 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.WebhooksGrpcTransport, transports.WebhooksGrpcAsyncIOTransport], @@ -1825,7 +1957,7 @@ def test_webhooks_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