diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 65116f60..f8d4cbae 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -4,6 +4,9 @@
# For syntax help see:
# https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners#codeowners-syntax
+# The @googleapis/yoshi-python is the default owner for changes in this repo
+* @googleapis/yoshi-python
+
# The python-samples-owners team is the default owner for samples
/samples/**/*.py @telpirion @sirtorry @googleapis/python-samples-owners
\ No newline at end of file
diff --git a/.github/snippet-bot.yml b/.github/snippet-bot.yml
new file mode 100644
index 00000000..e69de29b
diff --git a/.kokoro/docs/common.cfg b/.kokoro/docs/common.cfg
index 95963d11..180702da 100644
--- a/.kokoro/docs/common.cfg
+++ b/.kokoro/docs/common.cfg
@@ -30,7 +30,7 @@ env_vars: {
env_vars: {
key: "V2_STAGING_BUCKET"
- value: "docs-staging-v2-staging"
+ value: "docs-staging-v2"
}
# It will upload the docker image after successful builds.
diff --git a/.kokoro/populate-secrets.sh b/.kokoro/populate-secrets.sh
new file mode 100755
index 00000000..f5251425
--- /dev/null
+++ b/.kokoro/populate-secrets.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+# Copyright 2020 Google LLC.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# 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.
+
+set -eo pipefail
+
+function now { date +"%Y-%m-%d %H:%M:%S" | tr -d '\n' ;}
+function msg { println "$*" >&2 ;}
+function println { printf '%s\n' "$(now) $*" ;}
+
+
+# Populates requested secrets set in SECRET_MANAGER_KEYS from service account:
+# kokoro-trampoline@cloud-devrel-kokoro-resources.iam.gserviceaccount.com
+SECRET_LOCATION="${KOKORO_GFILE_DIR}/secret_manager"
+msg "Creating folder on disk for secrets: ${SECRET_LOCATION}"
+mkdir -p ${SECRET_LOCATION}
+for key in $(echo ${SECRET_MANAGER_KEYS} | sed "s/,/ /g")
+do
+ msg "Retrieving secret ${key}"
+ docker run --entrypoint=gcloud \
+ --volume=${KOKORO_GFILE_DIR}:${KOKORO_GFILE_DIR} \
+ gcr.io/google.com/cloudsdktool/cloud-sdk \
+ secrets versions access latest \
+ --project cloud-devrel-kokoro-resources \
+ --secret ${key} > \
+ "${SECRET_LOCATION}/${key}"
+ if [[ $? == 0 ]]; then
+ msg "Secret written to ${SECRET_LOCATION}/${key}"
+ else
+ msg "Error retrieving secret ${key}"
+ fi
+done
diff --git a/.kokoro/release/common.cfg b/.kokoro/release/common.cfg
index ef255b9f..14180c27 100644
--- a/.kokoro/release/common.cfg
+++ b/.kokoro/release/common.cfg
@@ -23,42 +23,18 @@ env_vars: {
value: "github/python-translate/.kokoro/release.sh"
}
-# Fetch the token needed for reporting release status to GitHub
-before_action {
- fetch_keystore {
- keystore_resource {
- keystore_config_id: 73713
- keyname: "yoshi-automation-github-key"
- }
- }
-}
-
-# Fetch PyPI password
-before_action {
- fetch_keystore {
- keystore_resource {
- keystore_config_id: 73713
- keyname: "google_cloud_pypi_password"
- }
- }
-}
-
-# Fetch magictoken to use with Magic Github Proxy
-before_action {
- fetch_keystore {
- keystore_resource {
- keystore_config_id: 73713
- keyname: "releasetool-magictoken"
- }
- }
+# Fetch PyPI password
+before_action {
+ fetch_keystore {
+ keystore_resource {
+ keystore_config_id: 73713
+ keyname: "google_cloud_pypi_password"
+ }
+ }
}
-# Fetch api key to use with Magic Github Proxy
-before_action {
- fetch_keystore {
- keystore_resource {
- keystore_config_id: 73713
- keyname: "magic-github-proxy-api-key"
- }
- }
-}
+# Tokens needed to report release status back to GitHub
+env_vars: {
+ key: "SECRET_MANAGER_KEYS"
+ value: "releasetool-publish-reporter-app,releasetool-publish-reporter-googleapis-installation,releasetool-publish-reporter-pem"
+}
\ No newline at end of file
diff --git a/.kokoro/samples/python3.6/common.cfg b/.kokoro/samples/python3.6/common.cfg
index 0d5ec9ab..0afe4cf9 100644
--- a/.kokoro/samples/python3.6/common.cfg
+++ b/.kokoro/samples/python3.6/common.cfg
@@ -13,6 +13,12 @@ env_vars: {
value: "py-3.6"
}
+# Declare build specific Cloud project.
+env_vars: {
+ key: "BUILD_SPECIFIC_GCLOUD_PROJECT"
+ value: "python-docs-samples-tests-py36"
+}
+
env_vars: {
key: "TRAMPOLINE_BUILD_FILE"
value: "github/python-translate/.kokoro/test-samples.sh"
diff --git a/.kokoro/samples/python3.7/common.cfg b/.kokoro/samples/python3.7/common.cfg
index 59a17837..b82e68ae 100644
--- a/.kokoro/samples/python3.7/common.cfg
+++ b/.kokoro/samples/python3.7/common.cfg
@@ -13,6 +13,12 @@ env_vars: {
value: "py-3.7"
}
+# Declare build specific Cloud project.
+env_vars: {
+ key: "BUILD_SPECIFIC_GCLOUD_PROJECT"
+ value: "python-docs-samples-tests-py37"
+}
+
env_vars: {
key: "TRAMPOLINE_BUILD_FILE"
value: "github/python-translate/.kokoro/test-samples.sh"
diff --git a/.kokoro/samples/python3.8/common.cfg b/.kokoro/samples/python3.8/common.cfg
index 6cff86d8..9a34eac6 100644
--- a/.kokoro/samples/python3.8/common.cfg
+++ b/.kokoro/samples/python3.8/common.cfg
@@ -13,6 +13,12 @@ env_vars: {
value: "py-3.8"
}
+# Declare build specific Cloud project.
+env_vars: {
+ key: "BUILD_SPECIFIC_GCLOUD_PROJECT"
+ value: "python-docs-samples-tests-py38"
+}
+
env_vars: {
key: "TRAMPOLINE_BUILD_FILE"
value: "github/python-translate/.kokoro/test-samples.sh"
diff --git a/.kokoro/test-samples.sh b/.kokoro/test-samples.sh
index e121af3e..6409c76b 100755
--- a/.kokoro/test-samples.sh
+++ b/.kokoro/test-samples.sh
@@ -28,6 +28,12 @@ if [[ $KOKORO_BUILD_ARTIFACTS_SUBDIR = *"periodic"* ]]; then
git checkout $LATEST_RELEASE
fi
+# Exit early if samples directory doesn't exist
+if [ ! -d "./samples" ]; then
+ echo "No tests run. `./samples` not found"
+ exit 0
+fi
+
# Disable buffering, so that the logs stream through.
export PYTHONUNBUFFERED=1
@@ -101,4 +107,4 @@ cd "$ROOT"
# Workaround for Kokoro permissions issue: delete secrets
rm testing/{test-env.sh,client-secrets.json,service-account.json}
-exit "$RTN"
\ No newline at end of file
+exit "$RTN"
diff --git a/.kokoro/trampoline.sh b/.kokoro/trampoline.sh
index e8c4251f..f39236e9 100755
--- a/.kokoro/trampoline.sh
+++ b/.kokoro/trampoline.sh
@@ -15,9 +15,14 @@
set -eo pipefail
-python3 "${KOKORO_GFILE_DIR}/trampoline_v1.py" || ret_code=$?
+# Always run the cleanup script, regardless of the success of bouncing into
+# the container.
+function cleanup() {
+ chmod +x ${KOKORO_GFILE_DIR}/trampoline_cleanup.sh
+ ${KOKORO_GFILE_DIR}/trampoline_cleanup.sh
+ echo "cleanup";
+}
+trap cleanup EXIT
-chmod +x ${KOKORO_GFILE_DIR}/trampoline_cleanup.sh
-${KOKORO_GFILE_DIR}/trampoline_cleanup.sh || true
-
-exit ${ret_code}
+$(dirname $0)/populate-secrets.sh # Secret Manager secrets.
+python3 "${KOKORO_GFILE_DIR}/trampoline_v1.py"
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 11aa7cfa..e0644800 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,13 @@
[1]: https://pypi.org/project/google-cloud-translate/#history
+### [3.0.2](https://www.github.com/googleapis/python-translate/compare/v3.0.1...v3.0.2) (2020-12-09)
+
+
+### Documentation
+
+* add w/ glossary and model ([1e030d4](https://www.github.com/googleapis/python-translate/commit/1e030d4557ee1f67bad5e5b4759d0200efd27afd))
+
### [3.0.1](https://www.github.com/googleapis/python-translate/compare/v3.0.0...v3.0.1) (2020-08-08)
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
index b3d1f602..039f4368 100644
--- a/CODE_OF_CONDUCT.md
+++ b/CODE_OF_CONDUCT.md
@@ -1,44 +1,95 @@
-# Contributor Code of Conduct
+# Code of Conduct
-As contributors and maintainers of this project,
-and in the interest of fostering an open and welcoming community,
-we pledge to respect all people who contribute through reporting issues,
-posting feature requests, updating documentation,
-submitting pull requests or patches, and other activities.
+## Our Pledge
-We are committed to making participation in this project
-a harassment-free experience for everyone,
-regardless of level of experience, gender, gender identity and expression,
-sexual orientation, disability, personal appearance,
-body size, race, ethnicity, age, religion, or nationality.
+In the interest of fostering an open and welcoming environment, we as
+contributors and maintainers pledge to making participation in our project and
+our community a harassment-free experience for everyone, regardless of age, body
+size, disability, ethnicity, gender identity and expression, level of
+experience, education, socio-economic status, nationality, personal appearance,
+race, religion, or sexual identity and orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment
+include:
+
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
-* The use of sexualized language or imagery
-* Personal attacks
-* Trolling or insulting/derogatory comments
-* Public or private harassment
-* Publishing other's private information,
-such as physical or electronic
-addresses, without explicit permission
-* Other unethical or unprofessional conduct.
+* The use of sexualized language or imagery and unwelcome sexual attention or
+ advances
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic
+ address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable
+behavior and are expected to take appropriate and fair corrective action in
+response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject
-comments, commits, code, wiki edits, issues, and other contributions
-that are not aligned to this Code of Conduct.
-By adopting this Code of Conduct,
-project maintainers commit themselves to fairly and consistently
-applying these principles to every aspect of managing this project.
-Project maintainers who do not follow or enforce the Code of Conduct
-may be permanently removed from the project team.
-
-This code of conduct applies both within project spaces and in public spaces
-when an individual is representing the project or its community.
-
-Instances of abusive, harassing, or otherwise unacceptable behavior
-may be reported by opening an issue
-or contacting one or more of the project maintainers.
-
-This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0,
-available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/)
+comments, commits, code, wiki edits, issues, and other contributions that are
+not aligned to this Code of Conduct, or to ban temporarily or permanently any
+contributor for other behaviors that they deem inappropriate, threatening,
+offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces
+when an individual is representing the project or its community. Examples of
+representing a project or community include using an official project e-mail
+address, posting via an official social media account, or acting as an appointed
+representative at an online or offline event. Representation of a project may be
+further defined and clarified by project maintainers.
+
+This Code of Conduct also applies outside the project spaces when the Project
+Steward has a reasonable belief that an individual's behavior may have a
+negative impact on the project or its community.
+
+## Conflict Resolution
+
+We do not believe that all conflict is bad; healthy debate and disagreement
+often yield positive results. However, it is never okay to be disrespectful or
+to engage in behavior that violates the project’s code of conduct.
+
+If you see someone violating the code of conduct, you are encouraged to address
+the behavior directly with those involved. Many issues can be resolved quickly
+and easily, and this gives people more control over the outcome of their
+dispute. If you are unable to resolve the matter for any reason, or if the
+behavior is threatening or harassing, report it. We are dedicated to providing
+an environment where participants feel welcome and safe.
+
+
+Reports should be directed to *googleapis-stewards@google.com*, the
+Project Steward(s) for *Google Cloud Client Libraries*. It is the Project Steward’s duty to
+receive and address reported violations of the code of conduct. They will then
+work with a committee consisting of representatives from the Open Source
+Programs Office and the Google Open Source Strategy team. If for any reason you
+are uncomfortable reaching out to the Project Steward, please email
+opensource@google.com.
+
+We will investigate every complaint, but you may not receive a direct response.
+We will use our discretion in determining when and how to follow up on reported
+incidents, which may range from not taking action to permanent expulsion from
+the project and project-sponsored spaces. We will notify the accused of the
+report and provide them an opportunity to discuss it before any action is taken.
+The identity of the reporter will be omitted from the details of the report
+supplied to the accused. In potentially harmful situations, such as ongoing
+harassment or threats to anyone's safety, we may take action without notice.
+
+## Attribution
+
+This Code of Conduct is adapted from the Contributor Covenant, version 1.4,
+available at
+https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
\ No newline at end of file
diff --git a/docs/conf.py b/docs/conf.py
index 57ed8f60..51457137 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -29,7 +29,7 @@
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
-needs_sphinx = "1.6.3"
+needs_sphinx = "1.5.5"
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
@@ -39,6 +39,7 @@
"sphinx.ext.autosummary",
"sphinx.ext.intersphinx",
"sphinx.ext.coverage",
+ "sphinx.ext.doctest",
"sphinx.ext.napoleon",
"sphinx.ext.todo",
"sphinx.ext.viewcode",
diff --git a/google/cloud/translate_v3/services/translation_service/async_client.py b/google/cloud/translate_v3/services/translation_service/async_client.py
index 9cb9b9d8..8d2c52b9 100644
--- a/google/cloud/translate_v3/services/translation_service/async_client.py
+++ b/google/cloud/translate_v3/services/translation_service/async_client.py
@@ -28,13 +28,13 @@
from google.auth import credentials # type: ignore
from google.oauth2 import service_account # type: ignore
-from google.api_core import operation
-from google.api_core import operation_async
+from google.api_core import operation # type: ignore
+from google.api_core import operation_async # type: ignore
from google.cloud.translate_v3.services.translation_service import pagers
from google.cloud.translate_v3.types import translation_service
from google.protobuf import timestamp_pb2 as timestamp # type: ignore
-from .transports.base import TranslationServiceTransport
+from .transports.base import TranslationServiceTransport, DEFAULT_CLIENT_INFO
from .transports.grpc_asyncio import TranslationServiceGrpcAsyncIOTransport
from .client import TranslationServiceClient
@@ -48,6 +48,7 @@ class TranslationServiceAsyncClient:
DEFAULT_MTLS_ENDPOINT = TranslationServiceClient.DEFAULT_MTLS_ENDPOINT
glossary_path = staticmethod(TranslationServiceClient.glossary_path)
+ parse_glossary_path = staticmethod(TranslationServiceClient.parse_glossary_path)
from_service_account_file = TranslationServiceClient.from_service_account_file
from_service_account_json = from_service_account_file
@@ -63,6 +64,7 @@ def __init__(
credentials: credentials.Credentials = None,
transport: Union[str, TranslationServiceTransport] = "grpc_asyncio",
client_options: ClientOptions = None,
+ client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO,
) -> None:
"""Instantiate the translation service client.
@@ -78,16 +80,19 @@ def __init__(
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
+ 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, this is the default value for
- the environment variable) and "auto" (auto switch to the default
- mTLS endpoint if client SSL credentials is present). However,
- the ``api_endpoint`` property takes precedence if provided.
- (2) The ``client_cert_source`` property is used to provide client
- SSL credentials for mutual TLS transport. If not provided, the
- default SSL credentials will be used if present.
+ 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
@@ -95,7 +100,10 @@ def __init__(
"""
self._client = TranslationServiceClient(
- credentials=credentials, transport=transport, client_options=client_options,
+ credentials=credentials,
+ transport=transport,
+ client_options=client_options,
+ client_info=client_info,
)
async def translate_text(
@@ -248,7 +256,7 @@ async def translate_text(
rpc = gapic_v1.method_async.wrap_method(
self._client._transport.translate_text,
default_timeout=600.0,
- client_info=_client_info,
+ client_info=DEFAULT_CLIENT_INFO,
)
# Certain fields should be provided within the metadata header;
@@ -368,7 +376,7 @@ async def detect_language(
rpc = gapic_v1.method_async.wrap_method(
self._client._transport.detect_language,
default_timeout=600.0,
- client_info=_client_info,
+ client_info=DEFAULT_CLIENT_INFO,
)
# Certain fields should be provided within the metadata header;
@@ -494,7 +502,7 @@ async def get_supported_languages(
),
),
default_timeout=600.0,
- client_info=_client_info,
+ client_info=DEFAULT_CLIENT_INFO,
)
# Certain fields should be provided within the metadata header;
@@ -558,7 +566,7 @@ async def batch_translate_text(
rpc = gapic_v1.method_async.wrap_method(
self._client._transport.batch_translate_text,
default_timeout=600.0,
- client_info=_client_info,
+ client_info=DEFAULT_CLIENT_INFO,
)
# Certain fields should be provided within the metadata header;
@@ -647,7 +655,7 @@ async def create_glossary(
rpc = gapic_v1.method_async.wrap_method(
self._client._transport.create_glossary,
default_timeout=600.0,
- client_info=_client_info,
+ client_info=DEFAULT_CLIENT_INFO,
)
# Certain fields should be provided within the metadata header;
@@ -737,7 +745,7 @@ async def list_glossaries(
),
),
default_timeout=600.0,
- client_info=_client_info,
+ client_info=DEFAULT_CLIENT_INFO,
)
# Certain fields should be provided within the metadata header;
@@ -822,7 +830,7 @@ async def get_glossary(
),
),
default_timeout=600.0,
- client_info=_client_info,
+ client_info=DEFAULT_CLIENT_INFO,
)
# Certain fields should be provided within the metadata header;
@@ -907,7 +915,7 @@ async def delete_glossary(
),
),
default_timeout=600.0,
- client_info=_client_info,
+ client_info=DEFAULT_CLIENT_INFO,
)
# Certain fields should be provided within the metadata header;
@@ -932,11 +940,11 @@ async def delete_glossary(
try:
- _client_info = gapic_v1.client_info.ClientInfo(
+ DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo(
gapic_version=pkg_resources.get_distribution("google-cloud-translate",).version,
)
except pkg_resources.DistributionNotFound:
- _client_info = gapic_v1.client_info.ClientInfo()
+ DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo()
__all__ = ("TranslationServiceAsyncClient",)
diff --git a/google/cloud/translate_v3/services/translation_service/client.py b/google/cloud/translate_v3/services/translation_service/client.py
index d00cd12d..af612268 100644
--- a/google/cloud/translate_v3/services/translation_service/client.py
+++ b/google/cloud/translate_v3/services/translation_service/client.py
@@ -16,27 +16,29 @@
#
from collections import OrderedDict
+from distutils import util
import os
import re
-from typing import Callable, Dict, Sequence, Tuple, Type, Union
+from typing import Callable, Dict, Optional, Sequence, Tuple, Type, Union
import pkg_resources
-import google.api_core.client_options as ClientOptions # type: ignore
+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
-from google.api_core import operation_async
+from google.api_core import operation # type: ignore
+from google.api_core import operation_async # type: ignore
from google.cloud.translate_v3.services.translation_service import pagers
from google.cloud.translate_v3.types import translation_service
from google.protobuf import timestamp_pb2 as timestamp # type: ignore
-from .transports.base import TranslationServiceTransport
+from .transports.base import TranslationServiceTransport, DEFAULT_CLIENT_INFO
from .transports.grpc import TranslationServiceGrpcTransport
from .transports.grpc_asyncio import TranslationServiceGrpcAsyncIOTransport
@@ -152,9 +154,10 @@ def parse_glossary_path(path: str) -> Dict[str, str]:
def __init__(
self,
*,
- credentials: credentials.Credentials = None,
- transport: Union[str, TranslationServiceTransport] = None,
- client_options: ClientOptions = None,
+ credentials: Optional[credentials.Credentials] = None,
+ transport: Union[str, TranslationServiceTransport, None] = None,
+ client_options: Optional[client_options_lib.ClientOptions] = None,
+ client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO,
) -> None:
"""Instantiate the translation service client.
@@ -167,48 +170,74 @@ def __init__(
transport (Union[str, ~.TranslationServiceTransport]): 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.
+ client_options (client_options_lib.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
+ 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, this is the default value for
- the environment variable) and "auto" (auto switch to the default
- mTLS endpoint if client SSL credentials is present). However,
- the ``api_endpoint`` property takes precedence if provided.
- (2) The ``client_cert_source`` property is used to provide client
- SSL credentials for mutual TLS transport. If not provided, the
- default SSL credentials will be used if present.
+ 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 = ClientOptions.from_dict(client_options)
+ client_options = client_options_lib.from_dict(client_options)
if client_options is None:
- client_options = ClientOptions.ClientOptions()
+ client_options = client_options_lib.ClientOptions()
- if client_options.api_endpoint is None:
- use_mtls_env = os.getenv("GOOGLE_API_USE_MTLS", "never")
+ # Create SSL credentials for mutual TLS if needed.
+ use_client_cert = bool(
+ util.strtobool(os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false"))
+ )
+
+ ssl_credentials = 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
+ else:
+ creds = SslCredentials()
+ is_mtls = creds.is_mtls
+ ssl_credentials = creds.ssl_credentials 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":
- client_options.api_endpoint = self.DEFAULT_ENDPOINT
+ api_endpoint = self.DEFAULT_ENDPOINT
elif use_mtls_env == "always":
- client_options.api_endpoint = self.DEFAULT_MTLS_ENDPOINT
+ api_endpoint = self.DEFAULT_MTLS_ENDPOINT
elif use_mtls_env == "auto":
- has_client_cert_source = (
- client_options.client_cert_source is not None
- or mtls.has_default_client_cert_source()
- )
- client_options.api_endpoint = (
- self.DEFAULT_MTLS_ENDPOINT
- if has_client_cert_source
- else self.DEFAULT_ENDPOINT
+ api_endpoint = (
+ self.DEFAULT_MTLS_ENDPOINT if is_mtls else self.DEFAULT_ENDPOINT
)
else:
raise MutualTLSChannelError(
- "Unsupported GOOGLE_API_USE_MTLS value. Accepted values: never, auto, always"
+ "Unsupported GOOGLE_API_USE_MTLS_ENDPOINT value. Accepted values: never, auto, always"
)
# Save or instantiate the transport.
@@ -232,11 +261,11 @@ def __init__(
self._transport = Transport(
credentials=credentials,
credentials_file=client_options.credentials_file,
- host=client_options.api_endpoint,
+ host=api_endpoint,
scopes=client_options.scopes,
- api_mtls_endpoint=client_options.api_endpoint,
- client_cert_source=client_options.client_cert_source,
+ ssl_channel_credentials=ssl_credentials,
quota_project_id=client_options.quota_project_id,
+ client_info=client_info,
)
def translate_text(
@@ -1056,11 +1085,11 @@ def delete_glossary(
try:
- _client_info = gapic_v1.client_info.ClientInfo(
+ DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo(
gapic_version=pkg_resources.get_distribution("google-cloud-translate",).version,
)
except pkg_resources.DistributionNotFound:
- _client_info = gapic_v1.client_info.ClientInfo()
+ DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo()
__all__ = ("TranslationServiceClient",)
diff --git a/google/cloud/translate_v3/services/translation_service/transports/base.py b/google/cloud/translate_v3/services/translation_service/transports/base.py
index ad022171..204e32ec 100644
--- a/google/cloud/translate_v3/services/translation_service/transports/base.py
+++ b/google/cloud/translate_v3/services/translation_service/transports/base.py
@@ -19,7 +19,7 @@
import typing
import pkg_resources
-from google import auth
+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
@@ -31,11 +31,11 @@
try:
- _client_info = gapic_v1.client_info.ClientInfo(
+ DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo(
gapic_version=pkg_resources.get_distribution("google-cloud-translate",).version,
)
except pkg_resources.DistributionNotFound:
- _client_info = gapic_v1.client_info.ClientInfo()
+ DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo()
class TranslationServiceTransport(abc.ABC):
@@ -54,6 +54,7 @@ def __init__(
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.
@@ -71,6 +72,11 @@ def __init__(
scope (Optional[Sequence[str]]): A list of scopes.
quota_project_id (Optional[str]): An optional project to use for billing
and quota.
+ client_info (google.api_core.gapic_v1.client_info.ClientInfo):
+ The client info used to send a user-agent string along with
+ API requests. If ``None``, then default info will be used.
+ Generally, you only need to set this if you're developing
+ your own client library.
"""
# Save the hostname. Default to port 443 (HTTPS) if none is specified.
if ":" not in host:
@@ -98,16 +104,16 @@ def __init__(
self._credentials = credentials
# Lifted into its own function so it can be stubbed out during tests.
- self._prep_wrapped_messages()
+ self._prep_wrapped_messages(client_info)
- def _prep_wrapped_messages(self):
+ def _prep_wrapped_messages(self, client_info):
# Precompute the wrapped methods.
self._wrapped_methods = {
self.translate_text: gapic_v1.method.wrap_method(
- self.translate_text, default_timeout=600.0, client_info=_client_info,
+ self.translate_text, default_timeout=600.0, client_info=client_info,
),
self.detect_language: gapic_v1.method.wrap_method(
- self.detect_language, default_timeout=600.0, client_info=_client_info,
+ self.detect_language, default_timeout=600.0, client_info=client_info,
),
self.get_supported_languages: gapic_v1.method.wrap_method(
self.get_supported_languages,
@@ -120,15 +126,15 @@ def _prep_wrapped_messages(self):
),
),
default_timeout=600.0,
- client_info=_client_info,
+ client_info=client_info,
),
self.batch_translate_text: gapic_v1.method.wrap_method(
self.batch_translate_text,
default_timeout=600.0,
- client_info=_client_info,
+ client_info=client_info,
),
self.create_glossary: gapic_v1.method.wrap_method(
- self.create_glossary, default_timeout=600.0, client_info=_client_info,
+ self.create_glossary, default_timeout=600.0, client_info=client_info,
),
self.list_glossaries: gapic_v1.method.wrap_method(
self.list_glossaries,
@@ -141,7 +147,7 @@ def _prep_wrapped_messages(self):
),
),
default_timeout=600.0,
- client_info=_client_info,
+ client_info=client_info,
),
self.get_glossary: gapic_v1.method.wrap_method(
self.get_glossary,
@@ -154,7 +160,7 @@ def _prep_wrapped_messages(self):
),
),
default_timeout=600.0,
- client_info=_client_info,
+ client_info=client_info,
),
self.delete_glossary: gapic_v1.method.wrap_method(
self.delete_glossary,
@@ -167,7 +173,7 @@ def _prep_wrapped_messages(self):
),
),
default_timeout=600.0,
- client_info=_client_info,
+ client_info=client_info,
),
}
diff --git a/google/cloud/translate_v3/services/translation_service/transports/grpc.py b/google/cloud/translate_v3/services/translation_service/transports/grpc.py
index f8ee5ef5..09e06595 100644
--- a/google/cloud/translate_v3/services/translation_service/transports/grpc.py
+++ b/google/cloud/translate_v3/services/translation_service/transports/grpc.py
@@ -15,21 +15,22 @@
# 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.translate_v3.types import translation_service
from google.longrunning import operations_pb2 as operations # type: ignore
-from .base import TranslationServiceTransport
+from .base import TranslationServiceTransport, DEFAULT_CLIENT_INFO
class TranslationServiceGrpcTransport(TranslationServiceTransport):
@@ -57,7 +58,9 @@ def __init__(
channel: grpc.Channel = None,
api_mtls_endpoint: str = None,
client_cert_source: Callable[[], Tuple[bytes, bytes]] = None,
- quota_project_id: Optional[str] = None
+ ssl_channel_credentials: grpc.ChannelCredentials = None,
+ quota_project_id: Optional[str] = None,
+ client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO,
) -> None:
"""Instantiate the transport.
@@ -76,16 +79,23 @@ def __init__(
ignored if ``channel`` is provided.
channel (Optional[grpc.Channel]): A ``Channel`` instance through
which to make calls.
- api_mtls_endpoint (Optional[str]): The mutual TLS endpoint. If
- provided, it overrides the ``host`` argument and tries to create
+ 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]]]): 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.
+ 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.
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
@@ -101,6 +111,11 @@ def __init__(
# If a channel was explicitly provided, set it.
self._grpc_channel = channel
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
@@ -131,6 +146,23 @@ def __init__(
scopes=scopes or self.AUTH_SCOPES,
quota_project_id=quota_project_id,
)
+ 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
+ )
+
+ # 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,
+ scopes=scopes or self.AUTH_SCOPES,
+ quota_project_id=quota_project_id,
+ )
self._stubs = {} # type: Dict[str, Callable]
@@ -141,6 +173,7 @@ def __init__(
credentials_file=credentials_file,
scopes=scopes or self.AUTH_SCOPES,
quota_project_id=quota_project_id,
+ client_info=client_info,
)
@classmethod
@@ -151,7 +184,7 @@ def create_channel(
credentials_file: str = None,
scopes: Optional[Sequence[str]] = None,
quota_project_id: Optional[str] = None,
- **kwargs
+ **kwargs,
) -> grpc.Channel:
"""Create and return a gRPC channel object.
Args:
@@ -185,7 +218,7 @@ def create_channel(
credentials_file=credentials_file,
scopes=scopes,
quota_project_id=quota_project_id,
- **kwargs
+ **kwargs,
)
@property
@@ -195,13 +228,6 @@ def grpc_channel(self) -> grpc.Channel:
This property caches on the instance; repeated calls return
the same channel.
"""
- # Sanity check: Only create a new channel if we do not already
- # have one.
- if not hasattr(self, "_grpc_channel"):
- self._grpc_channel = self.create_channel(
- self._host, credentials=self._credentials,
- )
-
# Return the channel from cache.
return self._grpc_channel
diff --git a/google/cloud/translate_v3/services/translation_service/transports/grpc_asyncio.py b/google/cloud/translate_v3/services/translation_service/transports/grpc_asyncio.py
index 7fb7d890..e7e9c05c 100644
--- a/google/cloud/translate_v3/services/translation_service/transports/grpc_asyncio.py
+++ b/google/cloud/translate_v3/services/translation_service/transports/grpc_asyncio.py
@@ -15,10 +15,13 @@
# 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
@@ -28,7 +31,7 @@
from google.cloud.translate_v3.types import translation_service
from google.longrunning import operations_pb2 as operations # type: ignore
-from .base import TranslationServiceTransport
+from .base import TranslationServiceTransport, DEFAULT_CLIENT_INFO
from .grpc import TranslationServiceGrpcTransport
@@ -99,7 +102,9 @@ def __init__(
channel: aio.Channel = None,
api_mtls_endpoint: str = None,
client_cert_source: Callable[[], Tuple[bytes, bytes]] = None,
+ ssl_channel_credentials: grpc.ChannelCredentials = None,
quota_project_id=None,
+ client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO,
) -> None:
"""Instantiate the transport.
@@ -119,16 +124,23 @@ def __init__(
are passed to :func:`google.auth.default`.
channel (Optional[aio.Channel]): A ``Channel`` instance through
which to make calls.
- api_mtls_endpoint (Optional[str]): The mutual TLS endpoint. If
- provided, it overrides the ``host`` argument and tries to create
+ 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]]]): 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.
+ 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.
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
@@ -144,12 +156,22 @@ def __init__(
# If a channel was explicitly provided, set it.
self._grpc_channel = channel
elif api_mtls_endpoint:
+ warnings.warn(
+ "api_mtls_endpoint and client_cert_source are deprecated",
+ DeprecationWarning,
+ )
+
host = (
api_mtls_endpoint
if ":" in api_mtls_endpoint
else api_mtls_endpoint + ":443"
)
+ if credentials is None:
+ credentials, _ = auth.default(
+ scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id
+ )
+
# Create SSL credentials with client_cert_source or application
# default SSL credentials.
if client_cert_source:
@@ -169,6 +191,23 @@ def __init__(
scopes=scopes or self.AUTH_SCOPES,
quota_project_id=quota_project_id,
)
+ 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
+ )
+
+ # 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,
+ scopes=scopes or self.AUTH_SCOPES,
+ quota_project_id=quota_project_id,
+ )
# Run the base constructor.
super().__init__(
@@ -177,6 +216,7 @@ def __init__(
credentials_file=credentials_file,
scopes=scopes or self.AUTH_SCOPES,
quota_project_id=quota_project_id,
+ client_info=client_info,
)
self._stubs = {}
@@ -188,13 +228,6 @@ def grpc_channel(self) -> aio.Channel:
This property caches on the instance; repeated calls return
the same channel.
"""
- # Sanity check: Only create a new channel if we do not already
- # have one.
- if not hasattr(self, "_grpc_channel"):
- self._grpc_channel = self.create_channel(
- self._host, credentials=self._credentials,
- )
-
# Return the channel from cache.
return self._grpc_channel
diff --git a/google/cloud/translate_v3beta1/services/translation_service/async_client.py b/google/cloud/translate_v3beta1/services/translation_service/async_client.py
index fe0e508b..9054a09b 100644
--- a/google/cloud/translate_v3beta1/services/translation_service/async_client.py
+++ b/google/cloud/translate_v3beta1/services/translation_service/async_client.py
@@ -28,13 +28,13 @@
from google.auth import credentials # type: ignore
from google.oauth2 import service_account # type: ignore
-from google.api_core import operation
-from google.api_core import operation_async
+from google.api_core import operation # type: ignore
+from google.api_core import operation_async # type: ignore
from google.cloud.translate_v3beta1.services.translation_service import pagers
from google.cloud.translate_v3beta1.types import translation_service
from google.protobuf import timestamp_pb2 as timestamp # type: ignore
-from .transports.base import TranslationServiceTransport
+from .transports.base import TranslationServiceTransport, DEFAULT_CLIENT_INFO
from .transports.grpc_asyncio import TranslationServiceGrpcAsyncIOTransport
from .client import TranslationServiceClient
@@ -48,6 +48,7 @@ class TranslationServiceAsyncClient:
DEFAULT_MTLS_ENDPOINT = TranslationServiceClient.DEFAULT_MTLS_ENDPOINT
glossary_path = staticmethod(TranslationServiceClient.glossary_path)
+ parse_glossary_path = staticmethod(TranslationServiceClient.parse_glossary_path)
from_service_account_file = TranslationServiceClient.from_service_account_file
from_service_account_json = from_service_account_file
@@ -63,6 +64,7 @@ def __init__(
credentials: credentials.Credentials = None,
transport: Union[str, TranslationServiceTransport] = "grpc_asyncio",
client_options: ClientOptions = None,
+ client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO,
) -> None:
"""Instantiate the translation service client.
@@ -78,16 +80,19 @@ def __init__(
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
+ 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, this is the default value for
- the environment variable) and "auto" (auto switch to the default
- mTLS endpoint if client SSL credentials is present). However,
- the ``api_endpoint`` property takes precedence if provided.
- (2) The ``client_cert_source`` property is used to provide client
- SSL credentials for mutual TLS transport. If not provided, the
- default SSL credentials will be used if present.
+ 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
@@ -95,7 +100,10 @@ def __init__(
"""
self._client = TranslationServiceClient(
- credentials=credentials, transport=transport, client_options=client_options,
+ credentials=credentials,
+ transport=transport,
+ client_options=client_options,
+ client_info=client_info,
)
async def translate_text(
@@ -132,7 +140,7 @@ async def translate_text(
rpc = gapic_v1.method_async.wrap_method(
self._client._transport.translate_text,
default_timeout=600.0,
- client_info=_client_info,
+ client_info=DEFAULT_CLIENT_INFO,
)
# Certain fields should be provided within the metadata header;
@@ -243,7 +251,7 @@ async def detect_language(
rpc = gapic_v1.method_async.wrap_method(
self._client._transport.detect_language,
default_timeout=600.0,
- client_info=_client_info,
+ client_info=DEFAULT_CLIENT_INFO,
)
# Certain fields should be provided within the metadata header;
@@ -365,11 +373,11 @@ async def get_supported_languages(
maximum=60.0,
multiplier=1.3,
predicate=retries.if_exception_type(
- exceptions.DeadlineExceeded, exceptions.ServiceUnavailable,
+ exceptions.ServiceUnavailable, exceptions.DeadlineExceeded,
),
),
default_timeout=600.0,
- client_info=_client_info,
+ client_info=DEFAULT_CLIENT_INFO,
)
# Certain fields should be provided within the metadata header;
@@ -433,7 +441,7 @@ async def batch_translate_text(
rpc = gapic_v1.method_async.wrap_method(
self._client._transport.batch_translate_text,
default_timeout=600.0,
- client_info=_client_info,
+ client_info=DEFAULT_CLIENT_INFO,
)
# Certain fields should be provided within the metadata header;
@@ -522,7 +530,7 @@ async def create_glossary(
rpc = gapic_v1.method_async.wrap_method(
self._client._transport.create_glossary,
default_timeout=600.0,
- client_info=_client_info,
+ client_info=DEFAULT_CLIENT_INFO,
)
# Certain fields should be provided within the metadata header;
@@ -620,11 +628,11 @@ async def list_glossaries(
maximum=60.0,
multiplier=1.3,
predicate=retries.if_exception_type(
- exceptions.DeadlineExceeded, exceptions.ServiceUnavailable,
+ exceptions.ServiceUnavailable, exceptions.DeadlineExceeded,
),
),
default_timeout=600.0,
- client_info=_client_info,
+ client_info=DEFAULT_CLIENT_INFO,
)
# Certain fields should be provided within the metadata header;
@@ -705,11 +713,11 @@ async def get_glossary(
maximum=60.0,
multiplier=1.3,
predicate=retries.if_exception_type(
- exceptions.DeadlineExceeded, exceptions.ServiceUnavailable,
+ exceptions.ServiceUnavailable, exceptions.DeadlineExceeded,
),
),
default_timeout=600.0,
- client_info=_client_info,
+ client_info=DEFAULT_CLIENT_INFO,
)
# Certain fields should be provided within the metadata header;
@@ -790,11 +798,11 @@ async def delete_glossary(
maximum=60.0,
multiplier=1.3,
predicate=retries.if_exception_type(
- exceptions.DeadlineExceeded, exceptions.ServiceUnavailable,
+ exceptions.ServiceUnavailable, exceptions.DeadlineExceeded,
),
),
default_timeout=600.0,
- client_info=_client_info,
+ client_info=DEFAULT_CLIENT_INFO,
)
# Certain fields should be provided within the metadata header;
@@ -819,11 +827,11 @@ async def delete_glossary(
try:
- _client_info = gapic_v1.client_info.ClientInfo(
+ DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo(
gapic_version=pkg_resources.get_distribution("google-cloud-translate",).version,
)
except pkg_resources.DistributionNotFound:
- _client_info = gapic_v1.client_info.ClientInfo()
+ DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo()
__all__ = ("TranslationServiceAsyncClient",)
diff --git a/google/cloud/translate_v3beta1/services/translation_service/client.py b/google/cloud/translate_v3beta1/services/translation_service/client.py
index 6d991415..47a82cca 100644
--- a/google/cloud/translate_v3beta1/services/translation_service/client.py
+++ b/google/cloud/translate_v3beta1/services/translation_service/client.py
@@ -16,27 +16,29 @@
#
from collections import OrderedDict
+from distutils import util
import os
import re
-from typing import Callable, Dict, Sequence, Tuple, Type, Union
+from typing import Callable, Dict, Optional, Sequence, Tuple, Type, Union
import pkg_resources
-import google.api_core.client_options as ClientOptions # type: ignore
+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
-from google.api_core import operation_async
+from google.api_core import operation # type: ignore
+from google.api_core import operation_async # type: ignore
from google.cloud.translate_v3beta1.services.translation_service import pagers
from google.cloud.translate_v3beta1.types import translation_service
from google.protobuf import timestamp_pb2 as timestamp # type: ignore
-from .transports.base import TranslationServiceTransport
+from .transports.base import TranslationServiceTransport, DEFAULT_CLIENT_INFO
from .transports.grpc import TranslationServiceGrpcTransport
from .transports.grpc_asyncio import TranslationServiceGrpcAsyncIOTransport
@@ -152,9 +154,10 @@ def parse_glossary_path(path: str) -> Dict[str, str]:
def __init__(
self,
*,
- credentials: credentials.Credentials = None,
- transport: Union[str, TranslationServiceTransport] = None,
- client_options: ClientOptions = None,
+ credentials: Optional[credentials.Credentials] = None,
+ transport: Union[str, TranslationServiceTransport, None] = None,
+ client_options: Optional[client_options_lib.ClientOptions] = None,
+ client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO,
) -> None:
"""Instantiate the translation service client.
@@ -167,48 +170,74 @@ def __init__(
transport (Union[str, ~.TranslationServiceTransport]): 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.
+ client_options (client_options_lib.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
+ 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, this is the default value for
- the environment variable) and "auto" (auto switch to the default
- mTLS endpoint if client SSL credentials is present). However,
- the ``api_endpoint`` property takes precedence if provided.
- (2) The ``client_cert_source`` property is used to provide client
- SSL credentials for mutual TLS transport. If not provided, the
- default SSL credentials will be used if present.
+ 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 = ClientOptions.from_dict(client_options)
+ client_options = client_options_lib.from_dict(client_options)
if client_options is None:
- client_options = ClientOptions.ClientOptions()
+ client_options = client_options_lib.ClientOptions()
- if client_options.api_endpoint is None:
- use_mtls_env = os.getenv("GOOGLE_API_USE_MTLS", "never")
+ # Create SSL credentials for mutual TLS if needed.
+ use_client_cert = bool(
+ util.strtobool(os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false"))
+ )
+
+ ssl_credentials = 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
+ else:
+ creds = SslCredentials()
+ is_mtls = creds.is_mtls
+ ssl_credentials = creds.ssl_credentials 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":
- client_options.api_endpoint = self.DEFAULT_ENDPOINT
+ api_endpoint = self.DEFAULT_ENDPOINT
elif use_mtls_env == "always":
- client_options.api_endpoint = self.DEFAULT_MTLS_ENDPOINT
+ api_endpoint = self.DEFAULT_MTLS_ENDPOINT
elif use_mtls_env == "auto":
- has_client_cert_source = (
- client_options.client_cert_source is not None
- or mtls.has_default_client_cert_source()
- )
- client_options.api_endpoint = (
- self.DEFAULT_MTLS_ENDPOINT
- if has_client_cert_source
- else self.DEFAULT_ENDPOINT
+ api_endpoint = (
+ self.DEFAULT_MTLS_ENDPOINT if is_mtls else self.DEFAULT_ENDPOINT
)
else:
raise MutualTLSChannelError(
- "Unsupported GOOGLE_API_USE_MTLS value. Accepted values: never, auto, always"
+ "Unsupported GOOGLE_API_USE_MTLS_ENDPOINT value. Accepted values: never, auto, always"
)
# Save or instantiate the transport.
@@ -232,11 +261,11 @@ def __init__(
self._transport = Transport(
credentials=credentials,
credentials_file=client_options.credentials_file,
- host=client_options.api_endpoint,
+ host=api_endpoint,
scopes=client_options.scopes,
- api_mtls_endpoint=client_options.api_endpoint,
- client_cert_source=client_options.client_cert_source,
+ ssl_channel_credentials=ssl_credentials,
quota_project_id=client_options.quota_project_id,
+ client_info=client_info,
)
def translate_text(
@@ -942,11 +971,11 @@ def delete_glossary(
try:
- _client_info = gapic_v1.client_info.ClientInfo(
+ DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo(
gapic_version=pkg_resources.get_distribution("google-cloud-translate",).version,
)
except pkg_resources.DistributionNotFound:
- _client_info = gapic_v1.client_info.ClientInfo()
+ DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo()
__all__ = ("TranslationServiceClient",)
diff --git a/google/cloud/translate_v3beta1/services/translation_service/transports/base.py b/google/cloud/translate_v3beta1/services/translation_service/transports/base.py
index b532a056..7c9f6810 100644
--- a/google/cloud/translate_v3beta1/services/translation_service/transports/base.py
+++ b/google/cloud/translate_v3beta1/services/translation_service/transports/base.py
@@ -19,7 +19,7 @@
import typing
import pkg_resources
-from google import auth
+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
@@ -31,11 +31,11 @@
try:
- _client_info = gapic_v1.client_info.ClientInfo(
+ DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo(
gapic_version=pkg_resources.get_distribution("google-cloud-translate",).version,
)
except pkg_resources.DistributionNotFound:
- _client_info = gapic_v1.client_info.ClientInfo()
+ DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo()
class TranslationServiceTransport(abc.ABC):
@@ -54,6 +54,7 @@ def __init__(
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.
@@ -71,6 +72,11 @@ def __init__(
scope (Optional[Sequence[str]]): A list of scopes.
quota_project_id (Optional[str]): An optional project to use for billing
and quota.
+ client_info (google.api_core.gapic_v1.client_info.ClientInfo):
+ The client info used to send a user-agent string along with
+ API requests. If ``None``, then default info will be used.
+ Generally, you only need to set this if you're developing
+ your own client library.
"""
# Save the hostname. Default to port 443 (HTTPS) if none is specified.
if ":" not in host:
@@ -98,16 +104,16 @@ def __init__(
self._credentials = credentials
# Lifted into its own function so it can be stubbed out during tests.
- self._prep_wrapped_messages()
+ self._prep_wrapped_messages(client_info)
- def _prep_wrapped_messages(self):
+ def _prep_wrapped_messages(self, client_info):
# Precompute the wrapped methods.
self._wrapped_methods = {
self.translate_text: gapic_v1.method.wrap_method(
- self.translate_text, default_timeout=600.0, client_info=_client_info,
+ self.translate_text, default_timeout=600.0, client_info=client_info,
),
self.detect_language: gapic_v1.method.wrap_method(
- self.detect_language, default_timeout=600.0, client_info=_client_info,
+ self.detect_language, default_timeout=600.0, client_info=client_info,
),
self.get_supported_languages: gapic_v1.method.wrap_method(
self.get_supported_languages,
@@ -116,19 +122,19 @@ def _prep_wrapped_messages(self):
maximum=60.0,
multiplier=1.3,
predicate=retries.if_exception_type(
- exceptions.DeadlineExceeded, exceptions.ServiceUnavailable,
+ exceptions.ServiceUnavailable, exceptions.DeadlineExceeded,
),
),
default_timeout=600.0,
- client_info=_client_info,
+ client_info=client_info,
),
self.batch_translate_text: gapic_v1.method.wrap_method(
self.batch_translate_text,
default_timeout=600.0,
- client_info=_client_info,
+ client_info=client_info,
),
self.create_glossary: gapic_v1.method.wrap_method(
- self.create_glossary, default_timeout=600.0, client_info=_client_info,
+ self.create_glossary, default_timeout=600.0, client_info=client_info,
),
self.list_glossaries: gapic_v1.method.wrap_method(
self.list_glossaries,
@@ -137,11 +143,11 @@ def _prep_wrapped_messages(self):
maximum=60.0,
multiplier=1.3,
predicate=retries.if_exception_type(
- exceptions.DeadlineExceeded, exceptions.ServiceUnavailable,
+ exceptions.ServiceUnavailable, exceptions.DeadlineExceeded,
),
),
default_timeout=600.0,
- client_info=_client_info,
+ client_info=client_info,
),
self.get_glossary: gapic_v1.method.wrap_method(
self.get_glossary,
@@ -150,11 +156,11 @@ def _prep_wrapped_messages(self):
maximum=60.0,
multiplier=1.3,
predicate=retries.if_exception_type(
- exceptions.DeadlineExceeded, exceptions.ServiceUnavailable,
+ exceptions.ServiceUnavailable, exceptions.DeadlineExceeded,
),
),
default_timeout=600.0,
- client_info=_client_info,
+ client_info=client_info,
),
self.delete_glossary: gapic_v1.method.wrap_method(
self.delete_glossary,
@@ -163,11 +169,11 @@ def _prep_wrapped_messages(self):
maximum=60.0,
multiplier=1.3,
predicate=retries.if_exception_type(
- exceptions.DeadlineExceeded, exceptions.ServiceUnavailable,
+ exceptions.ServiceUnavailable, exceptions.DeadlineExceeded,
),
),
default_timeout=600.0,
- client_info=_client_info,
+ client_info=client_info,
),
}
diff --git a/google/cloud/translate_v3beta1/services/translation_service/transports/grpc.py b/google/cloud/translate_v3beta1/services/translation_service/transports/grpc.py
index f6dadf28..88882482 100644
--- a/google/cloud/translate_v3beta1/services/translation_service/transports/grpc.py
+++ b/google/cloud/translate_v3beta1/services/translation_service/transports/grpc.py
@@ -15,21 +15,22 @@
# 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.translate_v3beta1.types import translation_service
from google.longrunning import operations_pb2 as operations # type: ignore
-from .base import TranslationServiceTransport
+from .base import TranslationServiceTransport, DEFAULT_CLIENT_INFO
class TranslationServiceGrpcTransport(TranslationServiceTransport):
@@ -57,7 +58,9 @@ def __init__(
channel: grpc.Channel = None,
api_mtls_endpoint: str = None,
client_cert_source: Callable[[], Tuple[bytes, bytes]] = None,
- quota_project_id: Optional[str] = None
+ ssl_channel_credentials: grpc.ChannelCredentials = None,
+ quota_project_id: Optional[str] = None,
+ client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO,
) -> None:
"""Instantiate the transport.
@@ -76,16 +79,23 @@ def __init__(
ignored if ``channel`` is provided.
channel (Optional[grpc.Channel]): A ``Channel`` instance through
which to make calls.
- api_mtls_endpoint (Optional[str]): The mutual TLS endpoint. If
- provided, it overrides the ``host`` argument and tries to create
+ 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]]]): 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.
+ 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.
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
@@ -101,6 +111,11 @@ def __init__(
# If a channel was explicitly provided, set it.
self._grpc_channel = channel
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
@@ -131,6 +146,23 @@ def __init__(
scopes=scopes or self.AUTH_SCOPES,
quota_project_id=quota_project_id,
)
+ 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
+ )
+
+ # 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,
+ scopes=scopes or self.AUTH_SCOPES,
+ quota_project_id=quota_project_id,
+ )
self._stubs = {} # type: Dict[str, Callable]
@@ -141,6 +173,7 @@ def __init__(
credentials_file=credentials_file,
scopes=scopes or self.AUTH_SCOPES,
quota_project_id=quota_project_id,
+ client_info=client_info,
)
@classmethod
@@ -151,7 +184,7 @@ def create_channel(
credentials_file: str = None,
scopes: Optional[Sequence[str]] = None,
quota_project_id: Optional[str] = None,
- **kwargs
+ **kwargs,
) -> grpc.Channel:
"""Create and return a gRPC channel object.
Args:
@@ -185,7 +218,7 @@ def create_channel(
credentials_file=credentials_file,
scopes=scopes,
quota_project_id=quota_project_id,
- **kwargs
+ **kwargs,
)
@property
@@ -195,13 +228,6 @@ def grpc_channel(self) -> grpc.Channel:
This property caches on the instance; repeated calls return
the same channel.
"""
- # Sanity check: Only create a new channel if we do not already
- # have one.
- if not hasattr(self, "_grpc_channel"):
- self._grpc_channel = self.create_channel(
- self._host, credentials=self._credentials,
- )
-
# Return the channel from cache.
return self._grpc_channel
diff --git a/google/cloud/translate_v3beta1/services/translation_service/transports/grpc_asyncio.py b/google/cloud/translate_v3beta1/services/translation_service/transports/grpc_asyncio.py
index e7f63e99..883c06a6 100644
--- a/google/cloud/translate_v3beta1/services/translation_service/transports/grpc_asyncio.py
+++ b/google/cloud/translate_v3beta1/services/translation_service/transports/grpc_asyncio.py
@@ -15,10 +15,13 @@
# 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
@@ -28,7 +31,7 @@
from google.cloud.translate_v3beta1.types import translation_service
from google.longrunning import operations_pb2 as operations # type: ignore
-from .base import TranslationServiceTransport
+from .base import TranslationServiceTransport, DEFAULT_CLIENT_INFO
from .grpc import TranslationServiceGrpcTransport
@@ -99,7 +102,9 @@ def __init__(
channel: aio.Channel = None,
api_mtls_endpoint: str = None,
client_cert_source: Callable[[], Tuple[bytes, bytes]] = None,
+ ssl_channel_credentials: grpc.ChannelCredentials = None,
quota_project_id=None,
+ client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO,
) -> None:
"""Instantiate the transport.
@@ -119,16 +124,23 @@ def __init__(
are passed to :func:`google.auth.default`.
channel (Optional[aio.Channel]): A ``Channel`` instance through
which to make calls.
- api_mtls_endpoint (Optional[str]): The mutual TLS endpoint. If
- provided, it overrides the ``host`` argument and tries to create
+ 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]]]): 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.
+ 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.
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
@@ -144,12 +156,22 @@ def __init__(
# If a channel was explicitly provided, set it.
self._grpc_channel = channel
elif api_mtls_endpoint:
+ warnings.warn(
+ "api_mtls_endpoint and client_cert_source are deprecated",
+ DeprecationWarning,
+ )
+
host = (
api_mtls_endpoint
if ":" in api_mtls_endpoint
else api_mtls_endpoint + ":443"
)
+ if credentials is None:
+ credentials, _ = auth.default(
+ scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id
+ )
+
# Create SSL credentials with client_cert_source or application
# default SSL credentials.
if client_cert_source:
@@ -169,6 +191,23 @@ def __init__(
scopes=scopes or self.AUTH_SCOPES,
quota_project_id=quota_project_id,
)
+ 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
+ )
+
+ # 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,
+ scopes=scopes or self.AUTH_SCOPES,
+ quota_project_id=quota_project_id,
+ )
# Run the base constructor.
super().__init__(
@@ -177,6 +216,7 @@ def __init__(
credentials_file=credentials_file,
scopes=scopes or self.AUTH_SCOPES,
quota_project_id=quota_project_id,
+ client_info=client_info,
)
self._stubs = {}
@@ -188,13 +228,6 @@ def grpc_channel(self) -> aio.Channel:
This property caches on the instance; repeated calls return
the same channel.
"""
- # Sanity check: Only create a new channel if we do not already
- # have one.
- if not hasattr(self, "_grpc_channel"):
- self._grpc_channel = self.create_channel(
- self._host, credentials=self._credentials,
- )
-
# Return the channel from cache.
return self._grpc_channel
diff --git a/noxfile.py b/noxfile.py
index 86bba293..845cd5f9 100644
--- a/noxfile.py
+++ b/noxfile.py
@@ -173,7 +173,9 @@ def docfx(session):
"""Build the docfx yaml files for this library."""
session.install("-e", ".")
- session.install("sphinx", "alabaster", "recommonmark", "sphinx-docfx-yaml")
+ # sphinx-docfx-yaml supports up to sphinx version 1.5.5.
+ # https://github.com/docascode/sphinx-docfx-yaml/issues/97
+ session.install("sphinx==1.5.5", "alabaster", "recommonmark", "sphinx-docfx-yaml")
shutil.rmtree(os.path.join("docs", "_build"), ignore_errors=True)
session.run(
diff --git a/samples/snippets/beta_snippets.py b/samples/snippets/beta_snippets.py
index 10ec2dc6..6b770e61 100644
--- a/samples/snippets/beta_snippets.py
+++ b/samples/snippets/beta_snippets.py
@@ -19,11 +19,12 @@
def translate_text(project_id, text):
# [START translate_translate_text_beta]
from google.cloud import translate_v3beta1 as translate
+
client = translate.TranslationServiceClient()
# project_id = YOUR_PROJECT_ID
# text = 'Text you wish to translate'
- location = 'global'
+ location = "global"
parent = f"projects/{project_id}/locations/{location}"
@@ -33,38 +34,38 @@ def translate_text(project_id, text):
"contents": [text],
"mime_type": "text/plain", # mime types: text/plain, text/html
"source_language_code": "en-US",
- "target_language_code": "sr-Latn"
+ "target_language_code": "sr-Latn",
}
)
for translation in response.translations:
- print(u'Translated Text: {}'.format(translation))
+ print("Translated Text: {}".format(translation))
# [END translate_translate_text_beta]
def batch_translate_text(project_id, input_uri, output_uri):
# [START translate_batch_translate_text_beta]
from google.cloud import translate_v3beta1 as translate
+
client = translate.TranslationServiceClient()
# project_id = YOUR_PROJECT_ID
# input_uri = 'gs://cloud-samples-data/translation/text.txt'
# output_uri = 'gs://YOUR_BUCKET_ID/path_to_store_results/'
- location = 'us-central1'
+ location = "us-central1"
parent = f"projects/{project_id}/locations/{location}"
gcs_source = translate.types.GcsSource(input_uri=input_uri)
input_config = translate.types.InputConfig(
- mime_type='text/plain', # mime types: text/plain, text/html
- gcs_source=gcs_source)
+ mime_type="text/plain", # mime types: text/plain, text/html
+ gcs_source=gcs_source,
+ )
- gcs_destination = translate.types.GcsDestination(
- output_uri_prefix=output_uri)
+ gcs_destination = translate.types.GcsDestination(output_uri_prefix=output_uri)
- output_config = translate.types.OutputConfig(
- gcs_destination=gcs_destination)
+ output_config = translate.types.OutputConfig(gcs_destination=gcs_destination)
operation = client.batch_translate_text(
request={
@@ -72,25 +73,26 @@ def batch_translate_text(project_id, input_uri, output_uri):
"source_language_code": "en-US",
"target_language_codes": ["sr-Latn"],
"input_configs": [input_config],
- "output_config": output_config
+ "output_config": output_config,
}
)
- result = operation.result(timeout=240)
+ result = operation.result(timeout=320)
- print(u'Total Characters: {}'.format(result.total_characters))
- print(u'Translated Characters: {}'.format(result.translated_characters))
+ print("Total Characters: {}".format(result.total_characters))
+ print("Translated Characters: {}".format(result.translated_characters))
# [END translate_batch_translate_text_beta]
def detect_language(project_id, text):
# [START translate_detect_language_beta]
from google.cloud import translate_v3beta1 as translate
+
client = translate.TranslationServiceClient()
# project_id = YOUR_PROJECT_ID
# text = 'Text you wish to translate'
- location = 'global'
+ location = "global"
parent = f"projects/{project_id}/locations/{location}"
@@ -98,176 +100,178 @@ def detect_language(project_id, text):
request={
"parent": parent,
"content": text,
- "mime_type": "text/plain" # mime types: text/plain, text/html
+ "mime_type": "text/plain", # mime types: text/plain, text/html
}
)
for language in response.languages:
- print(u'Language Code: {} (Confidence: {})'.format(
- language.language_code,
- language.confidence))
+ print(
+ "Language Code: {} (Confidence: {})".format(
+ language.language_code, language.confidence
+ )
+ )
# [END translate_detect_language_beta]
def list_languages(project_id):
# [START translate_list_codes_beta]
from google.cloud import translate_v3beta1 as translate
+
client = translate.TranslationServiceClient()
# project_id = YOUR_PROJECT_ID
- location = 'global'
+ location = "global"
parent = f"projects/{project_id}/locations/{location}"
response = client.get_supported_languages(parent=parent)
- print('Supported Languages:')
+ print("Supported Languages:")
for language in response.languages:
- print(u'Language Code: {}'.format(language.language_code))
+ print("Language Code: {}".format(language.language_code))
# [END translate_list_codes_beta]
def list_languages_with_target(project_id, display_language_code):
# [START translate_list_language_names_beta]
from google.cloud import translate_v3beta1 as translate
+
client = translate.TranslationServiceClient()
# project_id = YOUR_PROJECT_ID
# display_language_code = 'is'
- location = 'global'
+ location = "global"
parent = f"projects/{project_id}/locations/{location}"
response = client.get_supported_languages(
- parent=parent,
- display_language_code=display_language_code)
+ parent=parent, display_language_code=display_language_code
+ )
- print('Supported Languages:')
+ print("Supported Languages:")
for language in response.languages:
- print(u'Language Code: {}'.format(language.language_code))
- print(u'Display Name: {}\n'.format(language.display_name))
+ print("Language Code: {}".format(language.language_code))
+ print("Display Name: {}\n".format(language.display_name))
# [END translate_list_language_names_beta]
def create_glossary(project_id, glossary_id):
# [START translate_create_glossary_beta]
from google.cloud import translate_v3beta1 as translate
+
client = translate.TranslationServiceClient()
# project_id = 'YOUR_PROJECT_ID'
# glossary_id = 'glossary-id'
- location = 'us-central1' # The location of the glossary
+ location = "us-central1" # The location of the glossary
- name = client.glossary_path(
- project_id,
- location,
- glossary_id)
+ name = client.glossary_path(project_id, location, glossary_id)
language_codes_set = translate.types.Glossary.LanguageCodesSet(
- language_codes=['en', 'es'])
+ language_codes=["en", "es"]
+ )
gcs_source = translate.types.GcsSource(
- input_uri='gs://cloud-samples-data/translation/glossary.csv')
+ input_uri="gs://cloud-samples-data/translation/glossary.csv"
+ )
- input_config = translate.types.GlossaryInputConfig(
- gcs_source=gcs_source)
+ input_config = translate.types.GlossaryInputConfig(gcs_source=gcs_source)
glossary = translate.types.Glossary(
- name=name,
- language_codes_set=language_codes_set,
- input_config=input_config)
+ name=name, language_codes_set=language_codes_set, input_config=input_config
+ )
parent = f"projects/{project_id}/locations/{location}"
operation = client.create_glossary(parent=parent, glossary=glossary)
result = operation.result(timeout=90)
- print(u'Created: {}'.format(result.name))
- print(u'Input Uri: {}'.format(result.input_config.gcs_source.input_uri))
+ print("Created: {}".format(result.name))
+ print("Input Uri: {}".format(result.input_config.gcs_source.input_uri))
# [END translate_create_glossary_beta]
def list_glossaries(project_id):
# [START translate_list_glossary_beta]
from google.cloud import translate_v3beta1 as translate
+
client = translate.TranslationServiceClient()
# project_id = 'YOUR_PROJECT_ID'
- location = 'us-central1' # The location of the glossary
+ location = "us-central1" # The location of the glossary
parent = f"projects/{project_id}/locations/{location}"
for glossary in client.list_glossaries(parent=parent):
- print(u'Name: {}'.format(glossary.name))
- print(u'Entry count: {}'.format(glossary.entry_count))
- print(u'Input uri: {}'.format(
- glossary.input_config.gcs_source.input_uri))
+ print("Name: {}".format(glossary.name))
+ print("Entry count: {}".format(glossary.entry_count))
+ print("Input uri: {}".format(glossary.input_config.gcs_source.input_uri))
for language_code in glossary.language_codes_set.language_codes:
- print(u'Language code: {}'.format(language_code))
+ print("Language code: {}".format(language_code))
# [END translate_list_glossary_beta]
def get_glossary(project_id, glossary_id):
# [START translate_get_glossary_beta]
from google.cloud import translate_v3beta1 as translate
+
client = translate.TranslationServiceClient()
# project_id = 'YOUR_PROJECT_ID'
# glossary_id = 'GLOSSARY_ID'
name = client.glossary_path(
- project_id,
- 'us-central1', # The location of the glossary
- glossary_id)
+ project_id, "us-central1", glossary_id # The location of the glossary
+ )
response = client.get_glossary(name=name)
- print(u'Name: {}'.format(response.name))
- print(u'Language Pair:')
- print(u'\tSource Language Code: {}'.format(
- response.language_pair.source_language_code))
- print(u'\tTarget Language Code: {}'.format(
- response.language_pair.target_language_code))
- print(u'Input Uri: {}'.format(
- response.input_config.gcs_source.input_uri))
+ print("Name: {}".format(response.name))
+ print("Language Pair:")
+ print(
+ "\tSource Language Code: {}".format(response.language_pair.source_language_code)
+ )
+ print(
+ "\tTarget Language Code: {}".format(response.language_pair.target_language_code)
+ )
+ print("Input Uri: {}".format(response.input_config.gcs_source.input_uri))
# [END translate_get_glossary_beta]
def delete_glossary(project_id, glossary_id):
# [START translate_delete_glossary_beta]
from google.cloud import translate_v3beta1 as translate
+
client = translate.TranslationServiceClient()
# project_id = 'YOUR_PROJECT_ID'
# glossary_id = 'GLOSSARY_ID'
name = client.glossary_path(
- project_id,
- 'us-central1', # The location of the glossary
- glossary_id)
+ project_id, "us-central1", glossary_id # The location of the glossary
+ )
operation = client.delete_glossary(name=name)
result = operation.result(timeout=90)
- print(u'Deleted: {}'.format(result.name))
+ print("Deleted: {}".format(result.name))
# [END translate_delete_glossary_beta]
def translate_text_with_glossary(project_id, glossary_id, text):
# [START translate_translate_text_with_glossary_beta]
from google.cloud import translate_v3beta1 as translate
+
client = translate.TranslationServiceClient()
# project_id = 'YOUR_PROJECT_ID'
# glossary_id = 'GLOSSARY_ID'
# text = 'Text you wish to translate'
- location = 'us-central1' # The location of the glossary
+ location = "us-central1" # The location of the glossary
glossary = client.glossary_path(
- project_id,
- 'us-central1', # The location of the glossary
- glossary_id)
+ project_id, "us-central1", glossary_id # The location of the glossary
+ )
- glossary_config = translate.types.TranslateTextGlossaryConfig(
- glossary=glossary)
+ glossary_config = translate.types.TranslateTextGlossaryConfig(glossary=glossary)
parent = f"projects/{project_id}/locations/{location}"
@@ -278,7 +282,7 @@ def translate_text_with_glossary(project_id, glossary_id, text):
"mime_type": "text/plain",
"source_language_code": "en",
"target_language_code": "es",
- "glossary_config": glossary_config
+ "glossary_config": glossary_config,
}
)
@@ -287,84 +291,92 @@ def translate_text_with_glossary(project_id, glossary_id, text):
# [END translate_translate_text_with_glossary_beta]
-if __name__ == '__main__':
+if __name__ == "__main__":
parser = argparse.ArgumentParser(
- description=__doc__,
- formatter_class=argparse.RawDescriptionHelpFormatter)
+ description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter
+ )
- subparsers = parser.add_subparsers(dest='command')
+ subparsers = parser.add_subparsers(dest="command")
translate_text_parser = subparsers.add_parser(
- 'translate-text', help=translate_text.__doc__)
- translate_text_parser.add_argument('project_id')
- translate_text_parser.add_argument('text')
+ "translate-text", help=translate_text.__doc__
+ )
+ translate_text_parser.add_argument("project_id")
+ translate_text_parser.add_argument("text")
batch_translate_text_parser = subparsers.add_parser(
- 'batch-translate-text', help=translate_text.__doc__)
- batch_translate_text_parser.add_argument('project_id')
- batch_translate_text_parser.add_argument('gcs_source')
- batch_translate_text_parser.add_argument('gcs_destination')
+ "batch-translate-text", help=translate_text.__doc__
+ )
+ batch_translate_text_parser.add_argument("project_id")
+ batch_translate_text_parser.add_argument("gcs_source")
+ batch_translate_text_parser.add_argument("gcs_destination")
detect_langage_parser = subparsers.add_parser(
- 'detect-language', help=detect_language.__doc__)
- detect_langage_parser.add_argument('project_id')
- detect_langage_parser.add_argument('text')
+ "detect-language", help=detect_language.__doc__
+ )
+ detect_langage_parser.add_argument("project_id")
+ detect_langage_parser.add_argument("text")
list_languages_parser = subparsers.add_parser(
- 'list-languages', help=list_languages.__doc__)
- list_languages_parser.add_argument('project_id')
+ "list-languages", help=list_languages.__doc__
+ )
+ list_languages_parser.add_argument("project_id")
list_languages_with_target_parser = subparsers.add_parser(
- 'list-languages-with-target', help=list_languages_with_target.__doc__)
- list_languages_with_target_parser.add_argument('project_id')
- list_languages_with_target_parser.add_argument('display_language_code')
+ "list-languages-with-target", help=list_languages_with_target.__doc__
+ )
+ list_languages_with_target_parser.add_argument("project_id")
+ list_languages_with_target_parser.add_argument("display_language_code")
create_glossary_parser = subparsers.add_parser(
- 'create-glossary', help=create_glossary.__doc__)
- create_glossary_parser.add_argument('project_id')
- create_glossary_parser.add_argument('glossary_id')
+ "create-glossary", help=create_glossary.__doc__
+ )
+ create_glossary_parser.add_argument("project_id")
+ create_glossary_parser.add_argument("glossary_id")
get_glossary_parser = subparsers.add_parser(
- 'get-glossary', help=get_glossary.__doc__)
- get_glossary_parser.add_argument('project_id')
- get_glossary_parser.add_argument('glossary_id')
+ "get-glossary", help=get_glossary.__doc__
+ )
+ get_glossary_parser.add_argument("project_id")
+ get_glossary_parser.add_argument("glossary_id")
list_glossary_parser = subparsers.add_parser(
- 'list-glossaries', help=list_glossaries.__doc__)
- list_glossary_parser.add_argument('project_id')
+ "list-glossaries", help=list_glossaries.__doc__
+ )
+ list_glossary_parser.add_argument("project_id")
delete_glossary_parser = subparsers.add_parser(
- 'delete-glossary', help=delete_glossary.__doc__)
- delete_glossary_parser.add_argument('project_id')
- delete_glossary_parser.add_argument('glossary_id')
+ "delete-glossary", help=delete_glossary.__doc__
+ )
+ delete_glossary_parser.add_argument("project_id")
+ delete_glossary_parser.add_argument("glossary_id")
translate_with_glossary_parser = subparsers.add_parser(
- 'translate-with-glossary', help=translate_text_with_glossary.__doc__)
- translate_with_glossary_parser.add_argument('project_id')
- translate_with_glossary_parser.add_argument('glossary_id')
- translate_with_glossary_parser.add_argument('text')
+ "translate-with-glossary", help=translate_text_with_glossary.__doc__
+ )
+ translate_with_glossary_parser.add_argument("project_id")
+ translate_with_glossary_parser.add_argument("glossary_id")
+ translate_with_glossary_parser.add_argument("text")
args = parser.parse_args()
- if args.command == 'translate-text':
+ if args.command == "translate-text":
translate_text(args.project_id, args.text)
- elif args.command == 'batch-translate-text':
- batch_translate_text(
- args.project_id, args.gcs_source, args.gcs_destination)
- elif args.command == 'detect-language':
+ elif args.command == "batch-translate-text":
+ batch_translate_text(args.project_id, args.gcs_source, args.gcs_destination)
+ elif args.command == "detect-language":
detect_language(args.project_id, args.text)
- elif args.command == 'list-languages':
+ elif args.command == "list-languages":
list_languages(args.project_id)
- elif args.command == 'list-languages-with-target':
+ elif args.command == "list-languages-with-target":
list_languages_with_target(args.project_id, args.display_language_code)
- elif args.command == 'create-glossary':
+ elif args.command == "create-glossary":
create_glossary(args.project_id, args.glossary_id)
- elif args.command == 'get-glossary':
+ elif args.command == "get-glossary":
get_glossary(args.project_id, args.glossary_id)
- elif args.command == 'list-glossaries':
+ elif args.command == "list-glossaries":
list_glossaries(args.project_id)
- elif args.command == 'delete-glossary':
+ elif args.command == "delete-glossary":
delete_glossary(args.project_id, args.glossary_id)
- elif args.command == 'translate-with-glossary':
- translate_text_with_glossary(
- args.project_id, args.glossary_id, args.text)
+ elif args.command == "translate-with-glossary":
+ translate_text_with_glossary(args.project_id, args.glossary_id, args.text)
diff --git a/samples/snippets/beta_snippets_test.py b/samples/snippets/beta_snippets_test.py
index a42ab08c..7e0c2dc6 100644
--- a/samples/snippets/beta_snippets_test.py
+++ b/samples/snippets/beta_snippets_test.py
@@ -22,13 +22,13 @@
import beta_snippets
-PROJECT_ID = os.environ['GOOGLE_CLOUD_PROJECT']
+PROJECT_ID = os.environ["GOOGLE_CLOUD_PROJECT"]
-@pytest.fixture(scope='function')
+@pytest.fixture(scope="function")
def bucket():
"""Create a temporary bucket to store annotation output."""
- bucket_name = f'tmp-{uuid.uuid4().hex}'
+ bucket_name = f"tmp-{uuid.uuid4().hex}"
storage_client = storage.Client()
bucket = storage_client.create_bucket(bucket_name)
@@ -37,10 +37,10 @@ def bucket():
bucket.delete(force=True)
-@pytest.fixture(scope='session')
+@pytest.fixture(scope="session")
def glossary():
"""Get the ID of a glossary available to session (do not mutate/delete)."""
- glossary_id = 'must-start-with-letters-' + str(uuid.uuid1())
+ glossary_id = "must-start-with-letters-" + str(uuid.uuid1())
beta_snippets.create_glossary(PROJECT_ID, glossary_id)
yield glossary_id
@@ -51,10 +51,10 @@ def glossary():
pass
-@pytest.fixture(scope='function')
+@pytest.fixture(scope="function")
def unique_glossary_id():
"""Get a unique ID. Attempts to delete glossary with this ID after test."""
- glossary_id = 'must-start-with-letters-' + str(uuid.uuid1())
+ glossary_id = "must-start-with-letters-" + str(uuid.uuid1())
yield glossary_id
@@ -65,69 +65,69 @@ def unique_glossary_id():
def test_translate_text(capsys):
- beta_snippets.translate_text(PROJECT_ID, 'Hello world')
+ beta_snippets.translate_text(PROJECT_ID, "Hello world")
out, _ = capsys.readouterr()
- assert 'Translated Text:' in out
+ assert "Translated Text:" in out
@pytest.mark.flaky(max_runs=3, min_passes=1)
def test_batch_translate_text(capsys, bucket):
beta_snippets.batch_translate_text(
PROJECT_ID,
- 'gs://cloud-samples-data/translation/text.txt',
- 'gs://{}/translation/BATCH_TRANSLATION_OUTPUT/'.format(bucket.name))
+ "gs://cloud-samples-data/translation/text.txt",
+ "gs://{}/translation/BATCH_TRANSLATION_OUTPUT/".format(bucket.name),
+ )
out, _ = capsys.readouterr()
- assert 'Total Characters: 13' in out
- assert 'Translated Characters: 13' in out
+ assert "Total Characters: 13" in out
+ assert "Translated Characters: 13" in out
def test_detect_language(capsys):
- beta_snippets.detect_language(PROJECT_ID, u'Hæ sæta')
+ beta_snippets.detect_language(PROJECT_ID, "Hæ sæta")
out, _ = capsys.readouterr()
- assert 'is' in out
+ assert "is" in out
def test_list_languages(capsys):
beta_snippets.list_languages(PROJECT_ID)
out, _ = capsys.readouterr()
- assert 'zh-CN' in out
+ assert "zh-CN" in out
def test_list_languages_with_target(capsys):
- beta_snippets.list_languages_with_target(PROJECT_ID, 'is')
+ beta_snippets.list_languages_with_target(PROJECT_ID, "is")
out, _ = capsys.readouterr()
- assert u'Language Code: sq' in out
- assert u'Display Name: albanska' in out
+ assert "Language Code: sq" in out
+ assert "Display Name: albanska" in out
@pytest.mark.flaky(max_runs=3, min_passes=1)
def test_create_glossary(capsys, unique_glossary_id):
beta_snippets.create_glossary(PROJECT_ID, unique_glossary_id)
out, _ = capsys.readouterr()
- assert 'Created' in out
+ assert "Created" in out
assert unique_glossary_id in out
- assert 'gs://cloud-samples-data/translation/glossary.csv' in out
+ assert "gs://cloud-samples-data/translation/glossary.csv" in out
def test_get_glossary(capsys, glossary):
beta_snippets.get_glossary(PROJECT_ID, glossary)
out, _ = capsys.readouterr()
assert glossary in out
- assert 'gs://cloud-samples-data/translation/glossary.csv' in out
+ assert "gs://cloud-samples-data/translation/glossary.csv" in out
def test_list_glossary(capsys, glossary):
beta_snippets.list_glossaries(PROJECT_ID)
out, _ = capsys.readouterr()
assert glossary in out
- assert 'gs://cloud-samples-data/translation/glossary.csv' in out
+ assert "gs://cloud-samples-data/translation/glossary.csv" in out
def test_translate_text_with_glossary(capsys, glossary):
- beta_snippets.translate_text_with_glossary(
- PROJECT_ID, glossary, 'account')
+ beta_snippets.translate_text_with_glossary(PROJECT_ID, glossary, "account")
out, _ = capsys.readouterr()
- assert 'cuenta' in out
+ assert "cuenta" in out
@pytest.mark.flaky(max_runs=3, min_passes=1)
@@ -135,5 +135,5 @@ def test_delete_glossary(capsys, unique_glossary_id):
beta_snippets.create_glossary(PROJECT_ID, unique_glossary_id)
beta_snippets.delete_glossary(PROJECT_ID, unique_glossary_id)
out, _ = capsys.readouterr()
- assert 'us-central1' in out
+ assert "us-central1" in out
assert unique_glossary_id in out
diff --git a/samples/snippets/hybrid_glossaries/hybrid_tutorial.py b/samples/snippets/hybrid_glossaries/hybrid_tutorial.py
index c4a84345..9eae168a 100644
--- a/samples/snippets/hybrid_glossaries/hybrid_tutorial.py
+++ b/samples/snippets/hybrid_glossaries/hybrid_tutorial.py
@@ -23,12 +23,13 @@
from google.cloud import texttospeech
from google.cloud import translate_v3beta1 as translate
from google.cloud import vision
+
# [END translate_hybrid_imports]
# [START translate_hybrid_project_id]
# extract GCP project id
-PROJECT_ID = os.environ['GOOGLE_CLOUD_PROJECT']
+PROJECT_ID = os.environ["GOOGLE_CLOUD_PROJECT"]
# [END translate_hybrid_project_id]
@@ -47,15 +48,16 @@ def pic_to_text(infile):
client = vision.ImageAnnotatorClient()
# Opens the input image file
- with io.open(infile, 'rb') as image_file:
+ with io.open(infile, "rb") as image_file:
content = image_file.read()
- image = vision.types.Image(content=content)
+ image = vision.Image(content=content)
# For dense text, use document_text_detection
# For less dense text, use text_detection
response = client.document_text_detection(image=image)
text = response.full_text_annotation.text
+ print("Detected text: {}".format(text))
return text
# [END translate_hybrid_vision]
@@ -80,29 +82,24 @@ def create_glossary(languages, project_id, glossary_name, glossary_uri):
client = translate.TranslationServiceClient()
# Designates the data center location that you want to use
- location = 'us-central1'
+ location = "us-central1"
# Set glossary resource name
- name = client.glossary_path(
- project_id,
- location,
- glossary_name)
+ name = client.glossary_path(project_id, location, glossary_name)
# Set language codes
- language_codes_set = translate.types.Glossary.LanguageCodesSet(
- language_codes=languages)
+ language_codes_set = translate.Glossary.LanguageCodesSet(
+ language_codes=languages
+ )
- gcs_source = translate.types.GcsSource(
- input_uri=glossary_uri)
+ gcs_source = translate.GcsSource(input_uri=glossary_uri)
- input_config = translate.types.GlossaryInputConfig(
- gcs_source=gcs_source)
+ input_config = translate.GlossaryInputConfig(gcs_source=gcs_source)
# Set glossary resource information
- glossary = translate.types.Glossary(
- name=name,
- language_codes_set=language_codes_set,
- input_config=input_config)
+ glossary = translate.Glossary(
+ name=name, language_codes_set=language_codes_set, input_config=input_config
+ )
parent = f"projects/{project_id}/locations/{location}"
@@ -112,16 +109,20 @@ def create_glossary(languages, project_id, glossary_name, glossary_uri):
try:
operation = client.create_glossary(parent=parent, glossary=glossary)
operation.result(timeout=90)
- print('Created glossary ' + glossary_name + '.')
+ print("Created glossary " + glossary_name + ".")
except AlreadyExists:
- print('The glossary ' + glossary_name +
- ' already exists. No new glossary was created.')
+ print(
+ "The glossary "
+ + glossary_name
+ + " already exists. No new glossary was created."
+ )
# [END translate_hybrid_create_glossary]
# [START translate_hybrid_translate]
-def translate_text(text, source_language_code, target_language_code,
- project_id, glossary_name):
+def translate_text(
+ text, source_language_code, target_language_code, project_id, glossary_name
+):
"""Translates text to a given language using a glossary
ARGS
@@ -140,15 +141,11 @@ def translate_text(text, source_language_code, target_language_code,
client = translate.TranslationServiceClient()
# Designates the data center location that you want to use
- location = 'us-central1'
+ location = "us-central1"
- glossary = client.glossary_path(
- project_id,
- location,
- glossary_name)
+ glossary = client.glossary_path(project_id, location, glossary_name)
- glossary_config = translate.types.TranslateTextGlossaryConfig(
- glossary=glossary)
+ glossary_config = translate.TranslateTextGlossaryConfig(glossary=glossary)
parent = f"projects/{project_id}/locations/{location}"
@@ -159,7 +156,7 @@ def translate_text(text, source_language_code, target_language_code,
"mime_type": "text/plain", # mime types: text/plain, text/html
"source_language_code": source_language_code,
"target_language_code": target_language_code,
- "glossary_config": glossary_config
+ "glossary_config": glossary_config,
}
)
@@ -189,8 +186,9 @@ def text_to_speech(text, outfile):
# Convert plaintext to SSML in order to wait two seconds
# between each line in synthetic speech
- ssml = '{}'.format(
- escaped_lines.replace('\n', '\n'))
+ ssml = "{}".format(
+ escaped_lines.replace("\n", '\n')
+ )
# Instantiates a client
client = texttospeech.TextToSpeechClient()
@@ -201,28 +199,27 @@ def text_to_speech(text, outfile):
# Builds the voice request, selects the language code ("en-US") and
# the SSML voice gender ("MALE")
voice = texttospeech.VoiceSelectionParams(
- language_code='en-US',
- ssml_gender=texttospeech.SsmlVoiceGender.MALE)
+ language_code="en-US", ssml_gender=texttospeech.SsmlVoiceGender.MALE
+ )
# Selects the type of audio file to return
audio_config = texttospeech.AudioConfig(
- audio_encoding=texttospeech.AudioEncoding.MP3)
+ audio_encoding=texttospeech.AudioEncoding.MP3
+ )
# Performs the text-to-speech request on the text input with the selected
# voice parameters and audio file type
request = texttospeech.SynthesizeSpeechRequest(
- input=synthesis_input,
- voice=voice,
- audio_config=audio_config
+ input=synthesis_input, voice=voice, audio_config=audio_config
)
response = client.synthesize_speech(request=request)
# Writes the synthetic audio to the output file.
- with open(outfile, 'wb') as out:
+ with open(outfile, "wb") as out:
out.write(response.audio_content)
- print('Audio content written to file ' + outfile)
+ print("Audio content written to file " + outfile)
# [END translate_hybrid_tts]
@@ -230,30 +227,31 @@ def text_to_speech(text, outfile):
def main():
# Photo from which to extract text
- infile = 'resources/example.png'
+ infile = "resources/example.png"
# Name of file that will hold synthetic speech
- outfile = 'resources/example.mp3'
+ outfile = "resources/example.mp3"
# Defines the languages in the glossary
# This list must match the languages in the glossary
# Here, the glossary includes French and English
- glossary_langs = ['fr', 'en']
+ glossary_langs = ["fr", "en"]
# Name that will be assigned to your project's glossary resource
- glossary_name = 'bistro-glossary'
+ glossary_name = "bistro-glossary"
# uri of .csv file uploaded to Cloud Storage
- glossary_uri = 'gs://cloud-samples-data/translation/bistro_glossary.csv'
+ glossary_uri = "gs://cloud-samples-data/translation/bistro_glossary.csv"
create_glossary(glossary_langs, PROJECT_ID, glossary_name, glossary_uri)
# photo -> detected text
text_to_translate = pic_to_text(infile)
# detected text -> translated text
- text_to_speak = translate_text(text_to_translate, 'fr', 'en',
- PROJECT_ID, glossary_name)
+ text_to_speak = translate_text(
+ text_to_translate, "fr", "en", PROJECT_ID, glossary_name
+ )
# translated text -> synthetic audio
text_to_speech(text_to_speak, outfile)
# [END translate_hybrid_integration]
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/samples/snippets/hybrid_glossaries/hybrid_tutorial_test.py b/samples/snippets/hybrid_glossaries/hybrid_tutorial_test.py
index 8df7cc35..2b4f6559 100644
--- a/samples/snippets/hybrid_glossaries/hybrid_tutorial_test.py
+++ b/samples/snippets/hybrid_glossaries/hybrid_tutorial_test.py
@@ -13,7 +13,6 @@
# limitations under the License.
import os
-import re
import sys
import uuid
@@ -23,7 +22,7 @@
from hybrid_tutorial import translate_text
-PROJECT_ID = os.environ['GOOGLE_CLOUD_PROJECT']
+PROJECT_ID = os.environ["GOOGLE_CLOUD_PROJECT"]
# VISION TESTS
@@ -33,35 +32,22 @@ def test_vision_standard_format():
# Generate text using Vision API
text = pic_to_text('resources/standard_format.jpeg')
- assert re.match(r"This\s?is\s?a\s?test!\s?", text)
-
-
-def test_vision_non_standard_format():
-
- # Generate text
- text = pic_to_text('resources/non_standard_format.png')
-
- # Read expected text
- with open('resources/non_standard_format.txt') as f:
- expected_text = f.read()
-
- assert text == expected_text
+ assert len(text) > 0
# TRANSLATE TESTS
def test_create_and_delete_glossary():
- sys.path.insert(1, '../')
+ sys.path.insert(1, "../")
from beta_snippets import delete_glossary
- languages = ['fr', 'en']
- glossary_name = f'test-glossary-{uuid.uuid4()}'
- glossary_uri = 'gs://cloud-samples-data/translation/bistro_glossary.csv'
+ languages = ["fr", "en"]
+ glossary_name = f"test-glossary-{uuid.uuid4()}"
+ glossary_uri = "gs://cloud-samples-data/translation/bistro_glossary.csv"
# create_glossary will raise an exception if creation fails
- create_glossary(languages, PROJECT_ID, glossary_name,
- glossary_uri)
+ create_glossary(languages, PROJECT_ID, glossary_name, glossary_uri)
# Delete glossary so that future tests will pass
# delete_glossary will raise an exception if deletion fails
@@ -70,21 +56,19 @@ def test_create_and_delete_glossary():
def test_translate_standard():
- expected_text = 'Hello'
+ expected_text = "Hello"
- text = translate_text('Bonjour', 'fr', 'en', PROJECT_ID,
- 'bistro-glossary')
+ text = translate_text("Bonjour", "fr", "en", PROJECT_ID, "bistro-glossary")
assert text == expected_text
def test_translate_glossary():
- expected_text = 'I eat goat cheese'
- input_text = 'Je mange du chevre'
+ expected_text = "I eat goat cheese"
+ input_text = "Je mange du chevre"
- text = translate_text(input_text, 'fr', 'en', PROJECT_ID,
- 'bistro-glossary')
+ text = translate_text(input_text, "fr", "en", PROJECT_ID, "bistro-glossary")
assert text == expected_text
@@ -93,10 +77,10 @@ def test_translate_glossary():
def test_tts_standard(capsys):
- outfile = 'resources/test_standard_text.mp3'
- textfile = 'resources/standard_format.txt'
+ outfile = "resources/test_standard_text.mp3"
+ textfile = "resources/standard_format.txt"
- with open(textfile, 'r') as f:
+ with open(textfile, "r") as f:
text = f.read()
text_to_speech(text, outfile)
@@ -106,7 +90,7 @@ def test_tts_standard(capsys):
out, err = capsys.readouterr()
# Assert success message printed
- assert 'Audio content written to file ' + outfile in out
+ assert "Audio content written to file " + outfile in out
# Delete test file
os.remove(outfile)
diff --git a/samples/snippets/hybrid_glossaries/noxfile.py b/samples/snippets/hybrid_glossaries/noxfile.py
index ba55d7ce..f3a90583 100644
--- a/samples/snippets/hybrid_glossaries/noxfile.py
+++ b/samples/snippets/hybrid_glossaries/noxfile.py
@@ -37,24 +37,22 @@
TEST_CONFIG = {
# You can opt out from the test for specific Python versions.
- 'ignored_versions': ["2.7"],
-
+ "ignored_versions": ["2.7"],
# An envvar key for determining the project id to use. Change it
# to 'BUILD_SPECIFIC_GCLOUD_PROJECT' if you want to opt in using a
# build specific Cloud project. You can also use your own string
# to use your own Cloud project.
- 'gcloud_project_env': 'GOOGLE_CLOUD_PROJECT',
+ "gcloud_project_env": "GOOGLE_CLOUD_PROJECT",
# 'gcloud_project_env': 'BUILD_SPECIFIC_GCLOUD_PROJECT',
-
# A dictionary you want to inject into your test. Don't put any
# secrets here. These values will override predefined values.
- 'envs': {},
+ "envs": {},
}
try:
# Ensure we can import noxfile_config in the project's directory.
- sys.path.append('.')
+ sys.path.append(".")
from noxfile_config import TEST_CONFIG_OVERRIDE
except ImportError as e:
print("No user noxfile_config found: detail: {}".format(e))
@@ -69,12 +67,12 @@ def get_pytest_env_vars():
ret = {}
# Override the GCLOUD_PROJECT and the alias.
- env_key = TEST_CONFIG['gcloud_project_env']
+ env_key = TEST_CONFIG["gcloud_project_env"]
# This should error out if not set.
- ret['GOOGLE_CLOUD_PROJECT'] = os.environ[env_key]
+ ret["GOOGLE_CLOUD_PROJECT"] = os.environ[env_key]
# Apply user supplied envs.
- ret.update(TEST_CONFIG['envs'])
+ ret.update(TEST_CONFIG["envs"])
return ret
@@ -83,7 +81,7 @@ def get_pytest_env_vars():
ALL_VERSIONS = ["2.7", "3.6", "3.7", "3.8"]
# Any default versions that should be ignored.
-IGNORED_VERSIONS = TEST_CONFIG['ignored_versions']
+IGNORED_VERSIONS = TEST_CONFIG["ignored_versions"]
TESTED_VERSIONS = sorted([v for v in ALL_VERSIONS if v not in IGNORED_VERSIONS])
@@ -138,7 +136,7 @@ def lint(session):
args = FLAKE8_COMMON_ARGS + [
"--application-import-names",
",".join(local_names),
- "."
+ ".",
]
session.run("flake8", *args)
@@ -182,9 +180,9 @@ def py(session):
if session.python in TESTED_VERSIONS:
_session_tests(session)
else:
- session.skip("SKIPPED: {} tests are disabled for this sample.".format(
- session.python
- ))
+ session.skip(
+ "SKIPPED: {} tests are disabled for this sample.".format(session.python)
+ )
#
@@ -201,6 +199,11 @@ def _get_repo_root():
break
if Path(p / ".git").exists():
return str(p)
+ # .git is not available in repos cloned via Cloud Build
+ # setup.py is always in the library's root, so use that instead
+ # https://github.com/googleapis/synthtool/issues/792
+ if Path(p / "setup.py").exists():
+ return str(p)
p = p.parent
raise Exception("Unable to detect repository root.")
diff --git a/samples/snippets/hybrid_glossaries/requirements.txt b/samples/snippets/hybrid_glossaries/requirements.txt
index af2fa067..ff0077c1 100644
--- a/samples/snippets/hybrid_glossaries/requirements.txt
+++ b/samples/snippets/hybrid_glossaries/requirements.txt
@@ -1,3 +1,3 @@
-google-cloud-translate==3.0.0
-google-cloud-vision==1.0.0
-google-cloud-texttospeech==2.1.0
+google-cloud-translate==3.0.1
+google-cloud-vision==2.0.0
+google-cloud-texttospeech==2.2.0
diff --git a/samples/snippets/hybrid_glossaries/resources/non_standard_format.png b/samples/snippets/hybrid_glossaries/resources/non_standard_format.png
deleted file mode 100644
index eeee9c7f..00000000
Binary files a/samples/snippets/hybrid_glossaries/resources/non_standard_format.png and /dev/null differ
diff --git a/samples/snippets/hybrid_glossaries/resources/non_standard_format.txt b/samples/snippets/hybrid_glossaries/resources/non_standard_format.txt
deleted file mode 100644
index 529799ee..00000000
--- a/samples/snippets/hybrid_glossaries/resources/non_standard_format.txt
+++ /dev/null
@@ -1,30 +0,0 @@
-MENU
-Google Cloud Bistro
-SALADS
-SANDWICHES
-GCP Green Salad
-Fresh Greens
-$5
-Kubernetes Sandwich
-ham and cheese sandwich
-$10
-Cloud Caprese
-Mozzarella, tomatoes, basil,
-balsamic reduction
-$8
-Dialogflow Panini
-chicken, pesto, and
-mozzarella panini
-$10
-Firebase Fruit Salad
-watermelon, honeydew melon,
-and pineapple
-$6
-Compute Engine Burger
-quarter-pound burger with
-cheddar cheese
-$10
-BigQuery BLT
-bacon, lettuce, and tomato
-sandwich
-$10
diff --git a/samples/snippets/noxfile.py b/samples/snippets/noxfile.py
index ba55d7ce..27d948d6 100644
--- a/samples/snippets/noxfile.py
+++ b/samples/snippets/noxfile.py
@@ -37,24 +37,22 @@
TEST_CONFIG = {
# You can opt out from the test for specific Python versions.
- 'ignored_versions': ["2.7"],
-
+ "ignored_versions": ["2.7"],
# An envvar key for determining the project id to use. Change it
# to 'BUILD_SPECIFIC_GCLOUD_PROJECT' if you want to opt in using a
# build specific Cloud project. You can also use your own string
# to use your own Cloud project.
- 'gcloud_project_env': 'GOOGLE_CLOUD_PROJECT',
+ "gcloud_project_env": "GOOGLE_CLOUD_PROJECT",
# 'gcloud_project_env': 'BUILD_SPECIFIC_GCLOUD_PROJECT',
-
# A dictionary you want to inject into your test. Don't put any
# secrets here. These values will override predefined values.
- 'envs': {},
+ "envs": {},
}
try:
# Ensure we can import noxfile_config in the project's directory.
- sys.path.append('.')
+ sys.path.append(".")
from noxfile_config import TEST_CONFIG_OVERRIDE
except ImportError as e:
print("No user noxfile_config found: detail: {}".format(e))
@@ -69,12 +67,12 @@ def get_pytest_env_vars():
ret = {}
# Override the GCLOUD_PROJECT and the alias.
- env_key = TEST_CONFIG['gcloud_project_env']
+ env_key = TEST_CONFIG["gcloud_project_env"]
# This should error out if not set.
- ret['GOOGLE_CLOUD_PROJECT'] = os.environ[env_key]
+ ret["GOOGLE_CLOUD_PROJECT"] = os.environ[env_key]
# Apply user supplied envs.
- ret.update(TEST_CONFIG['envs'])
+ ret.update(TEST_CONFIG["envs"])
return ret
@@ -83,7 +81,7 @@ def get_pytest_env_vars():
ALL_VERSIONS = ["2.7", "3.6", "3.7", "3.8"]
# Any default versions that should be ignored.
-IGNORED_VERSIONS = TEST_CONFIG['ignored_versions']
+IGNORED_VERSIONS = TEST_CONFIG["ignored_versions"]
TESTED_VERSIONS = sorted([v for v in ALL_VERSIONS if v not in IGNORED_VERSIONS])
@@ -138,7 +136,7 @@ def lint(session):
args = FLAKE8_COMMON_ARGS + [
"--application-import-names",
",".join(local_names),
- "."
+ ".",
]
session.run("flake8", *args)
@@ -201,6 +199,11 @@ def _get_repo_root():
break
if Path(p / ".git").exists():
return str(p)
+ # .git is not available in repos cloned via Cloud Build
+ # setup.py is always in the library's root, so use that instead
+ # https://github.com/googleapis/synthtool/issues/792
+ if Path(p / "setup.py").exists():
+ return str(p)
p = p.parent
raise Exception("Unable to detect repository root.")
diff --git a/samples/snippets/quickstart.py b/samples/snippets/quickstart.py
index 888b6691..9fc4027a 100644
--- a/samples/snippets/quickstart.py
+++ b/samples/snippets/quickstart.py
@@ -24,19 +24,17 @@ def run_quickstart():
translate_client = translate.Client()
# The text to translate
- text = u'Hello, world!'
+ text = u"Hello, world!"
# The target language
- target = 'ru'
+ target = "ru"
# Translates some text into Russian
- translation = translate_client.translate(
- text,
- target_language=target)
+ translation = translate_client.translate(text, target_language=target)
- print(u'Text: {}'.format(text))
- print(u'Translation: {}'.format(translation['translatedText']))
+ print(u"Text: {}".format(text))
+ print(u"Translation: {}".format(translation["translatedText"]))
# [END translate_quickstart]
-if __name__ == '__main__':
+if __name__ == "__main__":
run_quickstart()
diff --git a/samples/snippets/quickstart_test.py b/samples/snippets/quickstart_test.py
index 8def7f3e..e4dc4886 100644
--- a/samples/snippets/quickstart_test.py
+++ b/samples/snippets/quickstart_test.py
@@ -20,4 +20,4 @@
def test_quickstart(capsys):
quickstart.run_quickstart()
out, _ = capsys.readouterr()
- assert u'Translation' in out
+ assert u"Translation" in out
diff --git a/samples/snippets/requirements-test.txt b/samples/snippets/requirements-test.txt
index b267f58b..bd6c7999 100644
--- a/samples/snippets/requirements-test.txt
+++ b/samples/snippets/requirements-test.txt
@@ -1,3 +1,3 @@
backoff==1.10.0
flaky==3.7.0
-pytest==5.4.3
\ No newline at end of file
+pytest==5.4.3
diff --git a/samples/snippets/requirements.txt b/samples/snippets/requirements.txt
index 4c26010b..4f26184f 100644
--- a/samples/snippets/requirements.txt
+++ b/samples/snippets/requirements.txt
@@ -1,2 +1,3 @@
-google-cloud-translate==3.0.0
-google-cloud-storage==1.30.0
+google-cloud-translate==3.0.1
+google-cloud-storage==1.33.0
+google-cloud-automl==2.1.0
diff --git a/samples/snippets/snippets.py b/samples/snippets/snippets.py
index 24b45716..5700969c 100644
--- a/samples/snippets/snippets.py
+++ b/samples/snippets/snippets.py
@@ -23,22 +23,21 @@
import argparse
-import six
-
def detect_language(text):
# [START translate_detect_language]
"""Detects the text's language."""
from google.cloud import translate_v2 as translate
+
translate_client = translate.Client()
# Text can also be a sequence of strings, in which case this method
# will return a sequence of results for each text.
result = translate_client.detect_language(text)
- print('Text: {}'.format(text))
- print('Confidence: {}'.format(result['confidence']))
- print('Language: {}'.format(result['language']))
+ print("Text: {}".format(text))
+ print("Confidence: {}".format(result["confidence"]))
+ print("Language: {}".format(result["language"]))
# [END translate_detect_language]
@@ -46,12 +45,13 @@ def list_languages():
# [START translate_list_codes]
"""Lists all available languages."""
from google.cloud import translate_v2 as translate
+
translate_client = translate.Client()
results = translate_client.get_languages()
for language in results:
- print(u'{name} ({language})'.format(**language))
+ print(u"{name} ({language})".format(**language))
# [END translate_list_codes]
@@ -63,16 +63,17 @@ def list_languages_with_target(target):
See https://g.co/cloud/translate/v2/translate-reference#supported_languages
"""
from google.cloud import translate_v2 as translate
+
translate_client = translate.Client()
results = translate_client.get_languages(target_language=target)
for language in results:
- print(u'{name} ({language})'.format(**language))
+ print(u"{name} ({language})".format(**language))
# [END translate_list_language_names]
-def translate_text_with_model(target, text, model='nmt'):
+def translate_text_with_model(target, text, model="nmt"):
# [START translate_text_with_model]
"""Translates text into the target language.
@@ -81,21 +82,21 @@ def translate_text_with_model(target, text, model='nmt'):
Target must be an ISO 639-1 language code.
See https://g.co/cloud/translate/v2/translate-reference#supported_languages
"""
+ import six
from google.cloud import translate_v2 as translate
+
translate_client = translate.Client()
if isinstance(text, six.binary_type):
- text = text.decode('utf-8')
+ text = text.decode("utf-8")
# Text can also be a sequence of strings, in which case this method
# will return a sequence of results for each text.
- result = translate_client.translate(
- text, target_language=target, model=model)
+ result = translate_client.translate(text, target_language=target, model=model)
- print(u'Text: {}'.format(result['input']))
- print(u'Translation: {}'.format(result['translatedText']))
- print(u'Detected source language: {}'.format(
- result['detectedSourceLanguage']))
+ print(u"Text: {}".format(result["input"]))
+ print(u"Translation: {}".format(result["translatedText"]))
+ print(u"Detected source language: {}".format(result["detectedSourceLanguage"]))
# [END translate_text_with_model]
@@ -106,53 +107,57 @@ def translate_text(target, text):
Target must be an ISO 639-1 language code.
See https://g.co/cloud/translate/v2/translate-reference#supported_languages
"""
+ import six
from google.cloud import translate_v2 as translate
+
translate_client = translate.Client()
if isinstance(text, six.binary_type):
- text = text.decode('utf-8')
+ text = text.decode("utf-8")
# Text can also be a sequence of strings, in which case this method
# will return a sequence of results for each text.
- result = translate_client.translate(
- text, target_language=target)
+ result = translate_client.translate(text, target_language=target)
- print(u'Text: {}'.format(result['input']))
- print(u'Translation: {}'.format(result['translatedText']))
- print(u'Detected source language: {}'.format(
- result['detectedSourceLanguage']))
+ print(u"Text: {}".format(result["input"]))
+ print(u"Translation: {}".format(result["translatedText"]))
+ print(u"Detected source language: {}".format(result["detectedSourceLanguage"]))
# [END translate_translate_text]
-if __name__ == '__main__':
+if __name__ == "__main__":
parser = argparse.ArgumentParser(
- description=__doc__,
- formatter_class=argparse.RawDescriptionHelpFormatter)
- subparsers = parser.add_subparsers(dest='command')
+ description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter
+ )
+ subparsers = parser.add_subparsers(dest="command")
detect_langage_parser = subparsers.add_parser(
- 'detect-language', help=detect_language.__doc__)
- detect_langage_parser.add_argument('text')
+ "detect-language", help=detect_language.__doc__
+ )
+ detect_langage_parser.add_argument("text")
list_languages_parser = subparsers.add_parser(
- 'list-languages', help=list_languages.__doc__)
+ "list-languages", help=list_languages.__doc__
+ )
list_languages_with_target_parser = subparsers.add_parser(
- 'list-languages-with-target', help=list_languages_with_target.__doc__)
- list_languages_with_target_parser.add_argument('target')
+ "list-languages-with-target", help=list_languages_with_target.__doc__
+ )
+ list_languages_with_target_parser.add_argument("target")
translate_text_parser = subparsers.add_parser(
- 'translate-text', help=translate_text.__doc__)
- translate_text_parser.add_argument('target')
- translate_text_parser.add_argument('text')
+ "translate-text", help=translate_text.__doc__
+ )
+ translate_text_parser.add_argument("target")
+ translate_text_parser.add_argument("text")
args = parser.parse_args()
- if args.command == 'detect-language':
+ if args.command == "detect-language":
detect_language(args.text)
- elif args.command == 'list-languages':
+ elif args.command == "list-languages":
list_languages()
- elif args.command == 'list-languages-with-target':
+ elif args.command == "list-languages-with-target":
list_languages_with_target(args.target)
- elif args.command == 'translate-text':
+ elif args.command == "translate-text":
translate_text(args.target, args.text)
diff --git a/samples/snippets/snippets_test.py b/samples/snippets/snippets_test.py
index 6d63759d..b5fe362c 100644
--- a/samples/snippets/snippets_test.py
+++ b/samples/snippets/snippets_test.py
@@ -19,31 +19,31 @@
def test_detect_language(capsys):
- snippets.detect_language('Hæ sæta')
+ snippets.detect_language("Hæ sæta")
out, _ = capsys.readouterr()
- assert 'is' in out
+ assert "is" in out
def test_list_languages(capsys):
snippets.list_languages()
out, _ = capsys.readouterr()
- assert 'Icelandic (is)' in out
+ assert "Icelandic (is)" in out
def test_list_languages_with_target(capsys):
- snippets.list_languages_with_target('is')
+ snippets.list_languages_with_target("is")
out, _ = capsys.readouterr()
- assert u'íslenska (is)' in out
+ assert u"íslenska (is)" in out
def test_translate_text(capsys):
- snippets.translate_text('is', 'Hello world')
+ snippets.translate_text("is", "Hello world")
out, _ = capsys.readouterr()
- assert u'Halló heimur' in out
+ assert u"Halló heimur" in out
def test_translate_utf8(capsys):
- text = u'나는 파인애플을 좋아한다.'
- snippets.translate_text('en', text)
+ text = u"파인애플 13개"
+ snippets.translate_text("en", text)
out, _ = capsys.readouterr()
- assert u'I like pineapple' in out
+ assert u"13 pineapples" in out
diff --git a/samples/snippets/translate_v3_batch_translate_text.py b/samples/snippets/translate_v3_batch_translate_text.py
index 487b0965..0f4161c9 100644
--- a/samples/snippets/translate_v3_batch_translate_text.py
+++ b/samples/snippets/translate_v3_batch_translate_text.py
@@ -17,10 +17,10 @@
def batch_translate_text(
- input_uri="gs://YOUR_BUCKET_ID/path/to/your/file.txt",
- output_uri="gs://YOUR_BUCKET_ID/path/to/save/results/",
- project_id="YOUR_PROJECT_ID",
- timeout=180,
+ input_uri="gs://YOUR_BUCKET_ID/path/to/your/file.txt",
+ output_uri="gs://YOUR_BUCKET_ID/path/to/save/results/",
+ project_id="YOUR_PROJECT_ID",
+ timeout=180,
):
"""Translates a batch of texts on GCS and stores the result in a GCS location."""
@@ -32,7 +32,7 @@ def batch_translate_text(
input_configs_element = {
"gcs_source": gcs_source,
- "mime_type": "text/plain" # Can be "text/plain" or "text/html".
+ "mime_type": "text/plain", # Can be "text/plain" or "text/html".
}
gcs_destination = {"output_uri_prefix": output_uri}
output_config = {"gcs_destination": gcs_destination}
@@ -45,15 +45,15 @@ def batch_translate_text(
"source_language_code": "en",
"target_language_codes": ["ja"], # Up to 10 language codes here.
"input_configs": [input_configs_element],
- "output_config": output_config
+ "output_config": output_config,
}
)
- print(u"Waiting for operation to complete...")
+ print("Waiting for operation to complete...")
response = operation.result(timeout)
- print(u"Total Characters: {}".format(response.total_characters))
- print(u"Translated Characters: {}".format(response.translated_characters))
+ print("Total Characters: {}".format(response.total_characters))
+ print("Translated Characters: {}".format(response.translated_characters))
# [END translate_v3_batch_translate_text]
diff --git a/samples/snippets/translate_v3_batch_translate_text_test.py b/samples/snippets/translate_v3_batch_translate_text_test.py
index f604a3e1..ad637cd8 100644
--- a/samples/snippets/translate_v3_batch_translate_text_test.py
+++ b/samples/snippets/translate_v3_batch_translate_text_test.py
@@ -42,7 +42,7 @@ def test_batch_translate_text(capsys, bucket):
"gs://cloud-samples-data/translation/text.txt",
"gs://{}/translation/BATCH_TRANSLATION_OUTPUT/".format(bucket.name),
PROJECT_ID,
- timeout=240
+ timeout=320,
)
out, _ = capsys.readouterr()
assert "Total Characters" in out
diff --git a/samples/snippets/translate_v3_batch_translate_text_with_glossary.py b/samples/snippets/translate_v3_batch_translate_text_with_glossary.py
index e9c4a7c2..574b001c 100644
--- a/samples/snippets/translate_v3_batch_translate_text_with_glossary.py
+++ b/samples/snippets/translate_v3_batch_translate_text_with_glossary.py
@@ -18,11 +18,11 @@
def batch_translate_text_with_glossary(
- input_uri="gs://YOUR_BUCKET_ID/path/to/your/file.txt",
- output_uri="gs://YOUR_BUCKET_ID/path/to/save/results/",
- project_id="YOUR_PROJECT_ID",
- glossary_id="YOUR_GLOSSARY_ID",
- timeout=180,
+ input_uri="gs://YOUR_BUCKET_ID/path/to/your/file.txt",
+ output_uri="gs://YOUR_BUCKET_ID/path/to/save/results/",
+ project_id="YOUR_PROJECT_ID",
+ glossary_id="YOUR_GLOSSARY_ID",
+ timeout=320,
):
"""Translates a batch of texts on GCS and stores the result in a GCS location.
Glossary is applied for translation."""
@@ -37,7 +37,7 @@ def batch_translate_text_with_glossary(
input_configs_element = {
"gcs_source": gcs_source,
- "mime_type": "text/plain" # Can be "text/plain" or "text/html".
+ "mime_type": "text/plain", # Can be "text/plain" or "text/html".
}
gcs_destination = {"output_uri_prefix": output_uri}
output_config = {"gcs_destination": gcs_destination}
@@ -50,9 +50,7 @@ def batch_translate_text_with_glossary(
project_id, "us-central1", glossary_id # The location of the glossary
)
- glossary_config = translate.TranslateTextGlossaryConfig(
- glossary=glossary_path
- )
+ glossary_config = translate.TranslateTextGlossaryConfig(glossary=glossary_path)
glossaries = {"ja": glossary_config} # target lang as key
@@ -63,15 +61,15 @@ def batch_translate_text_with_glossary(
"target_language_codes": ["ja"], # Up to 10 language codes here.
"input_configs": [input_configs_element],
"glossaries": glossaries,
- "output_config": output_config
+ "output_config": output_config,
}
)
- print(u"Waiting for operation to complete...")
+ print("Waiting for operation to complete...")
response = operation.result(timeout)
- print(u"Total Characters: {}".format(response.total_characters))
- print(u"Translated Characters: {}".format(response.translated_characters))
+ print("Total Characters: {}".format(response.total_characters))
+ print("Translated Characters: {}".format(response.translated_characters))
# [END translate_v3_batch_translate_text_with_glossary]
diff --git a/samples/snippets/translate_v3_batch_translate_text_with_glossary_and_model.py b/samples/snippets/translate_v3_batch_translate_text_with_glossary_and_model.py
new file mode 100644
index 00000000..3110dcee
--- /dev/null
+++ b/samples/snippets/translate_v3_batch_translate_text_with_glossary_and_model.py
@@ -0,0 +1,77 @@
+# Copyright 2019 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.
+
+# [START translate_v3_batch_translate_text_with_glossary_and_model]
+from google.cloud import translate
+
+
+def batch_translate_text_with_glossary_and_model(
+ input_uri="gs://YOUR_BUCKET_ID/path/to/your/file.txt",
+ output_uri="gs://YOUR_BUCKET_ID/path/to/save/results/",
+ project_id="YOUR_PROJECT_ID",
+ model_id="YOUR_MODEL_ID",
+ glossary_id="YOUR_GLOSSARY_ID",
+):
+ """
+ Batch translate text with Glossary and Translation model
+ """
+
+ client = translate.TranslationServiceClient()
+
+ # Supported language codes: https://cloud.google.com/translate/docs/languages
+ location = "us-central1"
+
+ target_language_codes = ["ja"]
+ gcs_source = {"input_uri": input_uri}
+
+ # Optional. Can be "text/plain" or "text/html".
+ mime_type = "text/plain"
+ input_configs_element = {"gcs_source": gcs_source, "mime_type": mime_type}
+ input_configs = [input_configs_element]
+ gcs_destination = {"output_uri_prefix": output_uri}
+ output_config = {"gcs_destination": gcs_destination}
+ parent = f"projects/{project_id}/locations/{location}"
+ model_path = "projects/{}/locations/{}/models/{}".format(
+ project_id, "us-central1", model_id
+ )
+ models = {"ja": model_path}
+
+ glossary_path = client.glossary_path(
+ project_id, "us-central1", glossary_id # The location of the glossary
+ )
+
+ glossary_config = translate.TranslateTextGlossaryConfig(glossary=glossary_path)
+ glossaries = {"ja": glossary_config} # target lang as key
+
+ operation = client.batch_translate_text(
+ request={
+ "parent": parent,
+ "source_language_code": "en",
+ "target_language_codes": target_language_codes,
+ "input_configs": input_configs,
+ "output_config": output_config,
+ "models": models,
+ "glossaries": glossaries,
+ }
+ )
+
+ print("Waiting for operation to complete...")
+ response = operation.result()
+
+ # Display the translation for each input text provided
+ print("Total Characters: {}".format(response.total_characters))
+ print("Translated Characters: {}".format(response.translated_characters))
+
+
+# [END translate_v3_batch_translate_text_with_glossary_and_model]
diff --git a/samples/snippets/translate_v3_batch_translate_text_with_glossary_and_model_test.py b/samples/snippets/translate_v3_batch_translate_text_with_glossary_and_model_test.py
new file mode 100644
index 00000000..6579831a
--- /dev/null
+++ b/samples/snippets/translate_v3_batch_translate_text_with_glossary_and_model_test.py
@@ -0,0 +1,68 @@
+# Copyright 2019 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 uuid
+
+from google.cloud import storage
+import pytest
+
+import translate_v3_batch_translate_text_with_glossary_and_model
+import translate_v3_create_glossary
+import translate_v3_delete_glossary
+
+PROJECT_ID = os.environ["GOOGLE_CLOUD_PROJECT"]
+GLOSSARY_INPUT_URI = "gs://cloud-samples-data/translation/glossary_ja.csv"
+MODEL_ID = "TRL3128559826197068699"
+
+
+@pytest.fixture(scope="session")
+def glossary():
+ """Get the ID of a glossary available to session (do not mutate/delete)."""
+ glossary_id = "must-start-with-letters-" + str(uuid.uuid1())
+ translate_v3_create_glossary.create_glossary(
+ project_id=PROJECT_ID, input_uri=GLOSSARY_INPUT_URI, glossary_id=glossary_id
+ )
+
+ yield glossary_id
+
+ try:
+ translate_v3_delete_glossary.sample_delete_glossary(PROJECT_ID, glossary_id)
+ except Exception:
+ pass
+
+
+@pytest.fixture(scope="function")
+def bucket():
+ """Create a temporary bucket to store annotation output."""
+ bucket_name = "mike-test-delete-" + str(uuid.uuid1())
+ storage_client = storage.Client()
+ bucket = storage_client.create_bucket(bucket_name)
+
+ yield bucket
+
+ bucket.delete(force=True)
+
+
+def test_batch_translate_text_with_glossary_and_model(capsys, bucket, glossary):
+ translate_v3_batch_translate_text_with_glossary_and_model.batch_translate_text_with_glossary_and_model(
+ "gs://cloud-samples-data/translation/text_with_custom_model_and_glossary.txt",
+ "gs://{}/translation/BATCH_TRANSLATION_OUTPUT/".format(bucket.name),
+ PROJECT_ID,
+ MODEL_ID,
+ glossary,
+ )
+
+ out, _ = capsys.readouterr()
+ assert "Total Characters: 25" in out
diff --git a/samples/snippets/translate_v3_batch_translate_text_with_glossary_test.py b/samples/snippets/translate_v3_batch_translate_text_with_glossary_test.py
index 23aa6691..33a1f829 100644
--- a/samples/snippets/translate_v3_batch_translate_text_with_glossary_test.py
+++ b/samples/snippets/translate_v3_batch_translate_text_with_glossary_test.py
@@ -46,18 +46,18 @@ def glossary():
)
def delete_glossary():
try:
- translate_v3_delete_glossary.delete_glossary(
- PROJECT_ID, glossary_id)
+ translate_v3_delete_glossary.delete_glossary(PROJECT_ID, glossary_id)
except NotFound as e:
# Ignoring this case.
print("Got NotFound, detail: {}".format(str(e)))
+
delete_glossary()
@pytest.fixture(scope="function")
def bucket():
"""Create a temporary bucket to store annotation output."""
- bucket_name = f'tmp-{uuid.uuid4().hex}'
+ bucket_name = f"tmp-{uuid.uuid4().hex}"
storage_client = storage.Client()
bucket = storage_client.create_bucket(bucket_name)
@@ -73,7 +73,7 @@ def test_batch_translate_text_with_glossary(capsys, bucket, glossary):
"gs://{}/translation/BATCH_TRANSLATION_OUTPUT/".format(bucket.name),
PROJECT_ID,
glossary,
- 240
+ 320,
)
out, _ = capsys.readouterr()
diff --git a/samples/snippets/translate_v3_batch_translate_text_with_model.py b/samples/snippets/translate_v3_batch_translate_text_with_model.py
new file mode 100644
index 00000000..07d967d7
--- /dev/null
+++ b/samples/snippets/translate_v3_batch_translate_text_with_model.py
@@ -0,0 +1,69 @@
+# 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.
+
+
+# [START translate_v3_batch_translate_text_with_model]
+from google.cloud import translate
+
+
+def batch_translate_text_with_model(
+ input_uri="gs://YOUR_BUCKET_ID/path/to/your/file.txt",
+ output_uri="gs://YOUR_BUCKET_ID/path/to/save/results/",
+ project_id="YOUR_PROJECT_ID",
+ model_id="YOUR_MODEL_ID",
+):
+ """Batch translate text using Translation model.
+ Model can be AutoML or General[built-in] model. """
+
+ client = translate.TranslationServiceClient()
+
+ # Supported file types: https://cloud.google.com/translate/docs/supported-formats
+ gcs_source = {"input_uri": input_uri}
+ location = "us-central1"
+
+ input_configs_element = {
+ "gcs_source": gcs_source,
+ "mime_type": "text/plain", # Can be "text/plain" or "text/html".
+ }
+ gcs_destination = {"output_uri_prefix": output_uri}
+ output_config = {"gcs_destination": gcs_destination}
+ parent = f"projects/{project_id}/locations/{location}"
+
+ model_path = "projects/{}/locations/{}/models/{}".format(
+ project_id, location, model_id # The location of AutoML model.
+ )
+
+ # Supported language codes: https://cloud.google.com/translate/docs/languages
+ models = {"ja": model_path} # takes a target lang as key.
+
+ operation = client.batch_translate_text(
+ request={
+ "parent": parent,
+ "source_language_code": "en",
+ "target_language_codes": ["ja"], # Up to 10 language codes here.
+ "input_configs": [input_configs_element],
+ "output_config": output_config,
+ "models": models,
+ }
+ )
+
+ print("Waiting for operation to complete...")
+ response = operation.result()
+
+ # Display the translation for each input text provided.
+ print("Total Characters: {}".format(response.total_characters))
+ print("Translated Characters: {}".format(response.translated_characters))
+
+
+# [END translate_v3_batch_translate_text_with_model]
diff --git a/samples/snippets/translate_v3_batch_translate_text_with_model_test.py b/samples/snippets/translate_v3_batch_translate_text_with_model_test.py
new file mode 100644
index 00000000..f6ad1007
--- /dev/null
+++ b/samples/snippets/translate_v3_batch_translate_text_with_model_test.py
@@ -0,0 +1,49 @@
+# 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 uuid
+
+from google.cloud import storage
+import pytest
+
+import translate_v3_batch_translate_text_with_model
+
+
+PROJECT_ID = os.environ["GOOGLE_CLOUD_PROJECT"]
+MODEL_ID = "TRL3128559826197068699"
+
+
+@pytest.fixture(scope="function")
+def bucket():
+ """Create a temporary bucket to store annotation output."""
+ bucket_name = f"tmp-{uuid.uuid4().hex}"
+ storage_client = storage.Client()
+ bucket = storage_client.create_bucket(bucket_name)
+
+ yield bucket
+
+ bucket.delete(force=True)
+
+
+def test_batch_translate_text_with_model(capsys, bucket):
+ translate_v3_batch_translate_text_with_model.batch_translate_text_with_model(
+ "gs://cloud-samples-data/translation/custom_model_text.txt",
+ "gs://{}/translation/BATCH_TRANSLATION_OUTPUT/".format(bucket.name),
+ PROJECT_ID,
+ MODEL_ID,
+ )
+ out, _ = capsys.readouterr()
+ assert "Total Characters: 15" in out
+ assert "Translated Characters: 15" in out
diff --git a/samples/snippets/translate_v3_create_glossary.py b/samples/snippets/translate_v3_create_glossary.py
index 2955acaa..b2fd3863 100644
--- a/samples/snippets/translate_v3_create_glossary.py
+++ b/samples/snippets/translate_v3_create_glossary.py
@@ -17,10 +17,10 @@
def create_glossary(
- project_id="YOUR_PROJECT_ID",
- input_uri="YOUR_INPUT_URI",
- glossary_id="YOUR_GLOSSARY_ID",
- timeout=180,
+ project_id="YOUR_PROJECT_ID",
+ input_uri="YOUR_INPUT_URI",
+ glossary_id="YOUR_GLOSSARY_ID",
+ timeout=180,
):
"""
Create a equivalent term sets glossary. Glossary can be words or
diff --git a/samples/snippets/translate_v3_create_glossary_test.py b/samples/snippets/translate_v3_create_glossary_test.py
index a24f461e..3e4b61cf 100644
--- a/samples/snippets/translate_v3_create_glossary_test.py
+++ b/samples/snippets/translate_v3_create_glossary_test.py
@@ -46,9 +46,9 @@ def test_create_glossary(capsys):
)
def delete_glossary():
try:
- translate_v3_delete_glossary.delete_glossary(
- PROJECT_ID, glossary_id)
+ translate_v3_delete_glossary.delete_glossary(PROJECT_ID, glossary_id)
except NotFound as e:
# Ignoring this case.
print("Got NotFound, detail: {}".format(str(e)))
+
delete_glossary()
diff --git a/samples/snippets/translate_v3_delete_glossary.py b/samples/snippets/translate_v3_delete_glossary.py
index fb9f86af..336b7a06 100644
--- a/samples/snippets/translate_v3_delete_glossary.py
+++ b/samples/snippets/translate_v3_delete_glossary.py
@@ -17,9 +17,7 @@
def delete_glossary(
- project_id="YOUR_PROJECT_ID",
- glossary_id="YOUR_GLOSSARY_ID",
- timeout=180,
+ project_id="YOUR_PROJECT_ID", glossary_id="YOUR_GLOSSARY_ID", timeout=180,
):
"""Delete a specific glossary based on the glossary ID."""
client = translate.TranslationServiceClient()
diff --git a/samples/snippets/translate_v3_detect_language.py b/samples/snippets/translate_v3_detect_language.py
index 9e92b607..eae985c3 100644
--- a/samples/snippets/translate_v3_detect_language.py
+++ b/samples/snippets/translate_v3_detect_language.py
@@ -37,9 +37,9 @@ def detect_language(project_id="YOUR_PROJECT_ID"):
# The most probable language is first.
for language in response.languages:
# The language detected
- print(u"Language code: {}".format(language.language_code))
+ print("Language code: {}".format(language.language_code))
# Confidence of detection result for this language
- print(u"Confidence: {}".format(language.confidence))
+ print("Confidence: {}".format(language.confidence))
# [END translate_v3_detect_language]
diff --git a/samples/snippets/translate_v3_get_glossary_test.py b/samples/snippets/translate_v3_get_glossary_test.py
index 96ea6b78..a4fc3231 100644
--- a/samples/snippets/translate_v3_get_glossary_test.py
+++ b/samples/snippets/translate_v3_get_glossary_test.py
@@ -45,11 +45,11 @@ def glossary():
)
def delete_glossary():
try:
- translate_v3_delete_glossary.delete_glossary(
- PROJECT_ID, glossary_id)
+ translate_v3_delete_glossary.delete_glossary(PROJECT_ID, glossary_id)
except NotFound as e:
# Ignoring this case.
print("Got NotFound, detail: {}".format(str(e)))
+
delete_glossary()
diff --git a/samples/snippets/translate_v3_get_supported_languages.py b/samples/snippets/translate_v3_get_supported_languages.py
index db779278..3802a7e1 100644
--- a/samples/snippets/translate_v3_get_supported_languages.py
+++ b/samples/snippets/translate_v3_get_supported_languages.py
@@ -29,7 +29,7 @@ def get_supported_languages(project_id="YOUR_PROJECT_ID"):
# List language codes of supported languages.
print("Supported Languages:")
for language in response.languages:
- print(u"Language Code: {}".format(language.language_code))
+ print("Language Code: {}".format(language.language_code))
# [END translate_v3_get_supported_languages]
diff --git a/samples/snippets/translate_v3_get_supported_languages_with_target.py b/samples/snippets/translate_v3_get_supported_languages_with_target.py
index 3a164dcb..856b3178 100644
--- a/samples/snippets/translate_v3_get_supported_languages_with_target.py
+++ b/samples/snippets/translate_v3_get_supported_languages_with_target.py
@@ -27,12 +27,12 @@ def get_supported_languages_with_target(project_id="YOUR_PROJECT_ID"):
# Supported language codes: https://cloud.google.com/translate/docs/languages
response = client.get_supported_languages(
- display_language_code="is", # target language code
- parent=parent
+ display_language_code="is", parent=parent # target language code
)
# List language codes of supported languages
for language in response.languages:
- print(u"Language Code: {}".format(language.language_code))
- print(u"Display Name: {}".format(language.display_name))
+ print("Language Code: {}".format(language.language_code))
+ print("Display Name: {}".format(language.display_name))
+
# [END translate_v3_get_supported_languages_for_target]
diff --git a/samples/snippets/translate_v3_get_supported_languages_with_target_test.py b/samples/snippets/translate_v3_get_supported_languages_with_target_test.py
index 8f3f52cf..9688efee 100644
--- a/samples/snippets/translate_v3_get_supported_languages_with_target_test.py
+++ b/samples/snippets/translate_v3_get_supported_languages_with_target_test.py
@@ -21,9 +21,7 @@
def test_list_languages_with_target(capsys):
- get_supported_langs.get_supported_languages_with_target(
- PROJECT_ID
- )
+ get_supported_langs.get_supported_languages_with_target(PROJECT_ID)
out, _ = capsys.readouterr()
assert u"Language Code: sq" in out
assert u"Display Name: albanska" in out
diff --git a/samples/snippets/translate_v3_list_glossary_test.py b/samples/snippets/translate_v3_list_glossary_test.py
index 8f4eaa1a..ed2a4754 100644
--- a/samples/snippets/translate_v3_list_glossary_test.py
+++ b/samples/snippets/translate_v3_list_glossary_test.py
@@ -45,11 +45,11 @@ def glossary():
)
def delete_glossary():
try:
- translate_v3_delete_glossary.delete_glossary(
- PROJECT_ID, glossary_id)
+ translate_v3_delete_glossary.delete_glossary(PROJECT_ID, glossary_id)
except NotFound as e:
# Ignoring this case.
print("Got NotFound, detail: {}".format(str(e)))
+
delete_glossary()
diff --git a/samples/snippets/translate_v3_translate_text.py b/samples/snippets/translate_v3_translate_text.py
index 78a79b4e..cdfe819f 100644
--- a/samples/snippets/translate_v3_translate_text.py
+++ b/samples/snippets/translate_v3_translate_text.py
@@ -33,13 +33,13 @@ def translate_text(text="YOUR_TEXT_TO_TRANSLATE", project_id="YOUR_PROJECT_ID"):
"contents": [text],
"mime_type": "text/plain", # mime types: text/plain, text/html
"source_language_code": "en-US",
- "target_language_code": "fr"
+ "target_language_code": "fr",
}
)
# Display the translation for each input text provided
for translation in response.translations:
- print(u"Translated text: {}".format(translation.translated_text))
+ print("Translated text: {}".format(translation.translated_text))
# [END translate_v3_translate_text]
diff --git a/samples/snippets/translate_v3_translate_text_test.py b/samples/snippets/translate_v3_translate_text_test.py
index c93cb91f..fee6e771 100644
--- a/samples/snippets/translate_v3_translate_text_test.py
+++ b/samples/snippets/translate_v3_translate_text_test.py
@@ -21,7 +21,6 @@
def test_translate_text(capsys):
- translate_v3_translate_text.translate_text(
- "Hello World!", PROJECT_ID)
+ translate_v3_translate_text.translate_text("Hello World!", PROJECT_ID)
out, _ = capsys.readouterr()
assert "Bonjour le monde" in out
diff --git a/samples/snippets/translate_v3_translate_text_with_glossary.py b/samples/snippets/translate_v3_translate_text_with_glossary.py
index b62d5413..addd737f 100644
--- a/samples/snippets/translate_v3_translate_text_with_glossary.py
+++ b/samples/snippets/translate_v3_translate_text_with_glossary.py
@@ -32,8 +32,7 @@ def translate_text_with_glossary(
project_id, "us-central1", glossary_id # The location of the glossary
)
- glossary_config = translate.TranslateTextGlossaryConfig(
- glossary=glossary)
+ glossary_config = translate.TranslateTextGlossaryConfig(glossary=glossary)
# Supported language codes: https://cloud.google.com/translate/docs/languages
response = client.translate_text(
@@ -42,13 +41,13 @@ def translate_text_with_glossary(
"target_language_code": "ja",
"source_language_code": "en",
"parent": parent,
- "glossary_config": glossary_config
+ "glossary_config": glossary_config,
}
)
print("Translated text: \n")
for translation in response.glossary_translations:
- print(u"\t {}".format(translation.translated_text))
+ print("\t {}".format(translation.translated_text))
# [END translate_v3_translate_text_with_glossary]
diff --git a/samples/snippets/translate_v3_translate_text_with_glossary_test.py b/samples/snippets/translate_v3_translate_text_with_glossary_test.py
index 1caa9e6e..46724dde 100644
--- a/samples/snippets/translate_v3_translate_text_with_glossary_test.py
+++ b/samples/snippets/translate_v3_translate_text_with_glossary_test.py
@@ -46,11 +46,11 @@ def glossary():
)
def delete_glossary():
try:
- translate_v3_delete_glossary.delete_glossary(
- PROJECT_ID, glossary_id)
+ translate_v3_delete_glossary.delete_glossary(PROJECT_ID, glossary_id)
except NotFound as e:
# Ignoring this case.
print("Got NotFound, detail: {}".format(str(e)))
+
delete_glossary()
diff --git a/samples/snippets/translate_v3_translate_text_with_model.py b/samples/snippets/translate_v3_translate_text_with_model.py
index 44c92f96..bd61bb76 100644
--- a/samples/snippets/translate_v3_translate_text_with_model.py
+++ b/samples/snippets/translate_v3_translate_text_with_model.py
@@ -40,11 +40,10 @@ def translate_text_with_model(
"parent": parent,
"mime_type": "text/plain", # mime types: text/plain, text/html
}
-
)
# Display the translation for each input text provided
for translation in response.translations:
- print(u"Translated text: {}".format(translation.translated_text))
+ print("Translated text: {}".format(translation.translated_text))
# [END translate_v3_translate_text_with_model]
diff --git a/scripts/decrypt-secrets.sh b/scripts/decrypt-secrets.sh
index ff599eb2..21f6d2a2 100755
--- a/scripts/decrypt-secrets.sh
+++ b/scripts/decrypt-secrets.sh
@@ -20,14 +20,27 @@ ROOT=$( dirname "$DIR" )
# Work from the project root.
cd $ROOT
+# Prevent it from overriding files.
+# We recommend that sample authors use their own service account files and cloud project.
+# In that case, they are supposed to prepare these files by themselves.
+if [[ -f "testing/test-env.sh" ]] || \
+ [[ -f "testing/service-account.json" ]] || \
+ [[ -f "testing/client-secrets.json" ]]; then
+ echo "One or more target files exist, aborting."
+ exit 1
+fi
+
# Use SECRET_MANAGER_PROJECT if set, fallback to cloud-devrel-kokoro-resources.
PROJECT_ID="${SECRET_MANAGER_PROJECT:-cloud-devrel-kokoro-resources}"
gcloud secrets versions access latest --secret="python-docs-samples-test-env" \
+ --project="${PROJECT_ID}" \
> testing/test-env.sh
gcloud secrets versions access latest \
--secret="python-docs-samples-service-account" \
+ --project="${PROJECT_ID}" \
> testing/service-account.json
gcloud secrets versions access latest \
--secret="python-docs-samples-client-secrets" \
- > testing/client-secrets.json
\ No newline at end of file
+ --project="${PROJECT_ID}" \
+ > testing/client-secrets.json
diff --git a/setup.py b/setup.py
index 047a6707..9045fdcf 100644
--- a/setup.py
+++ b/setup.py
@@ -22,7 +22,7 @@
name = "google-cloud-translate"
description = "Google Cloud Translation API client library"
-version = "3.0.1"
+version = "3.0.2"
# Should be one of:
# 'Development Status :: 3 - Alpha'
# 'Development Status :: 4 - Beta'
diff --git a/synth.metadata b/synth.metadata
index 32b3b56a..85cf89ed 100644
--- a/synth.metadata
+++ b/synth.metadata
@@ -3,22 +3,22 @@
{
"git": {
"name": ".",
- "remote": "git@github.com:danoscarmike/python-translate",
- "sha": "2a80f87c6ff441fb81161db8cda1049aa6851cc4"
+ "remote": "https://github.com/googleapis/python-translate.git",
+ "sha": "2bc6296122e54bc93804d37411ff7554e2808626"
}
},
{
"git": {
"name": "synthtool",
"remote": "https://github.com/googleapis/synthtool.git",
- "sha": "5f2f711c91199ba2f609d3f06a2fe22aee4e5be3"
+ "sha": "f68649c5f26bcff6817c6d21e90dac0fc71fef8e"
}
},
{
"git": {
"name": "synthtool",
"remote": "https://github.com/googleapis/synthtool.git",
- "sha": "5f2f711c91199ba2f609d3f06a2fe22aee4e5be3"
+ "sha": "f68649c5f26bcff6817c6d21e90dac0fc71fef8e"
}
}
],
diff --git a/tests/system.py b/tests/system.py
index 56b16091..0cf45215 100644
--- a/tests/system.py
+++ b/tests/system.py
@@ -15,6 +15,7 @@
import os
+import pytest
import unittest
from google.cloud import translate_v2
@@ -32,6 +33,7 @@ class Config(object):
CLIENT_V3 = None
location = "global"
project_id = os.environ["PROJECT_ID"]
+ use_mtls = os.environ.get("GOOGLE_API_USE_MTLS_ENDPOINT", "never")
def setUpModule():
@@ -39,7 +41,15 @@ def setUpModule():
Config.CLIENT_V3 = translate.TranslationServiceClient()
+# Only v3/v3beta1 clients have mTLS support, so we need to skip all the
+# v2 client tests for mTLS testing.
+skip_for_mtls = pytest.mark.skipif(
+ Config.use_mtls == "always", reason="Skip the v2 client test for mTLS testing"
+)
+
+
class TestTranslate(unittest.TestCase):
+ @skip_for_mtls
def test_get_languages(self):
result = Config.CLIENT_V2.get_languages()
# There are **many** more than 10 languages.
@@ -51,6 +61,7 @@ def test_get_languages(self):
self.assertEqual(lang_map["lv"], "Latvian")
self.assertEqual(lang_map["zu"], "Zulu")
+ @skip_for_mtls
def test_detect_language(self):
values = ["takoy", "fa\xe7ade", "s'il vous plait"]
detections = Config.CLIENT_V2.detect_language(values)
@@ -59,6 +70,7 @@ def test_detect_language(self):
self.assertEqual(detections[1]["language"], "fr")
self.assertEqual(detections[2]["language"], "fr")
+ @skip_for_mtls
def test_translate(self):
values = ["petnaest", "dek kvin", "Me llamo Jeff", "My name is Jeff"]
translations = Config.CLIENT_V2.translate(
diff --git a/tests/system/test_vpcsc.py b/tests/system/test_vpcsc.py
index 814ab875..e3bf098b 100644
--- a/tests/system/test_vpcsc.py
+++ b/tests/system/test_vpcsc.py
@@ -31,12 +31,12 @@ def client():
@pytest.fixture(scope="module")
def parent_inside(client):
- return client.location_path(vpcsc_config.project_inside, "us-central1")
+ return f"projects/{vpcsc_config.project_inside}/locations/us-central1"
@pytest.fixture(scope="module")
def parent_outside(client):
- return client.location_path(vpcsc_config.project_outside, "us-central1")
+ return f"projects/{vpcsc_config.project_outside}/locations/us-central1"
@pytest.fixture(scope="module")
@@ -75,26 +75,26 @@ def glossary_outside(glossary_name_outside):
@vpcsc_config.skip_unless_inside_vpcsc
def test_create_glossary_w_inside(client, parent_inside, glossary_inside):
- client.create_glossary(parent_inside, glossary_inside)
+ client.create_glossary(parent=parent_inside, glossary=glossary_inside)
@vpcsc_config.skip_unless_inside_vpcsc
def test_create_glossary_w_outside(client, parent_outside, glossary_outside):
with pytest.raises(exceptions.PermissionDenied) as exc:
- client.create_glossary(parent_outside, glossary_outside)
+ client.create_glossary(parent=parent_outside, glossary=glossary_outside)
assert exc.value.message.startswith(_VPCSC_PROHIBITED_MESSAGE)
@vpcsc_config.skip_unless_inside_vpcsc
def test_list_glossaries_w_inside(client, parent_inside):
- list(client.list_glossaries(parent_inside))
+ list(client.list_glossaries(parent=parent_inside))
@vpcsc_config.skip_unless_inside_vpcsc
def test_list_glossaries_w_outside(client, parent_outside):
with pytest.raises(exceptions.PermissionDenied) as exc:
- list(client.list_glossaries(parent_outside))
+ list(client.list_glossaries(parent=parent_outside))
assert exc.value.message.startswith(_VPCSC_PROHIBITED_MESSAGE)
@@ -102,7 +102,7 @@ def test_list_glossaries_w_outside(client, parent_outside):
@vpcsc_config.skip_unless_inside_vpcsc
def test_get_glossary_w_inside(client, glossary_name_inside):
try:
- client.get_glossary(glossary_name_inside)
+ client.get_glossary(name=glossary_name_inside)
except exceptions.NotFound: # no perms issue
pass
@@ -110,7 +110,7 @@ def test_get_glossary_w_inside(client, glossary_name_inside):
@vpcsc_config.skip_unless_inside_vpcsc
def test_get_glossary_w_outside(client, glossary_name_outside):
with pytest.raises(exceptions.PermissionDenied) as exc:
- client.get_glossary(glossary_name_outside)
+ client.get_glossary(name=glossary_name_outside)
assert exc.value.message.startswith(_VPCSC_PROHIBITED_MESSAGE)
@@ -118,7 +118,7 @@ def test_get_glossary_w_outside(client, glossary_name_outside):
@vpcsc_config.skip_unless_inside_vpcsc
def test_delete_glossary_w_inside(client, glossary_name_inside):
try:
- client.delete_glossary(glossary_name_inside)
+ client.delete_glossary(name=glossary_name_inside)
except exceptions.NotFound: # no perms issue
pass
@@ -126,7 +126,7 @@ def test_delete_glossary_w_inside(client, glossary_name_inside):
@vpcsc_config.skip_unless_inside_vpcsc
def test_delete_glossary_w_outside(client, glossary_name_outside):
with pytest.raises(exceptions.PermissionDenied) as exc:
- client.delete_glossary(glossary_name_outside)
+ client.delete_glossary(name=glossary_name_outside)
assert exc.value.message.startswith(_VPCSC_PROHIBITED_MESSAGE)
@@ -140,11 +140,13 @@ def test_batch_translate_text_w_inside(client, parent_inside):
"gcs_destination": {"output_uri_prefix": "gs://fake-bucket/output/"}
}
client.batch_translate_text( # no perms issue
- parent_inside,
- source_language_code,
- target_language_codes,
- input_configs,
- output_config,
+ request={
+ "parent": parent_inside,
+ "source_language_code": source_language_code,
+ "target_language_codes": target_language_codes,
+ "input_configs": input_configs,
+ "output_config": output_config,
+ }
)
@@ -158,11 +160,13 @@ def test_batch_translate_text_w_outside(client, parent_outside):
}
with pytest.raises(exceptions.PermissionDenied) as exc:
client.batch_translate_text(
- parent_outside,
- source_language_code,
- target_language_codes,
- input_configs,
- output_config,
+ request={
+ "parent": parent_outside,
+ "source_language_code": source_language_code,
+ "target_language_codes": target_language_codes,
+ "input_configs": input_configs,
+ "output_config": output_config,
+ }
)
assert exc.value.message.startswith(_VPCSC_PROHIBITED_MESSAGE)
diff --git a/tests/unit/gapic/translate_v3/test_translation_service.py b/tests/unit/gapic/translate_v3/test_translation_service.py
index 556a93a2..c296227c 100644
--- a/tests/unit/gapic/translate_v3/test_translation_service.py
+++ b/tests/unit/gapic/translate_v3/test_translation_service.py
@@ -31,7 +31,7 @@
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
+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
@@ -165,14 +165,14 @@ def test_translation_service_client_client_options(
credentials_file=None,
host="squid.clam.whelk",
scopes=None,
- api_mtls_endpoint="squid.clam.whelk",
- client_cert_source=None,
+ ssl_channel_credentials=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 is
+ # 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": "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()
@@ -181,14 +181,14 @@ def test_translation_service_client_client_options(
credentials_file=None,
host=client.DEFAULT_ENDPOINT,
scopes=None,
- api_mtls_endpoint=client.DEFAULT_ENDPOINT,
- client_cert_source=None,
+ ssl_channel_credentials=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 is
+ # 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": "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()
@@ -197,90 +197,185 @@ def test_translation_service_client_client_options(
credentials_file=None,
host=client.DEFAULT_MTLS_ENDPOINT,
scopes=None,
- api_mtls_endpoint=client.DEFAULT_MTLS_ENDPOINT,
- client_cert_source=None,
+ ssl_channel_credentials=None,
quota_project_id=None,
+ client_info=transports.base.DEFAULT_CLIENT_INFO,
)
- # Check the case api_endpoint is not provided, GOOGLE_API_USE_MTLS is
- # "auto", and client_cert_source is provided.
- with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS": "auto"}):
+ # 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,
+ ssl_channel_credentials=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",
+ [
+ (
+ TranslationServiceClient,
+ transports.TranslationServiceGrpcTransport,
+ "grpc",
+ "true",
+ ),
+ (
+ TranslationServiceAsyncClient,
+ transports.TranslationServiceGrpcAsyncIOTransport,
+ "grpc_asyncio",
+ "true",
+ ),
+ (
+ TranslationServiceClient,
+ transports.TranslationServiceGrpcTransport,
+ "grpc",
+ "false",
+ ),
+ (
+ TranslationServiceAsyncClient,
+ transports.TranslationServiceGrpcAsyncIOTransport,
+ "grpc_asyncio",
+ "false",
+ ),
+ ],
+)
+@mock.patch.object(
+ TranslationServiceClient,
+ "DEFAULT_ENDPOINT",
+ modify_default_endpoint(TranslationServiceClient),
+)
+@mock.patch.object(
+ TranslationServiceAsyncClient,
+ "DEFAULT_ENDPOINT",
+ modify_default_endpoint(TranslationServiceAsyncClient),
+)
+@mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "auto"})
+def test_translation_service_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)
- patched.assert_called_once_with(
- credentials=None,
- credentials_file=None,
- host=client.DEFAULT_MTLS_ENDPOINT,
- scopes=None,
- api_mtls_endpoint=client.DEFAULT_MTLS_ENDPOINT,
- client_cert_source=client_cert_source_callback,
- quota_project_id=None,
- )
-
- # Check the case api_endpoint is not provided, GOOGLE_API_USE_MTLS is
- # "auto", and default_client_cert_source is provided.
- with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS": "auto"}):
- with mock.patch.object(transport_class, "__init__") as patched:
+ ssl_channel_creds = mock.Mock()
with mock.patch(
- "google.auth.transport.mtls.has_default_client_cert_source",
- return_value=True,
+ "grpc.ssl_channel_credentials", return_value=ssl_channel_creds
):
patched.return_value = None
- client = client_class()
+ 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
+
patched.assert_called_once_with(
credentials=None,
credentials_file=None,
- host=client.DEFAULT_MTLS_ENDPOINT,
+ host=expected_host,
scopes=None,
- api_mtls_endpoint=client.DEFAULT_MTLS_ENDPOINT,
- client_cert_source=None,
+ ssl_channel_credentials=expected_ssl_channel_creds,
quota_project_id=None,
+ client_info=transports.base.DEFAULT_CLIENT_INFO,
)
- # Check the case api_endpoint is not provided, GOOGLE_API_USE_MTLS is
- # "auto", but client_cert_source and default_client_cert_source are None.
- with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS": "auto"}):
+ # 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=False,
+ "google.auth.transport.grpc.SslCredentials.__init__", return_value=None
):
- patched.return_value = None
- client = client_class()
- patched.assert_called_once_with(
- credentials=None,
- credentials_file=None,
- host=client.DEFAULT_ENDPOINT,
- scopes=None,
- api_mtls_endpoint=client.DEFAULT_ENDPOINT,
- client_cert_source=None,
- quota_project_id=None,
- )
-
- # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS has
- # unsupported value.
- with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS": "Unsupported"}):
- with pytest.raises(MutualTLSChannelError):
- 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,
- api_mtls_endpoint=client.DEFAULT_ENDPOINT,
- client_cert_source=None,
- quota_project_id="octopus",
- )
+ 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,
+ )
+
+ # 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,
+ scopes=None,
+ ssl_channel_credentials=None,
+ quota_project_id=None,
+ client_info=transports.base.DEFAULT_CLIENT_INFO,
+ )
@pytest.mark.parametrize(
@@ -307,9 +402,9 @@ def test_translation_service_client_client_options_scopes(
credentials_file=None,
host=client.DEFAULT_ENDPOINT,
scopes=["1", "2"],
- api_mtls_endpoint=client.DEFAULT_ENDPOINT,
- client_cert_source=None,
+ ssl_channel_credentials=None,
quota_project_id=None,
+ client_info=transports.base.DEFAULT_CLIENT_INFO,
)
@@ -337,9 +432,9 @@ def test_translation_service_client_client_options_credentials_file(
credentials_file="credentials.json",
host=client.DEFAULT_ENDPOINT,
scopes=None,
- api_mtls_endpoint=client.DEFAULT_ENDPOINT,
- client_cert_source=None,
+ ssl_channel_credentials=None,
quota_project_id=None,
+ client_info=transports.base.DEFAULT_CLIENT_INFO,
)
@@ -356,9 +451,9 @@ def test_translation_service_client_client_options_from_dict():
credentials_file=None,
host="squid.clam.whelk",
scopes=None,
- api_mtls_endpoint="squid.clam.whelk",
- client_cert_source=None,
+ ssl_channel_credentials=None,
quota_project_id=None,
+ client_info=transports.base.DEFAULT_CLIENT_INFO,
)
@@ -1639,8 +1734,8 @@ def test_list_glossaries_pages():
RuntimeError,
)
pages = list(client.list_glossaries(request={}).pages)
- for page, token in zip(pages, ["abc", "def", "ghi", ""]):
- assert page.raw_page.next_page_token == token
+ for page_, token in zip(pages, ["abc", "def", "ghi", ""]):
+ assert page_.raw_page.next_page_token == token
@pytest.mark.asyncio
@@ -1726,10 +1821,10 @@ async def test_list_glossaries_async_pages():
RuntimeError,
)
pages = []
- async for page in (await client.list_glossaries(request={})).pages:
- pages.append(page)
- for page, token in zip(pages, ["abc", "def", "ghi", ""]):
- assert page.raw_page.next_page_token == token
+ async for page_ in (await client.list_glossaries(request={})).pages:
+ pages.append(page_)
+ for page_, token in zip(pages, ["abc", "def", "ghi", ""]):
+ assert page_.raw_page.next_page_token == token
def test_get_glossary(
@@ -2182,6 +2277,21 @@ def test_transport_get_channel():
assert channel
+@pytest.mark.parametrize(
+ "transport_class",
+ [
+ transports.TranslationServiceGrpcTransport,
+ transports.TranslationServiceGrpcAsyncIOTransport,
+ ],
+)
+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 = TranslationServiceClient(credentials=credentials.AnonymousCredentials(),)
@@ -2251,6 +2361,17 @@ def test_translation_service_base_transport_with_credentials_file():
)
+def test_translation_service_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.translate_v3.services.translation_service.transports.TranslationServiceTransport._prep_wrapped_messages"
+ ) as Transport:
+ Transport.return_value = None
+ adc.return_value = (credentials.AnonymousCredentials(), None)
+ transport = transports.TranslationServiceTransport()
+ adc.assert_called_once()
+
+
def test_translation_service_auth_adc():
# If no credentials are provided, we should use ADC credentials.
with mock.patch.object(auth, "default") as adc:
@@ -2305,191 +2426,116 @@ def test_translation_service_host_with_port():
def test_translation_service_grpc_transport_channel():
channel = grpc.insecure_channel("http://localhost/")
- # Check that if channel is provided, mtls endpoint and client_cert_source
- # won't be used.
- callback = mock.MagicMock()
+ # Check that channel is used if provided.
transport = transports.TranslationServiceGrpcTransport(
- host="squid.clam.whelk",
- channel=channel,
- api_mtls_endpoint="mtls.squid.clam.whelk",
- client_cert_source=callback,
+ host="squid.clam.whelk", channel=channel,
)
assert transport.grpc_channel == channel
assert transport._host == "squid.clam.whelk:443"
- assert not callback.called
def test_translation_service_grpc_asyncio_transport_channel():
channel = aio.insecure_channel("http://localhost/")
- # Check that if channel is provided, mtls endpoint and client_cert_source
- # won't be used.
- callback = mock.MagicMock()
+ # Check that channel is used if provided.
transport = transports.TranslationServiceGrpcAsyncIOTransport(
- host="squid.clam.whelk",
- channel=channel,
- api_mtls_endpoint="mtls.squid.clam.whelk",
- client_cert_source=callback,
+ host="squid.clam.whelk", channel=channel,
)
assert transport.grpc_channel == channel
assert transport._host == "squid.clam.whelk:443"
- assert not callback.called
-
-
-@mock.patch("grpc.ssl_channel_credentials", autospec=True)
-@mock.patch("google.api_core.grpc_helpers.create_channel", autospec=True)
-def test_translation_service_grpc_transport_channel_mtls_with_client_cert_source(
- grpc_create_channel, grpc_ssl_channel_cred
-):
- # Check that if channel is None, but api_mtls_endpoint and client_cert_source
- # are provided, then a mTLS channel will be created.
- mock_cred = mock.Mock()
-
- 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
-
- transport = transports.TranslationServiceGrpcTransport(
- host="squid.clam.whelk",
- credentials=mock_cred,
- api_mtls_endpoint="mtls.squid.clam.whelk",
- client_cert_source=client_cert_source_callback,
- )
- 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=mock_cred,
- credentials_file=None,
- scopes=(
- "https://www.googleapis.com/auth/cloud-platform",
- "https://www.googleapis.com/auth/cloud-translation",
- ),
- ssl_credentials=mock_ssl_cred,
- quota_project_id=None,
- )
- assert transport.grpc_channel == mock_grpc_channel
-
-
-@mock.patch("grpc.ssl_channel_credentials", autospec=True)
-@mock.patch("google.api_core.grpc_helpers_async.create_channel", autospec=True)
-def test_translation_service_grpc_asyncio_transport_channel_mtls_with_client_cert_source(
- grpc_create_channel, grpc_ssl_channel_cred
-):
- # Check that if channel is None, but api_mtls_endpoint and client_cert_source
- # are provided, then a mTLS channel will be created.
- mock_cred = mock.Mock()
-
- 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
-
- transport = transports.TranslationServiceGrpcAsyncIOTransport(
- host="squid.clam.whelk",
- credentials=mock_cred,
- api_mtls_endpoint="mtls.squid.clam.whelk",
- client_cert_source=client_cert_source_callback,
- )
- 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=mock_cred,
- credentials_file=None,
- scopes=(
- "https://www.googleapis.com/auth/cloud-platform",
- "https://www.googleapis.com/auth/cloud-translation",
- ),
- ssl_credentials=mock_ssl_cred,
- quota_project_id=None,
- )
- assert transport.grpc_channel == mock_grpc_channel
@pytest.mark.parametrize(
- "api_mtls_endpoint", ["mtls.squid.clam.whelk", "mtls.squid.clam.whelk:443"]
+ "transport_class",
+ [
+ transports.TranslationServiceGrpcTransport,
+ transports.TranslationServiceGrpcAsyncIOTransport,
+ ],
)
-@mock.patch("google.api_core.grpc_helpers.create_channel", autospec=True)
-def test_translation_service_grpc_transport_channel_mtls_with_adc(
- grpc_create_channel, api_mtls_endpoint
+def test_translation_service_transport_channel_mtls_with_client_cert_source(
+ transport_class,
):
- # Check that if channel and client_cert_source are None, but api_mtls_endpoint
- # is provided, then a mTLS channel will be created with SSL ADC.
- mock_grpc_channel = mock.Mock()
- grpc_create_channel.return_value = mock_grpc_channel
-
- # Mock google.auth.transport.grpc.SslCredentials 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),
- ):
- mock_cred = mock.Mock()
- transport = transports.TranslationServiceGrpcTransport(
- host="squid.clam.whelk",
- credentials=mock_cred,
- api_mtls_endpoint=api_mtls_endpoint,
- 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/cloud-translation",
- ),
- ssl_credentials=mock_ssl_cred,
- quota_project_id=None,
- )
- assert transport.grpc_channel == mock_grpc_channel
+ with mock.patch(
+ "grpc.ssl_channel_credentials", autospec=True
+ ) as grpc_ssl_channel_cred:
+ with mock.patch.object(
+ transport_class, "create_channel", autospec=True
+ ) 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/cloud-translation",
+ ),
+ ssl_credentials=mock_ssl_cred,
+ quota_project_id=None,
+ )
+ assert transport.grpc_channel == mock_grpc_channel
@pytest.mark.parametrize(
- "api_mtls_endpoint", ["mtls.squid.clam.whelk", "mtls.squid.clam.whelk:443"]
+ "transport_class",
+ [
+ transports.TranslationServiceGrpcTransport,
+ transports.TranslationServiceGrpcAsyncIOTransport,
+ ],
)
-@mock.patch("google.api_core.grpc_helpers_async.create_channel", autospec=True)
-def test_translation_service_grpc_asyncio_transport_channel_mtls_with_adc(
- grpc_create_channel, api_mtls_endpoint
-):
- # Check that if channel and client_cert_source are None, but api_mtls_endpoint
- # is provided, then a mTLS channel will be created with SSL ADC.
- mock_grpc_channel = mock.Mock()
- grpc_create_channel.return_value = mock_grpc_channel
-
- # Mock google.auth.transport.grpc.SslCredentials class.
+def test_translation_service_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),
):
- mock_cred = mock.Mock()
- transport = transports.TranslationServiceGrpcAsyncIOTransport(
- host="squid.clam.whelk",
- credentials=mock_cred,
- api_mtls_endpoint=api_mtls_endpoint,
- 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/cloud-translation",
- ),
- ssl_credentials=mock_ssl_cred,
- quota_project_id=None,
- )
- assert transport.grpc_channel == mock_grpc_channel
+ with mock.patch.object(
+ transport_class, "create_channel", autospec=True
+ ) 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/cloud-translation",
+ ),
+ ssl_credentials=mock_ssl_cred,
+ quota_project_id=None,
+ )
+ assert transport.grpc_channel == mock_grpc_channel
def test_translation_service_grpc_lro_client():
@@ -2541,3 +2587,24 @@ def test_parse_glossary_path():
# Check that the path construction is reversible.
actual = TranslationServiceClient.parse_glossary_path(path)
assert expected == actual
+
+
+def test_client_withDEFAULT_CLIENT_INFO():
+ client_info = gapic_v1.client_info.ClientInfo()
+
+ with mock.patch.object(
+ transports.TranslationServiceTransport, "_prep_wrapped_messages"
+ ) as prep:
+ client = TranslationServiceClient(
+ credentials=credentials.AnonymousCredentials(), client_info=client_info,
+ )
+ prep.assert_called_once_with(client_info)
+
+ with mock.patch.object(
+ transports.TranslationServiceTransport, "_prep_wrapped_messages"
+ ) as prep:
+ transport_class = TranslationServiceClient.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/translate_v3beta1/test_translation_service.py b/tests/unit/gapic/translate_v3beta1/test_translation_service.py
index 1dd49ee1..5af7b5c2 100644
--- a/tests/unit/gapic/translate_v3beta1/test_translation_service.py
+++ b/tests/unit/gapic/translate_v3beta1/test_translation_service.py
@@ -31,7 +31,7 @@
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
+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
@@ -165,14 +165,14 @@ def test_translation_service_client_client_options(
credentials_file=None,
host="squid.clam.whelk",
scopes=None,
- api_mtls_endpoint="squid.clam.whelk",
- client_cert_source=None,
+ ssl_channel_credentials=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 is
+ # 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": "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()
@@ -181,14 +181,14 @@ def test_translation_service_client_client_options(
credentials_file=None,
host=client.DEFAULT_ENDPOINT,
scopes=None,
- api_mtls_endpoint=client.DEFAULT_ENDPOINT,
- client_cert_source=None,
+ ssl_channel_credentials=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 is
+ # 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": "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()
@@ -197,90 +197,185 @@ def test_translation_service_client_client_options(
credentials_file=None,
host=client.DEFAULT_MTLS_ENDPOINT,
scopes=None,
- api_mtls_endpoint=client.DEFAULT_MTLS_ENDPOINT,
- client_cert_source=None,
+ ssl_channel_credentials=None,
quota_project_id=None,
+ client_info=transports.base.DEFAULT_CLIENT_INFO,
)
- # Check the case api_endpoint is not provided, GOOGLE_API_USE_MTLS is
- # "auto", and client_cert_source is provided.
- with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS": "auto"}):
+ # 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,
+ ssl_channel_credentials=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",
+ [
+ (
+ TranslationServiceClient,
+ transports.TranslationServiceGrpcTransport,
+ "grpc",
+ "true",
+ ),
+ (
+ TranslationServiceAsyncClient,
+ transports.TranslationServiceGrpcAsyncIOTransport,
+ "grpc_asyncio",
+ "true",
+ ),
+ (
+ TranslationServiceClient,
+ transports.TranslationServiceGrpcTransport,
+ "grpc",
+ "false",
+ ),
+ (
+ TranslationServiceAsyncClient,
+ transports.TranslationServiceGrpcAsyncIOTransport,
+ "grpc_asyncio",
+ "false",
+ ),
+ ],
+)
+@mock.patch.object(
+ TranslationServiceClient,
+ "DEFAULT_ENDPOINT",
+ modify_default_endpoint(TranslationServiceClient),
+)
+@mock.patch.object(
+ TranslationServiceAsyncClient,
+ "DEFAULT_ENDPOINT",
+ modify_default_endpoint(TranslationServiceAsyncClient),
+)
+@mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "auto"})
+def test_translation_service_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)
- patched.assert_called_once_with(
- credentials=None,
- credentials_file=None,
- host=client.DEFAULT_MTLS_ENDPOINT,
- scopes=None,
- api_mtls_endpoint=client.DEFAULT_MTLS_ENDPOINT,
- client_cert_source=client_cert_source_callback,
- quota_project_id=None,
- )
-
- # Check the case api_endpoint is not provided, GOOGLE_API_USE_MTLS is
- # "auto", and default_client_cert_source is provided.
- with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS": "auto"}):
- with mock.patch.object(transport_class, "__init__") as patched:
+ ssl_channel_creds = mock.Mock()
with mock.patch(
- "google.auth.transport.mtls.has_default_client_cert_source",
- return_value=True,
+ "grpc.ssl_channel_credentials", return_value=ssl_channel_creds
):
patched.return_value = None
- client = client_class()
+ 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
+
patched.assert_called_once_with(
credentials=None,
credentials_file=None,
- host=client.DEFAULT_MTLS_ENDPOINT,
+ host=expected_host,
scopes=None,
- api_mtls_endpoint=client.DEFAULT_MTLS_ENDPOINT,
- client_cert_source=None,
+ ssl_channel_credentials=expected_ssl_channel_creds,
quota_project_id=None,
+ client_info=transports.base.DEFAULT_CLIENT_INFO,
)
- # Check the case api_endpoint is not provided, GOOGLE_API_USE_MTLS is
- # "auto", but client_cert_source and default_client_cert_source are None.
- with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS": "auto"}):
+ # 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=False,
+ "google.auth.transport.grpc.SslCredentials.__init__", return_value=None
):
- patched.return_value = None
- client = client_class()
- patched.assert_called_once_with(
- credentials=None,
- credentials_file=None,
- host=client.DEFAULT_ENDPOINT,
- scopes=None,
- api_mtls_endpoint=client.DEFAULT_ENDPOINT,
- client_cert_source=None,
- quota_project_id=None,
- )
-
- # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS has
- # unsupported value.
- with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS": "Unsupported"}):
- with pytest.raises(MutualTLSChannelError):
- 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,
- api_mtls_endpoint=client.DEFAULT_ENDPOINT,
- client_cert_source=None,
- quota_project_id="octopus",
- )
+ 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,
+ )
+
+ # 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,
+ scopes=None,
+ ssl_channel_credentials=None,
+ quota_project_id=None,
+ client_info=transports.base.DEFAULT_CLIENT_INFO,
+ )
@pytest.mark.parametrize(
@@ -307,9 +402,9 @@ def test_translation_service_client_client_options_scopes(
credentials_file=None,
host=client.DEFAULT_ENDPOINT,
scopes=["1", "2"],
- api_mtls_endpoint=client.DEFAULT_ENDPOINT,
- client_cert_source=None,
+ ssl_channel_credentials=None,
quota_project_id=None,
+ client_info=transports.base.DEFAULT_CLIENT_INFO,
)
@@ -337,9 +432,9 @@ def test_translation_service_client_client_options_credentials_file(
credentials_file="credentials.json",
host=client.DEFAULT_ENDPOINT,
scopes=None,
- api_mtls_endpoint=client.DEFAULT_ENDPOINT,
- client_cert_source=None,
+ ssl_channel_credentials=None,
quota_project_id=None,
+ client_info=transports.base.DEFAULT_CLIENT_INFO,
)
@@ -356,9 +451,9 @@ def test_translation_service_client_client_options_from_dict():
credentials_file=None,
host="squid.clam.whelk",
scopes=None,
- api_mtls_endpoint="squid.clam.whelk",
- client_cert_source=None,
+ ssl_channel_credentials=None,
quota_project_id=None,
+ client_info=transports.base.DEFAULT_CLIENT_INFO,
)
@@ -1520,8 +1615,8 @@ def test_list_glossaries_pages():
RuntimeError,
)
pages = list(client.list_glossaries(request={}).pages)
- for page, token in zip(pages, ["abc", "def", "ghi", ""]):
- assert page.raw_page.next_page_token == token
+ for page_, token in zip(pages, ["abc", "def", "ghi", ""]):
+ assert page_.raw_page.next_page_token == token
@pytest.mark.asyncio
@@ -1607,10 +1702,10 @@ async def test_list_glossaries_async_pages():
RuntimeError,
)
pages = []
- async for page in (await client.list_glossaries(request={})).pages:
- pages.append(page)
- for page, token in zip(pages, ["abc", "def", "ghi", ""]):
- assert page.raw_page.next_page_token == token
+ async for page_ in (await client.list_glossaries(request={})).pages:
+ pages.append(page_)
+ for page_, token in zip(pages, ["abc", "def", "ghi", ""]):
+ assert page_.raw_page.next_page_token == token
def test_get_glossary(
@@ -2063,6 +2158,21 @@ def test_transport_get_channel():
assert channel
+@pytest.mark.parametrize(
+ "transport_class",
+ [
+ transports.TranslationServiceGrpcTransport,
+ transports.TranslationServiceGrpcAsyncIOTransport,
+ ],
+)
+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 = TranslationServiceClient(credentials=credentials.AnonymousCredentials(),)
@@ -2132,6 +2242,17 @@ def test_translation_service_base_transport_with_credentials_file():
)
+def test_translation_service_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.translate_v3beta1.services.translation_service.transports.TranslationServiceTransport._prep_wrapped_messages"
+ ) as Transport:
+ Transport.return_value = None
+ adc.return_value = (credentials.AnonymousCredentials(), None)
+ transport = transports.TranslationServiceTransport()
+ adc.assert_called_once()
+
+
def test_translation_service_auth_adc():
# If no credentials are provided, we should use ADC credentials.
with mock.patch.object(auth, "default") as adc:
@@ -2186,191 +2307,116 @@ def test_translation_service_host_with_port():
def test_translation_service_grpc_transport_channel():
channel = grpc.insecure_channel("http://localhost/")
- # Check that if channel is provided, mtls endpoint and client_cert_source
- # won't be used.
- callback = mock.MagicMock()
+ # Check that channel is used if provided.
transport = transports.TranslationServiceGrpcTransport(
- host="squid.clam.whelk",
- channel=channel,
- api_mtls_endpoint="mtls.squid.clam.whelk",
- client_cert_source=callback,
+ host="squid.clam.whelk", channel=channel,
)
assert transport.grpc_channel == channel
assert transport._host == "squid.clam.whelk:443"
- assert not callback.called
def test_translation_service_grpc_asyncio_transport_channel():
channel = aio.insecure_channel("http://localhost/")
- # Check that if channel is provided, mtls endpoint and client_cert_source
- # won't be used.
- callback = mock.MagicMock()
+ # Check that channel is used if provided.
transport = transports.TranslationServiceGrpcAsyncIOTransport(
- host="squid.clam.whelk",
- channel=channel,
- api_mtls_endpoint="mtls.squid.clam.whelk",
- client_cert_source=callback,
+ host="squid.clam.whelk", channel=channel,
)
assert transport.grpc_channel == channel
assert transport._host == "squid.clam.whelk:443"
- assert not callback.called
-
-
-@mock.patch("grpc.ssl_channel_credentials", autospec=True)
-@mock.patch("google.api_core.grpc_helpers.create_channel", autospec=True)
-def test_translation_service_grpc_transport_channel_mtls_with_client_cert_source(
- grpc_create_channel, grpc_ssl_channel_cred
-):
- # Check that if channel is None, but api_mtls_endpoint and client_cert_source
- # are provided, then a mTLS channel will be created.
- mock_cred = mock.Mock()
-
- 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
-
- transport = transports.TranslationServiceGrpcTransport(
- host="squid.clam.whelk",
- credentials=mock_cred,
- api_mtls_endpoint="mtls.squid.clam.whelk",
- client_cert_source=client_cert_source_callback,
- )
- 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=mock_cred,
- credentials_file=None,
- scopes=(
- "https://www.googleapis.com/auth/cloud-platform",
- "https://www.googleapis.com/auth/cloud-translation",
- ),
- ssl_credentials=mock_ssl_cred,
- quota_project_id=None,
- )
- assert transport.grpc_channel == mock_grpc_channel
-
-
-@mock.patch("grpc.ssl_channel_credentials", autospec=True)
-@mock.patch("google.api_core.grpc_helpers_async.create_channel", autospec=True)
-def test_translation_service_grpc_asyncio_transport_channel_mtls_with_client_cert_source(
- grpc_create_channel, grpc_ssl_channel_cred
-):
- # Check that if channel is None, but api_mtls_endpoint and client_cert_source
- # are provided, then a mTLS channel will be created.
- mock_cred = mock.Mock()
-
- 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
-
- transport = transports.TranslationServiceGrpcAsyncIOTransport(
- host="squid.clam.whelk",
- credentials=mock_cred,
- api_mtls_endpoint="mtls.squid.clam.whelk",
- client_cert_source=client_cert_source_callback,
- )
- 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=mock_cred,
- credentials_file=None,
- scopes=(
- "https://www.googleapis.com/auth/cloud-platform",
- "https://www.googleapis.com/auth/cloud-translation",
- ),
- ssl_credentials=mock_ssl_cred,
- quota_project_id=None,
- )
- assert transport.grpc_channel == mock_grpc_channel
@pytest.mark.parametrize(
- "api_mtls_endpoint", ["mtls.squid.clam.whelk", "mtls.squid.clam.whelk:443"]
+ "transport_class",
+ [
+ transports.TranslationServiceGrpcTransport,
+ transports.TranslationServiceGrpcAsyncIOTransport,
+ ],
)
-@mock.patch("google.api_core.grpc_helpers.create_channel", autospec=True)
-def test_translation_service_grpc_transport_channel_mtls_with_adc(
- grpc_create_channel, api_mtls_endpoint
+def test_translation_service_transport_channel_mtls_with_client_cert_source(
+ transport_class,
):
- # Check that if channel and client_cert_source are None, but api_mtls_endpoint
- # is provided, then a mTLS channel will be created with SSL ADC.
- mock_grpc_channel = mock.Mock()
- grpc_create_channel.return_value = mock_grpc_channel
-
- # Mock google.auth.transport.grpc.SslCredentials 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),
- ):
- mock_cred = mock.Mock()
- transport = transports.TranslationServiceGrpcTransport(
- host="squid.clam.whelk",
- credentials=mock_cred,
- api_mtls_endpoint=api_mtls_endpoint,
- 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/cloud-translation",
- ),
- ssl_credentials=mock_ssl_cred,
- quota_project_id=None,
- )
- assert transport.grpc_channel == mock_grpc_channel
+ with mock.patch(
+ "grpc.ssl_channel_credentials", autospec=True
+ ) as grpc_ssl_channel_cred:
+ with mock.patch.object(
+ transport_class, "create_channel", autospec=True
+ ) 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/cloud-translation",
+ ),
+ ssl_credentials=mock_ssl_cred,
+ quota_project_id=None,
+ )
+ assert transport.grpc_channel == mock_grpc_channel
@pytest.mark.parametrize(
- "api_mtls_endpoint", ["mtls.squid.clam.whelk", "mtls.squid.clam.whelk:443"]
+ "transport_class",
+ [
+ transports.TranslationServiceGrpcTransport,
+ transports.TranslationServiceGrpcAsyncIOTransport,
+ ],
)
-@mock.patch("google.api_core.grpc_helpers_async.create_channel", autospec=True)
-def test_translation_service_grpc_asyncio_transport_channel_mtls_with_adc(
- grpc_create_channel, api_mtls_endpoint
-):
- # Check that if channel and client_cert_source are None, but api_mtls_endpoint
- # is provided, then a mTLS channel will be created with SSL ADC.
- mock_grpc_channel = mock.Mock()
- grpc_create_channel.return_value = mock_grpc_channel
-
- # Mock google.auth.transport.grpc.SslCredentials class.
+def test_translation_service_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),
):
- mock_cred = mock.Mock()
- transport = transports.TranslationServiceGrpcAsyncIOTransport(
- host="squid.clam.whelk",
- credentials=mock_cred,
- api_mtls_endpoint=api_mtls_endpoint,
- 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/cloud-translation",
- ),
- ssl_credentials=mock_ssl_cred,
- quota_project_id=None,
- )
- assert transport.grpc_channel == mock_grpc_channel
+ with mock.patch.object(
+ transport_class, "create_channel", autospec=True
+ ) 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/cloud-translation",
+ ),
+ ssl_credentials=mock_ssl_cred,
+ quota_project_id=None,
+ )
+ assert transport.grpc_channel == mock_grpc_channel
def test_translation_service_grpc_lro_client():
@@ -2422,3 +2468,24 @@ def test_parse_glossary_path():
# Check that the path construction is reversible.
actual = TranslationServiceClient.parse_glossary_path(path)
assert expected == actual
+
+
+def test_client_withDEFAULT_CLIENT_INFO():
+ client_info = gapic_v1.client_info.ClientInfo()
+
+ with mock.patch.object(
+ transports.TranslationServiceTransport, "_prep_wrapped_messages"
+ ) as prep:
+ client = TranslationServiceClient(
+ credentials=credentials.AnonymousCredentials(), client_info=client_info,
+ )
+ prep.assert_called_once_with(client_info)
+
+ with mock.patch.object(
+ transports.TranslationServiceTransport, "_prep_wrapped_messages"
+ ) as prep:
+ transport_class = TranslationServiceClient.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/v2/test__http.py b/tests/unit/v2/test__http.py
index 4830c0c8..c48cc4bb 100644
--- a/tests/unit/v2/test__http.py
+++ b/tests/unit/v2/test__http.py
@@ -28,30 +28,56 @@ def _make_one(self, *args, **kw):
return self._get_target_class()(*args, **kw)
def test_build_api_url_no_extra_query_params(self):
+ from six.moves.urllib.parse import parse_qsl
+ from six.moves.urllib.parse import urlsplit
+
conn = self._make_one(object())
- URI = "/".join(
- [
- conn.DEFAULT_API_ENDPOINT,
- "language",
- "translate",
- conn.API_VERSION,
- "foo",
- ]
+ uri = conn.build_api_url("/foo")
+ scheme, netloc, path, qs, _ = urlsplit(uri)
+ self.assertEqual("%s://%s" % (scheme, netloc), conn.API_BASE_URL)
+ self.assertEqual(
+ path, "/".join(["", "language", "translate", conn.API_VERSION, "foo"])
)
- self.assertEqual(conn.build_api_url("/foo"), URI)
+ parms = dict(parse_qsl(qs))
+ pretty_print = parms.pop("prettyPrint", "false")
+ self.assertEqual(pretty_print, "false")
+ self.assertEqual(parms, {})
def test_build_api_url_w_custom_endpoint(self):
+ from six.moves.urllib.parse import parse_qsl
+ from six.moves.urllib.parse import urlsplit
+
custom_endpoint = "https://foo-translation.googleapis.com"
conn = self._make_one(object(), api_endpoint=custom_endpoint)
- URI = "/".join(
- [custom_endpoint, "language", "translate", conn.API_VERSION, "foo"]
+ uri = conn.build_api_url("/foo")
+ scheme, netloc, path, qs, _ = urlsplit(uri)
+ self.assertEqual("%s://%s" % (scheme, netloc), custom_endpoint)
+ self.assertEqual(
+ path, "/".join(["", "language", "translate", conn.API_VERSION, "foo"])
)
- self.assertEqual(conn.build_api_url("/foo"), URI)
+ parms = dict(parse_qsl(qs))
+ pretty_print = parms.pop("prettyPrint", "false")
+ self.assertEqual(pretty_print, "false")
+ self.assertEqual(parms, {})
def test_build_api_url_w_extra_query_params(self):
from six.moves.urllib.parse import parse_qsl
from six.moves.urllib.parse import urlsplit
+ conn = self._make_one(object())
+ uri = conn.build_api_url("/foo", {"bar": "baz"})
+ scheme, netloc, path, qs, _ = urlsplit(uri)
+ self.assertEqual("%s://%s" % (scheme, netloc), conn.API_BASE_URL)
+ self.assertEqual(
+ path, "/".join(["", "language", "translate", conn.API_VERSION, "foo"])
+ )
+ parms = dict(parse_qsl(qs))
+ self.assertEqual(parms["bar"], "baz")
+
+ def test_build_api_url_w_extra_query_params_tuple(self):
+ from six.moves.urllib.parse import parse_qsl
+ from six.moves.urllib.parse import urlsplit
+
conn = self._make_one(object())
query_params = [("q", "val1"), ("q", "val2")]
uri = conn.build_api_url("/foo", query_params=query_params)
@@ -59,8 +85,11 @@ def test_build_api_url_w_extra_query_params(self):
self.assertEqual("%s://%s" % (scheme, netloc), conn.API_BASE_URL)
expected_path = "/".join(["", "language", "translate", conn.API_VERSION, "foo"])
self.assertEqual(path, expected_path)
- params = parse_qsl(qs)
- self.assertEqual(params, query_params)
+ params = list(
+ sorted(param for param in parse_qsl(qs) if param[0] != "prettyPrint")
+ )
+ expected_params = [("q", "val1"), ("q", "val2")]
+ self.assertEqual(params, expected_params)
def test_extra_headers(self):
import requests