diff --git a/google/cloud/texttospeech/__init__.py b/google/cloud/texttospeech/__init__.py index c111427a..d9fc5f70 100644 --- a/google/cloud/texttospeech/__init__.py +++ b/google/cloud/texttospeech/__init__.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- - # Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,34 +14,35 @@ # limitations under the License. # -from google.cloud.texttospeech_v1.services.text_to_speech.async_client import ( - TextToSpeechAsyncClient, -) from google.cloud.texttospeech_v1.services.text_to_speech.client import ( TextToSpeechClient, ) +from google.cloud.texttospeech_v1.services.text_to_speech.async_client import ( + TextToSpeechAsyncClient, +) + from google.cloud.texttospeech_v1.types.cloud_tts import AudioConfig -from google.cloud.texttospeech_v1.types.cloud_tts import AudioEncoding from google.cloud.texttospeech_v1.types.cloud_tts import ListVoicesRequest from google.cloud.texttospeech_v1.types.cloud_tts import ListVoicesResponse -from google.cloud.texttospeech_v1.types.cloud_tts import SsmlVoiceGender from google.cloud.texttospeech_v1.types.cloud_tts import SynthesisInput from google.cloud.texttospeech_v1.types.cloud_tts import SynthesizeSpeechRequest from google.cloud.texttospeech_v1.types.cloud_tts import SynthesizeSpeechResponse from google.cloud.texttospeech_v1.types.cloud_tts import Voice from google.cloud.texttospeech_v1.types.cloud_tts import VoiceSelectionParams +from google.cloud.texttospeech_v1.types.cloud_tts import AudioEncoding +from google.cloud.texttospeech_v1.types.cloud_tts import SsmlVoiceGender __all__ = ( + "TextToSpeechClient", + "TextToSpeechAsyncClient", "AudioConfig", - "AudioEncoding", "ListVoicesRequest", "ListVoicesResponse", - "SsmlVoiceGender", "SynthesisInput", "SynthesizeSpeechRequest", "SynthesizeSpeechResponse", - "TextToSpeechAsyncClient", - "TextToSpeechClient", "Voice", "VoiceSelectionParams", + "AudioEncoding", + "SsmlVoiceGender", ) diff --git a/google/cloud/texttospeech_v1/__init__.py b/google/cloud/texttospeech_v1/__init__.py index 4d285a25..b26fe026 100644 --- a/google/cloud/texttospeech_v1/__init__.py +++ b/google/cloud/texttospeech_v1/__init__.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- - # Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,19 +15,21 @@ # from .services.text_to_speech import TextToSpeechClient +from .services.text_to_speech import TextToSpeechAsyncClient + from .types.cloud_tts import AudioConfig -from .types.cloud_tts import AudioEncoding from .types.cloud_tts import ListVoicesRequest from .types.cloud_tts import ListVoicesResponse -from .types.cloud_tts import SsmlVoiceGender from .types.cloud_tts import SynthesisInput from .types.cloud_tts import SynthesizeSpeechRequest from .types.cloud_tts import SynthesizeSpeechResponse from .types.cloud_tts import Voice from .types.cloud_tts import VoiceSelectionParams - +from .types.cloud_tts import AudioEncoding +from .types.cloud_tts import SsmlVoiceGender __all__ = ( + "TextToSpeechAsyncClient", "AudioConfig", "AudioEncoding", "ListVoicesRequest", @@ -37,7 +38,7 @@ "SynthesisInput", "SynthesizeSpeechRequest", "SynthesizeSpeechResponse", + "TextToSpeechClient", "Voice", "VoiceSelectionParams", - "TextToSpeechClient", ) diff --git a/google/cloud/texttospeech_v1/gapic_metadata.json b/google/cloud/texttospeech_v1/gapic_metadata.json new file mode 100644 index 00000000..f9c0c9bd --- /dev/null +++ b/google/cloud/texttospeech_v1/gapic_metadata.json @@ -0,0 +1,43 @@ + { + "comment": "This file maps proto services/RPCs to the corresponding library clients/methods", + "language": "python", + "libraryPackage": "google.cloud.texttospeech_v1", + "protoPackage": "google.cloud.texttospeech.v1", + "schema": "1.0", + "services": { + "TextToSpeech": { + "clients": { + "grpc": { + "libraryClient": "TextToSpeechClient", + "rpcs": { + "ListVoices": { + "methods": [ + "list_voices" + ] + }, + "SynthesizeSpeech": { + "methods": [ + "synthesize_speech" + ] + } + } + }, + "grpc-async": { + "libraryClient": "TextToSpeechAsyncClient", + "rpcs": { + "ListVoices": { + "methods": [ + "list_voices" + ] + }, + "SynthesizeSpeech": { + "methods": [ + "synthesize_speech" + ] + } + } + } + } + } + } +} diff --git a/google/cloud/texttospeech_v1/services/__init__.py b/google/cloud/texttospeech_v1/services/__init__.py index 42ffdf2b..4de65971 100644 --- a/google/cloud/texttospeech_v1/services/__init__.py +++ b/google/cloud/texttospeech_v1/services/__init__.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- - # Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/google/cloud/texttospeech_v1/services/text_to_speech/__init__.py b/google/cloud/texttospeech_v1/services/text_to_speech/__init__.py index a63df317..67da2f5b 100644 --- a/google/cloud/texttospeech_v1/services/text_to_speech/__init__.py +++ b/google/cloud/texttospeech_v1/services/text_to_speech/__init__.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- - # Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,7 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. # - from .client import TextToSpeechClient from .async_client import TextToSpeechAsyncClient diff --git a/google/cloud/texttospeech_v1/services/text_to_speech/async_client.py b/google/cloud/texttospeech_v1/services/text_to_speech/async_client.py index 9660609e..b028cabb 100644 --- a/google/cloud/texttospeech_v1/services/text_to_speech/async_client.py +++ b/google/cloud/texttospeech_v1/services/text_to_speech/async_client.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- - # Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,7 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. # - from collections import OrderedDict import functools import re @@ -22,14 +20,13 @@ import pkg_resources import google.api_core.client_options as ClientOptions # type: ignore -from google.api_core import exceptions # type: ignore +from google.api_core import exceptions as core_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 import credentials as ga_credentials # type: ignore from google.oauth2 import service_account # type: ignore from google.cloud.texttospeech_v1.types import cloud_tts - from .transports.base import TextToSpeechTransport, DEFAULT_CLIENT_INFO from .transports.grpc_asyncio import TextToSpeechGrpcAsyncIOTransport from .client import TextToSpeechClient @@ -49,20 +46,16 @@ class TextToSpeechAsyncClient: parse_common_billing_account_path = staticmethod( TextToSpeechClient.parse_common_billing_account_path ) - common_folder_path = staticmethod(TextToSpeechClient.common_folder_path) parse_common_folder_path = staticmethod(TextToSpeechClient.parse_common_folder_path) - common_organization_path = staticmethod(TextToSpeechClient.common_organization_path) parse_common_organization_path = staticmethod( TextToSpeechClient.parse_common_organization_path ) - common_project_path = staticmethod(TextToSpeechClient.common_project_path) parse_common_project_path = staticmethod( TextToSpeechClient.parse_common_project_path ) - common_location_path = staticmethod(TextToSpeechClient.common_location_path) parse_common_location_path = staticmethod( TextToSpeechClient.parse_common_location_path @@ -70,7 +63,8 @@ class TextToSpeechAsyncClient: @classmethod def from_service_account_info(cls, info: dict, *args, **kwargs): - """Creates an instance of this client using the provided credentials info. + """Creates an instance of this client using the provided credentials + info. Args: info (dict): The service account private key info. @@ -85,7 +79,7 @@ def from_service_account_info(cls, info: dict, *args, **kwargs): @classmethod def from_service_account_file(cls, filename: str, *args, **kwargs): """Creates an instance of this client using the provided credentials - file. + file. Args: filename (str): The path to the service account private key json @@ -102,7 +96,7 @@ def from_service_account_file(cls, filename: str, *args, **kwargs): @property def transport(self) -> TextToSpeechTransport: - """Return the transport used by the client instance. + """Returns the transport used by the client instance. Returns: TextToSpeechTransport: The transport used by the client instance. @@ -116,12 +110,12 @@ def transport(self) -> TextToSpeechTransport: def __init__( self, *, - credentials: credentials.Credentials = None, + credentials: ga_credentials.Credentials = None, transport: Union[str, TextToSpeechTransport] = "grpc_asyncio", client_options: ClientOptions = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: - """Instantiate the text to speech client. + """Instantiates the text to speech client. Args: credentials (Optional[google.auth.credentials.Credentials]): The @@ -153,7 +147,6 @@ def __init__( google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport creation failed for any reason. """ - self._client = TextToSpeechClient( credentials=credentials, transport=transport, @@ -191,7 +184,6 @@ async def list_voices( This corresponds to the ``language_code`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - retry (google.api_core.retry.Retry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. @@ -218,7 +210,6 @@ async def list_voices( # If we have keyword arguments corresponding to fields on the # request, apply these. - if language_code is not None: request.language_code = language_code @@ -231,7 +222,8 @@ async def list_voices( maximum=60.0, multiplier=1.3, predicate=retries.if_exception_type( - exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, + core_exceptions.DeadlineExceeded, + core_exceptions.ServiceUnavailable, ), deadline=600.0, ), @@ -284,7 +276,6 @@ async def synthesize_speech( This corresponds to the ``audio_config`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - retry (google.api_core.retry.Retry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. @@ -311,7 +302,6 @@ async def synthesize_speech( # If we have keyword arguments corresponding to fields on the # request, apply these. - if input is not None: request.input = input if voice is not None: @@ -328,7 +318,8 @@ async def synthesize_speech( maximum=60.0, multiplier=1.3, predicate=retries.if_exception_type( - exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, + core_exceptions.DeadlineExceeded, + core_exceptions.ServiceUnavailable, ), deadline=600.0, ), diff --git a/google/cloud/texttospeech_v1/services/text_to_speech/client.py b/google/cloud/texttospeech_v1/services/text_to_speech/client.py index 836ac5a3..11251f4b 100644 --- a/google/cloud/texttospeech_v1/services/text_to_speech/client.py +++ b/google/cloud/texttospeech_v1/services/text_to_speech/client.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- - # Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,7 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. # - from collections import OrderedDict from distutils import util import os @@ -23,17 +21,16 @@ import pkg_resources from google.api_core import client_options as client_options_lib # type: ignore -from google.api_core import exceptions # type: ignore +from google.api_core import exceptions as core_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 import credentials as ga_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.cloud.texttospeech_v1.types import cloud_tts - from .transports.base import TextToSpeechTransport, DEFAULT_CLIENT_INFO from .transports.grpc import TextToSpeechGrpcTransport from .transports.grpc_asyncio import TextToSpeechGrpcAsyncIOTransport @@ -52,7 +49,7 @@ class TextToSpeechClientMeta(type): _transport_registry["grpc_asyncio"] = TextToSpeechGrpcAsyncIOTransport def get_transport_class(cls, label: str = None,) -> Type[TextToSpeechTransport]: - """Return an appropriate transport class. + """Returns an appropriate transport class. Args: label: The name of the desired transport. If none is @@ -75,7 +72,8 @@ class TextToSpeechClient(metaclass=TextToSpeechClientMeta): @staticmethod def _get_default_mtls_endpoint(api_endpoint): - """Convert api endpoint to mTLS endpoint. + """Converts api endpoint to mTLS endpoint. + Convert "*.sandbox.googleapis.com" and "*.googleapis.com" to "*.mtls.sandbox.googleapis.com" and "*.mtls.googleapis.com" respectively. Args: @@ -109,7 +107,8 @@ def _get_default_mtls_endpoint(api_endpoint): @classmethod def from_service_account_info(cls, info: dict, *args, **kwargs): - """Creates an instance of this client using the provided credentials info. + """Creates an instance of this client using the provided credentials + info. Args: info (dict): The service account private key info. @@ -126,7 +125,7 @@ def from_service_account_info(cls, info: dict, *args, **kwargs): @classmethod def from_service_account_file(cls, filename: str, *args, **kwargs): """Creates an instance of this client using the provided credentials - file. + file. Args: filename (str): The path to the service account private key json @@ -145,16 +144,17 @@ def from_service_account_file(cls, filename: str, *args, **kwargs): @property def transport(self) -> TextToSpeechTransport: - """Return the transport used by the client instance. + """Returns the transport used by the client instance. Returns: - TextToSpeechTransport: The transport used by the client instance. + TextToSpeechTransport: The transport used by the client + instance. """ return self._transport @staticmethod def common_billing_account_path(billing_account: str,) -> str: - """Return a fully-qualified billing_account string.""" + """Returns a fully-qualified billing_account string.""" return "billingAccounts/{billing_account}".format( billing_account=billing_account, ) @@ -167,7 +167,7 @@ def parse_common_billing_account_path(path: str) -> Dict[str, str]: @staticmethod def common_folder_path(folder: str,) -> str: - """Return a fully-qualified folder string.""" + """Returns a fully-qualified folder string.""" return "folders/{folder}".format(folder=folder,) @staticmethod @@ -178,7 +178,7 @@ def parse_common_folder_path(path: str) -> Dict[str, str]: @staticmethod def common_organization_path(organization: str,) -> str: - """Return a fully-qualified organization string.""" + """Returns a fully-qualified organization string.""" return "organizations/{organization}".format(organization=organization,) @staticmethod @@ -189,7 +189,7 @@ def parse_common_organization_path(path: str) -> Dict[str, str]: @staticmethod def common_project_path(project: str,) -> str: - """Return a fully-qualified project string.""" + """Returns a fully-qualified project string.""" return "projects/{project}".format(project=project,) @staticmethod @@ -200,7 +200,7 @@ def parse_common_project_path(path: str) -> Dict[str, str]: @staticmethod def common_location_path(project: str, location: str,) -> str: - """Return a fully-qualified location string.""" + """Returns a fully-qualified location string.""" return "projects/{project}/locations/{location}".format( project=project, location=location, ) @@ -214,12 +214,12 @@ def parse_common_location_path(path: str) -> Dict[str, str]: def __init__( self, *, - credentials: Optional[credentials.Credentials] = None, + credentials: Optional[ga_credentials.Credentials] = None, transport: Union[str, TextToSpeechTransport, None] = None, client_options: Optional[client_options_lib.ClientOptions] = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: - """Instantiate the text to speech client. + """Instantiates the text to speech client. Args: credentials (Optional[google.auth.credentials.Credentials]): The @@ -274,9 +274,10 @@ def __init__( client_cert_source_func = client_options.client_cert_source else: is_mtls = mtls.has_default_client_cert_source() - client_cert_source_func = ( - mtls.default_client_cert_source() if is_mtls else None - ) + if is_mtls: + client_cert_source_func = mtls.default_client_cert_source() + else: + client_cert_source_func = None # Figure out which api endpoint to use. if client_options.api_endpoint is not None: @@ -288,12 +289,14 @@ def __init__( elif use_mtls_env == "always": api_endpoint = self.DEFAULT_MTLS_ENDPOINT elif use_mtls_env == "auto": - api_endpoint = ( - self.DEFAULT_MTLS_ENDPOINT if is_mtls else self.DEFAULT_ENDPOINT - ) + if is_mtls: + api_endpoint = self.DEFAULT_MTLS_ENDPOINT + else: + api_endpoint = self.DEFAULT_ENDPOINT else: raise MutualTLSChannelError( - "Unsupported GOOGLE_API_USE_MTLS_ENDPOINT value. Accepted values: never, auto, always" + "Unsupported GOOGLE_API_USE_MTLS_ENDPOINT value. Accepted " + "values: never, auto, always" ) # Save or instantiate the transport. @@ -308,8 +311,8 @@ def __init__( ) if client_options.scopes: raise ValueError( - "When providing a transport instance, " - "provide its scopes directly." + "When providing a transport instance, provide its scopes " + "directly." ) self._transport = transport else: @@ -354,7 +357,6 @@ def list_voices( This corresponds to the ``language_code`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - retry (google.api_core.retry.Retry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. @@ -383,10 +385,8 @@ def list_voices( # there are no flattened fields. if not isinstance(request, cloud_tts.ListVoicesRequest): request = cloud_tts.ListVoicesRequest(request) - # If we have keyword arguments corresponding to fields on the # request, apply these. - if language_code is not None: request.language_code = language_code @@ -439,7 +439,6 @@ def synthesize_speech( This corresponds to the ``audio_config`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - retry (google.api_core.retry.Retry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. @@ -468,10 +467,8 @@ def synthesize_speech( # there are no flattened fields. if not isinstance(request, cloud_tts.SynthesizeSpeechRequest): request = cloud_tts.SynthesizeSpeechRequest(request) - # If we have keyword arguments corresponding to fields on the # request, apply these. - if input is not None: request.input = input if voice is not None: diff --git a/google/cloud/texttospeech_v1/services/text_to_speech/transports/__init__.py b/google/cloud/texttospeech_v1/services/text_to_speech/transports/__init__.py index ce3b91f1..ac87dc04 100644 --- a/google/cloud/texttospeech_v1/services/text_to_speech/transports/__init__.py +++ b/google/cloud/texttospeech_v1/services/text_to_speech/transports/__init__.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- - # Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,7 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. # - from collections import OrderedDict from typing import Dict, Type diff --git a/google/cloud/texttospeech_v1/services/text_to_speech/transports/base.py b/google/cloud/texttospeech_v1/services/text_to_speech/transports/base.py index d152757b..2e776f86 100644 --- a/google/cloud/texttospeech_v1/services/text_to_speech/transports/base.py +++ b/google/cloud/texttospeech_v1/services/text_to_speech/transports/base.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- - # Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,20 +13,20 @@ # See the License for the specific language governing permissions and # limitations under the License. # - import abc -import typing +from typing import Awaitable, Callable, Dict, Optional, Sequence, Union +import packaging.version import pkg_resources -from google import auth # type: ignore -from google.api_core import exceptions # type: ignore +import google.auth # type: ignore +import google.api_core # type: ignore +from google.api_core import exceptions as core_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 import credentials as ga_credentials # type: ignore from google.cloud.texttospeech_v1.types import cloud_tts - try: DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( gapic_version=pkg_resources.get_distribution( @@ -37,27 +36,41 @@ except pkg_resources.DistributionNotFound: DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() +try: + # google.auth.__version__ was added in 1.26.0 + _GOOGLE_AUTH_VERSION = google.auth.__version__ +except AttributeError: + try: # try pkg_resources if it is available + _GOOGLE_AUTH_VERSION = pkg_resources.get_distribution("google-auth").version + except pkg_resources.DistributionNotFound: # pragma: NO COVER + _GOOGLE_AUTH_VERSION = None + +_API_CORE_VERSION = google.api_core.__version__ + class TextToSpeechTransport(abc.ABC): """Abstract transport class for TextToSpeech.""" AUTH_SCOPES = ("https://www.googleapis.com/auth/cloud-platform",) + DEFAULT_HOST: str = "texttospeech.googleapis.com" + def __init__( self, *, - host: str = "texttospeech.googleapis.com", - credentials: credentials.Credentials = None, - credentials_file: typing.Optional[str] = None, - scopes: typing.Optional[typing.Sequence[str]] = AUTH_SCOPES, - quota_project_id: typing.Optional[str] = None, + host: str = DEFAULT_HOST, + credentials: ga_credentials.Credentials = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, **kwargs, ) -> None: """Instantiate the transport. Args: - host (Optional[str]): The hostname to connect to. + host (Optional[str]): + The hostname to connect to. credentials (Optional[google.auth.credentials.Credentials]): The authorization credentials to attach to requests. These credentials identify the application to the service; if none @@ -66,7 +79,7 @@ def __init__( credentials_file (Optional[str]): A file with credentials that can be loaded with :func:`google.auth.load_credentials_from_file`. This argument is mutually exclusive with credentials. - scope (Optional[Sequence[str]]): A list of scopes. + scopes (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): @@ -80,29 +93,76 @@ def __init__( host += ":443" self._host = host + scopes_kwargs = self._get_scopes_kwargs(self._host, scopes) + # Save the scopes. self._scopes = scopes or self.AUTH_SCOPES # If no credentials are provided, then determine the appropriate # defaults. if credentials and credentials_file: - raise exceptions.DuplicateCredentialArgs( + raise core_exceptions.DuplicateCredentialArgs( "'credentials_file' and 'credentials' are mutually exclusive" ) if credentials_file is not None: - credentials, _ = auth.load_credentials_from_file( - credentials_file, scopes=self._scopes, quota_project_id=quota_project_id + credentials, _ = google.auth.load_credentials_from_file( + credentials_file, **scopes_kwargs, quota_project_id=quota_project_id ) elif credentials is None: - credentials, _ = auth.default( - scopes=self._scopes, quota_project_id=quota_project_id + credentials, _ = google.auth.default( + **scopes_kwargs, quota_project_id=quota_project_id ) # Save the credentials. self._credentials = credentials + # TODO(busunkim): These two class methods are in the base transport + # to avoid duplicating code across the transport classes. These functions + # should be deleted once the minimum required versions of google-api-core + # and google-auth are increased. + + # TODO: Remove this function once google-auth >= 1.25.0 is required + @classmethod + def _get_scopes_kwargs( + cls, host: str, scopes: Optional[Sequence[str]] + ) -> Dict[str, Optional[Sequence[str]]]: + """Returns scopes kwargs to pass to google-auth methods depending on the google-auth version""" + + scopes_kwargs = {} + + if _GOOGLE_AUTH_VERSION and ( + packaging.version.parse(_GOOGLE_AUTH_VERSION) + >= packaging.version.parse("1.25.0") + ): + scopes_kwargs = {"scopes": scopes, "default_scopes": cls.AUTH_SCOPES} + else: + scopes_kwargs = {"scopes": scopes or cls.AUTH_SCOPES} + + return scopes_kwargs + + # TODO: Remove this function once google-api-core >= 1.26.0 is required + @classmethod + def _get_self_signed_jwt_kwargs( + cls, host: str, scopes: Optional[Sequence[str]] + ) -> Dict[str, Union[Optional[Sequence[str]], str]]: + """Returns kwargs to pass to grpc_helpers.create_channel depending on the google-api-core version""" + + self_signed_jwt_kwargs: Dict[str, Union[Optional[Sequence[str]], str]] = {} + + if _API_CORE_VERSION and ( + packaging.version.parse(_API_CORE_VERSION) + >= packaging.version.parse("1.26.0") + ): + self_signed_jwt_kwargs["default_scopes"] = cls.AUTH_SCOPES + self_signed_jwt_kwargs["scopes"] = scopes + self_signed_jwt_kwargs["default_host"] = cls.DEFAULT_HOST + else: + self_signed_jwt_kwargs["scopes"] = scopes or cls.AUTH_SCOPES + + return self_signed_jwt_kwargs + def _prep_wrapped_messages(self, client_info): # Precompute the wrapped methods. self._wrapped_methods = { @@ -113,7 +173,8 @@ def _prep_wrapped_messages(self, client_info): maximum=60.0, multiplier=1.3, predicate=retries.if_exception_type( - exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, + core_exceptions.DeadlineExceeded, + core_exceptions.ServiceUnavailable, ), deadline=600.0, ), @@ -127,7 +188,8 @@ def _prep_wrapped_messages(self, client_info): maximum=60.0, multiplier=1.3, predicate=retries.if_exception_type( - exceptions.DeadlineExceeded, exceptions.ServiceUnavailable, + core_exceptions.DeadlineExceeded, + core_exceptions.ServiceUnavailable, ), deadline=600.0, ), @@ -139,22 +201,20 @@ def _prep_wrapped_messages(self, client_info): @property def list_voices( self, - ) -> typing.Callable[ + ) -> Callable[ [cloud_tts.ListVoicesRequest], - typing.Union[ - cloud_tts.ListVoicesResponse, typing.Awaitable[cloud_tts.ListVoicesResponse] - ], + Union[cloud_tts.ListVoicesResponse, Awaitable[cloud_tts.ListVoicesResponse]], ]: raise NotImplementedError() @property def synthesize_speech( self, - ) -> typing.Callable[ + ) -> Callable[ [cloud_tts.SynthesizeSpeechRequest], - typing.Union[ + Union[ cloud_tts.SynthesizeSpeechResponse, - typing.Awaitable[cloud_tts.SynthesizeSpeechResponse], + Awaitable[cloud_tts.SynthesizeSpeechResponse], ], ]: raise NotImplementedError() diff --git a/google/cloud/texttospeech_v1/services/text_to_speech/transports/grpc.py b/google/cloud/texttospeech_v1/services/text_to_speech/transports/grpc.py index 939684e6..97d90bc0 100644 --- a/google/cloud/texttospeech_v1/services/text_to_speech/transports/grpc.py +++ b/google/cloud/texttospeech_v1/services/text_to_speech/transports/grpc.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- - # Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,20 +13,18 @@ # See the License for the specific language governing permissions and # limitations under the License. # - import warnings -from typing import Callable, Dict, Optional, Sequence, Tuple +from typing import Callable, Dict, Optional, Sequence, Tuple, Union from google.api_core import grpc_helpers # type: ignore from google.api_core import gapic_v1 # type: ignore -from google import auth # type: ignore -from google.auth import credentials # type: ignore +import google.auth # type: ignore +from google.auth import credentials as ga_credentials # type: ignore from google.auth.transport.grpc import SslCredentials # type: ignore import grpc # type: ignore from google.cloud.texttospeech_v1.types import cloud_tts - from .base import TextToSpeechTransport, DEFAULT_CLIENT_INFO @@ -50,7 +47,7 @@ def __init__( self, *, host: str = "texttospeech.googleapis.com", - credentials: credentials.Credentials = None, + credentials: ga_credentials.Credentials = None, credentials_file: str = None, scopes: Sequence[str] = None, channel: grpc.Channel = None, @@ -64,7 +61,8 @@ def __init__( """Instantiate the transport. Args: - host (Optional[str]): The hostname to connect to. + host (Optional[str]): + The hostname to connect to. credentials (Optional[google.auth.credentials.Credentials]): The authorization credentials to attach to requests. These credentials identify the application to the service; if none @@ -174,7 +172,7 @@ def __init__( def create_channel( cls, host: str = "texttospeech.googleapis.com", - credentials: credentials.Credentials = None, + credentials: ga_credentials.Credentials = None, credentials_file: str = None, scopes: Optional[Sequence[str]] = None, quota_project_id: Optional[str] = None, @@ -205,13 +203,15 @@ def create_channel( google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` and ``credentials_file`` are passed. """ - scopes = scopes or cls.AUTH_SCOPES + + self_signed_jwt_kwargs = cls._get_self_signed_jwt_kwargs(host, scopes) + return grpc_helpers.create_channel( host, credentials=credentials, credentials_file=credentials_file, - scopes=scopes, quota_project_id=quota_project_id, + **self_signed_jwt_kwargs, **kwargs, ) diff --git a/google/cloud/texttospeech_v1/services/text_to_speech/transports/grpc_asyncio.py b/google/cloud/texttospeech_v1/services/text_to_speech/transports/grpc_asyncio.py index 2a98846e..6bc02b07 100644 --- a/google/cloud/texttospeech_v1/services/text_to_speech/transports/grpc_asyncio.py +++ b/google/cloud/texttospeech_v1/services/text_to_speech/transports/grpc_asyncio.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- - # Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,21 +13,19 @@ # See the License for the specific language governing permissions and # limitations under the License. # - import warnings -from typing import Awaitable, Callable, Dict, Optional, Sequence, Tuple +from typing import Awaitable, Callable, Dict, Optional, Sequence, Tuple, Union from google.api_core import gapic_v1 # type: ignore from google.api_core import grpc_helpers_async # type: ignore -from google import auth # type: ignore -from google.auth import credentials # type: ignore +from google.auth import credentials as ga_credentials # type: ignore from google.auth.transport.grpc import SslCredentials # type: ignore +import packaging.version import grpc # type: ignore from grpc.experimental import aio # type: ignore from google.cloud.texttospeech_v1.types import cloud_tts - from .base import TextToSpeechTransport, DEFAULT_CLIENT_INFO from .grpc import TextToSpeechGrpcTransport @@ -53,7 +50,7 @@ class TextToSpeechGrpcAsyncIOTransport(TextToSpeechTransport): def create_channel( cls, host: str = "texttospeech.googleapis.com", - credentials: credentials.Credentials = None, + credentials: ga_credentials.Credentials = None, credentials_file: Optional[str] = None, scopes: Optional[Sequence[str]] = None, quota_project_id: Optional[str] = None, @@ -80,13 +77,15 @@ def create_channel( Returns: aio.Channel: A gRPC AsyncIO channel object. """ - scopes = scopes or cls.AUTH_SCOPES + + self_signed_jwt_kwargs = cls._get_self_signed_jwt_kwargs(host, scopes) + return grpc_helpers_async.create_channel( host, credentials=credentials, credentials_file=credentials_file, - scopes=scopes, quota_project_id=quota_project_id, + **self_signed_jwt_kwargs, **kwargs, ) @@ -94,7 +93,7 @@ def __init__( self, *, host: str = "texttospeech.googleapis.com", - credentials: credentials.Credentials = None, + credentials: ga_credentials.Credentials = None, credentials_file: Optional[str] = None, scopes: Optional[Sequence[str]] = None, channel: aio.Channel = None, @@ -108,7 +107,8 @@ def __init__( """Instantiate the transport. Args: - host (Optional[str]): The hostname to connect to. + host (Optional[str]): + The hostname to connect to. credentials (Optional[google.auth.credentials.Credentials]): The authorization credentials to attach to requests. These credentials identify the application to the service; if none @@ -166,7 +166,6 @@ def __init__( # If a channel was explicitly provided, set it. self._grpc_channel = channel self._ssl_channel_credentials = None - else: if api_mtls_endpoint: host = api_mtls_endpoint diff --git a/google/cloud/texttospeech_v1/types/__init__.py b/google/cloud/texttospeech_v1/types/__init__.py index d6e4a7af..ca42c1df 100644 --- a/google/cloud/texttospeech_v1/types/__init__.py +++ b/google/cloud/texttospeech_v1/types/__init__.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- - # Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,7 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. # - from .cloud_tts import ( AudioConfig, ListVoicesRequest, diff --git a/google/cloud/texttospeech_v1/types/cloud_tts.py b/google/cloud/texttospeech_v1/types/cloud_tts.py index c20d55df..0af98da4 100644 --- a/google/cloud/texttospeech_v1/types/cloud_tts.py +++ b/google/cloud/texttospeech_v1/types/cloud_tts.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- - # Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,7 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. # - import proto # type: ignore @@ -73,12 +71,11 @@ class ListVoicesRequest(proto.Message): voices. """ - language_code = proto.Field(proto.STRING, number=1) + language_code = proto.Field(proto.STRING, number=1,) class ListVoicesResponse(proto.Message): r"""The message returned to the client by the ``ListVoices`` method. - Attributes: voices (Sequence[google.cloud.texttospeech_v1.types.Voice]): The list of voices. @@ -89,7 +86,6 @@ class ListVoicesResponse(proto.Message): class Voice(proto.Message): r"""Description of a voice supported by the TTS service. - Attributes: language_codes (Sequence[str]): The languages that this voice supports, expressed as @@ -105,13 +101,10 @@ class Voice(proto.Message): voice. """ - language_codes = proto.RepeatedField(proto.STRING, number=1) - - name = proto.Field(proto.STRING, number=2) - + language_codes = proto.RepeatedField(proto.STRING, number=1,) + name = proto.Field(proto.STRING, number=2,) ssml_gender = proto.Field(proto.ENUM, number=3, enum="SsmlVoiceGender",) - - natural_sample_rate_hertz = proto.Field(proto.INT32, number=4) + natural_sample_rate_hertz = proto.Field(proto.INT32, number=4,) class SynthesizeSpeechRequest(proto.Message): @@ -131,9 +124,7 @@ class SynthesizeSpeechRequest(proto.Message): """ input = proto.Field(proto.MESSAGE, number=1, message="SynthesisInput",) - voice = proto.Field(proto.MESSAGE, number=2, message="VoiceSelectionParams",) - audio_config = proto.Field(proto.MESSAGE, number=3, message="AudioConfig",) @@ -154,14 +145,12 @@ class SynthesisInput(proto.Message): `SSML `__. """ - text = proto.Field(proto.STRING, number=1, oneof="input_source") - - ssml = proto.Field(proto.STRING, number=2, oneof="input_source") + text = proto.Field(proto.STRING, number=1, oneof="input_source",) + ssml = proto.Field(proto.STRING, number=2, oneof="input_source",) class VoiceSelectionParams(proto.Message): r"""Description of which voice to use for a synthesis request. - Attributes: language_code (str): Required. The language (and potentially also the region) of @@ -191,16 +180,13 @@ class VoiceSelectionParams(proto.Message): different gender rather than failing the request. """ - language_code = proto.Field(proto.STRING, number=1) - - name = proto.Field(proto.STRING, number=2) - + language_code = proto.Field(proto.STRING, number=1,) + name = proto.Field(proto.STRING, number=2,) ssml_gender = proto.Field(proto.ENUM, number=3, enum="SsmlVoiceGender",) class AudioConfig(proto.Message): r"""Description of audio data to be synthesized. - Attributes: audio_encoding (google.cloud.texttospeech_v1.types.AudioEncoding): Required. The format of the audio byte @@ -246,16 +232,11 @@ class AudioConfig(proto.Message): """ audio_encoding = proto.Field(proto.ENUM, number=1, enum="AudioEncoding",) - - speaking_rate = proto.Field(proto.DOUBLE, number=2) - - pitch = proto.Field(proto.DOUBLE, number=3) - - volume_gain_db = proto.Field(proto.DOUBLE, number=4) - - sample_rate_hertz = proto.Field(proto.INT32, number=5) - - effects_profile_id = proto.RepeatedField(proto.STRING, number=6) + speaking_rate = proto.Field(proto.DOUBLE, number=2,) + pitch = proto.Field(proto.DOUBLE, number=3,) + volume_gain_db = proto.Field(proto.DOUBLE, number=4,) + sample_rate_hertz = proto.Field(proto.INT32, number=5,) + effects_profile_id = proto.RepeatedField(proto.STRING, number=6,) class SynthesizeSpeechResponse(proto.Message): @@ -272,7 +253,7 @@ class SynthesizeSpeechResponse(proto.Message): representations use base64. """ - audio_content = proto.Field(proto.BYTES, number=1) + audio_content = proto.Field(proto.BYTES, number=1,) __all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/google/cloud/texttospeech_v1beta1/__init__.py b/google/cloud/texttospeech_v1beta1/__init__.py index f27e5613..db38ed31 100644 --- a/google/cloud/texttospeech_v1beta1/__init__.py +++ b/google/cloud/texttospeech_v1beta1/__init__.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- - # Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,20 +15,22 @@ # from .services.text_to_speech import TextToSpeechClient +from .services.text_to_speech import TextToSpeechAsyncClient + from .types.cloud_tts import AudioConfig -from .types.cloud_tts import AudioEncoding from .types.cloud_tts import ListVoicesRequest from .types.cloud_tts import ListVoicesResponse -from .types.cloud_tts import SsmlVoiceGender from .types.cloud_tts import SynthesisInput from .types.cloud_tts import SynthesizeSpeechRequest from .types.cloud_tts import SynthesizeSpeechResponse from .types.cloud_tts import Timepoint from .types.cloud_tts import Voice from .types.cloud_tts import VoiceSelectionParams - +from .types.cloud_tts import AudioEncoding +from .types.cloud_tts import SsmlVoiceGender __all__ = ( + "TextToSpeechAsyncClient", "AudioConfig", "AudioEncoding", "ListVoicesRequest", @@ -38,8 +39,8 @@ "SynthesisInput", "SynthesizeSpeechRequest", "SynthesizeSpeechResponse", + "TextToSpeechClient", "Timepoint", "Voice", "VoiceSelectionParams", - "TextToSpeechClient", ) diff --git a/google/cloud/texttospeech_v1beta1/gapic_metadata.json b/google/cloud/texttospeech_v1beta1/gapic_metadata.json new file mode 100644 index 00000000..2a31677f --- /dev/null +++ b/google/cloud/texttospeech_v1beta1/gapic_metadata.json @@ -0,0 +1,43 @@ + { + "comment": "This file maps proto services/RPCs to the corresponding library clients/methods", + "language": "python", + "libraryPackage": "google.cloud.texttospeech_v1beta1", + "protoPackage": "google.cloud.texttospeech.v1beta1", + "schema": "1.0", + "services": { + "TextToSpeech": { + "clients": { + "grpc": { + "libraryClient": "TextToSpeechClient", + "rpcs": { + "ListVoices": { + "methods": [ + "list_voices" + ] + }, + "SynthesizeSpeech": { + "methods": [ + "synthesize_speech" + ] + } + } + }, + "grpc-async": { + "libraryClient": "TextToSpeechAsyncClient", + "rpcs": { + "ListVoices": { + "methods": [ + "list_voices" + ] + }, + "SynthesizeSpeech": { + "methods": [ + "synthesize_speech" + ] + } + } + } + } + } + } +} diff --git a/google/cloud/texttospeech_v1beta1/services/__init__.py b/google/cloud/texttospeech_v1beta1/services/__init__.py index 42ffdf2b..4de65971 100644 --- a/google/cloud/texttospeech_v1beta1/services/__init__.py +++ b/google/cloud/texttospeech_v1beta1/services/__init__.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- - # Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/google/cloud/texttospeech_v1beta1/services/text_to_speech/__init__.py b/google/cloud/texttospeech_v1beta1/services/text_to_speech/__init__.py index a63df317..67da2f5b 100644 --- a/google/cloud/texttospeech_v1beta1/services/text_to_speech/__init__.py +++ b/google/cloud/texttospeech_v1beta1/services/text_to_speech/__init__.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- - # Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,7 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. # - from .client import TextToSpeechClient from .async_client import TextToSpeechAsyncClient diff --git a/google/cloud/texttospeech_v1beta1/services/text_to_speech/async_client.py b/google/cloud/texttospeech_v1beta1/services/text_to_speech/async_client.py index d2c2cd90..94338d6a 100644 --- a/google/cloud/texttospeech_v1beta1/services/text_to_speech/async_client.py +++ b/google/cloud/texttospeech_v1beta1/services/text_to_speech/async_client.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- - # Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,7 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. # - from collections import OrderedDict import functools import re @@ -22,14 +20,13 @@ import pkg_resources import google.api_core.client_options as ClientOptions # type: ignore -from google.api_core import exceptions # type: ignore +from google.api_core import exceptions as core_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 import credentials as ga_credentials # type: ignore from google.oauth2 import service_account # type: ignore from google.cloud.texttospeech_v1beta1.types import cloud_tts - from .transports.base import TextToSpeechTransport, DEFAULT_CLIENT_INFO from .transports.grpc_asyncio import TextToSpeechGrpcAsyncIOTransport from .client import TextToSpeechClient @@ -49,20 +46,16 @@ class TextToSpeechAsyncClient: parse_common_billing_account_path = staticmethod( TextToSpeechClient.parse_common_billing_account_path ) - common_folder_path = staticmethod(TextToSpeechClient.common_folder_path) parse_common_folder_path = staticmethod(TextToSpeechClient.parse_common_folder_path) - common_organization_path = staticmethod(TextToSpeechClient.common_organization_path) parse_common_organization_path = staticmethod( TextToSpeechClient.parse_common_organization_path ) - common_project_path = staticmethod(TextToSpeechClient.common_project_path) parse_common_project_path = staticmethod( TextToSpeechClient.parse_common_project_path ) - common_location_path = staticmethod(TextToSpeechClient.common_location_path) parse_common_location_path = staticmethod( TextToSpeechClient.parse_common_location_path @@ -70,7 +63,8 @@ class TextToSpeechAsyncClient: @classmethod def from_service_account_info(cls, info: dict, *args, **kwargs): - """Creates an instance of this client using the provided credentials info. + """Creates an instance of this client using the provided credentials + info. Args: info (dict): The service account private key info. @@ -85,7 +79,7 @@ def from_service_account_info(cls, info: dict, *args, **kwargs): @classmethod def from_service_account_file(cls, filename: str, *args, **kwargs): """Creates an instance of this client using the provided credentials - file. + file. Args: filename (str): The path to the service account private key json @@ -102,7 +96,7 @@ def from_service_account_file(cls, filename: str, *args, **kwargs): @property def transport(self) -> TextToSpeechTransport: - """Return the transport used by the client instance. + """Returns the transport used by the client instance. Returns: TextToSpeechTransport: The transport used by the client instance. @@ -116,12 +110,12 @@ def transport(self) -> TextToSpeechTransport: def __init__( self, *, - credentials: credentials.Credentials = None, + credentials: ga_credentials.Credentials = None, transport: Union[str, TextToSpeechTransport] = "grpc_asyncio", client_options: ClientOptions = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: - """Instantiate the text to speech client. + """Instantiates the text to speech client. Args: credentials (Optional[google.auth.credentials.Credentials]): The @@ -153,7 +147,6 @@ def __init__( google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport creation failed for any reason. """ - self._client = TextToSpeechClient( credentials=credentials, transport=transport, @@ -192,7 +185,6 @@ async def list_voices( This corresponds to the ``language_code`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - retry (google.api_core.retry.Retry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. @@ -219,7 +211,6 @@ async def list_voices( # If we have keyword arguments corresponding to fields on the # request, apply these. - if language_code is not None: request.language_code = language_code @@ -276,7 +267,6 @@ async def synthesize_speech( This corresponds to the ``audio_config`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - retry (google.api_core.retry.Retry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. @@ -303,7 +293,6 @@ async def synthesize_speech( # If we have keyword arguments corresponding to fields on the # request, apply these. - if input is not None: request.input = input if voice is not None: diff --git a/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py b/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py index 3942dfcf..881508f8 100644 --- a/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py +++ b/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- - # Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,7 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. # - from collections import OrderedDict from distutils import util import os @@ -23,17 +21,16 @@ import pkg_resources from google.api_core import client_options as client_options_lib # type: ignore -from google.api_core import exceptions # type: ignore +from google.api_core import exceptions as core_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 import credentials as ga_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.cloud.texttospeech_v1beta1.types import cloud_tts - from .transports.base import TextToSpeechTransport, DEFAULT_CLIENT_INFO from .transports.grpc import TextToSpeechGrpcTransport from .transports.grpc_asyncio import TextToSpeechGrpcAsyncIOTransport @@ -52,7 +49,7 @@ class TextToSpeechClientMeta(type): _transport_registry["grpc_asyncio"] = TextToSpeechGrpcAsyncIOTransport def get_transport_class(cls, label: str = None,) -> Type[TextToSpeechTransport]: - """Return an appropriate transport class. + """Returns an appropriate transport class. Args: label: The name of the desired transport. If none is @@ -75,7 +72,8 @@ class TextToSpeechClient(metaclass=TextToSpeechClientMeta): @staticmethod def _get_default_mtls_endpoint(api_endpoint): - """Convert api endpoint to mTLS endpoint. + """Converts api endpoint to mTLS endpoint. + Convert "*.sandbox.googleapis.com" and "*.googleapis.com" to "*.mtls.sandbox.googleapis.com" and "*.mtls.googleapis.com" respectively. Args: @@ -109,7 +107,8 @@ def _get_default_mtls_endpoint(api_endpoint): @classmethod def from_service_account_info(cls, info: dict, *args, **kwargs): - """Creates an instance of this client using the provided credentials info. + """Creates an instance of this client using the provided credentials + info. Args: info (dict): The service account private key info. @@ -126,7 +125,7 @@ def from_service_account_info(cls, info: dict, *args, **kwargs): @classmethod def from_service_account_file(cls, filename: str, *args, **kwargs): """Creates an instance of this client using the provided credentials - file. + file. Args: filename (str): The path to the service account private key json @@ -145,16 +144,17 @@ def from_service_account_file(cls, filename: str, *args, **kwargs): @property def transport(self) -> TextToSpeechTransport: - """Return the transport used by the client instance. + """Returns the transport used by the client instance. Returns: - TextToSpeechTransport: The transport used by the client instance. + TextToSpeechTransport: The transport used by the client + instance. """ return self._transport @staticmethod def common_billing_account_path(billing_account: str,) -> str: - """Return a fully-qualified billing_account string.""" + """Returns a fully-qualified billing_account string.""" return "billingAccounts/{billing_account}".format( billing_account=billing_account, ) @@ -167,7 +167,7 @@ def parse_common_billing_account_path(path: str) -> Dict[str, str]: @staticmethod def common_folder_path(folder: str,) -> str: - """Return a fully-qualified folder string.""" + """Returns a fully-qualified folder string.""" return "folders/{folder}".format(folder=folder,) @staticmethod @@ -178,7 +178,7 @@ def parse_common_folder_path(path: str) -> Dict[str, str]: @staticmethod def common_organization_path(organization: str,) -> str: - """Return a fully-qualified organization string.""" + """Returns a fully-qualified organization string.""" return "organizations/{organization}".format(organization=organization,) @staticmethod @@ -189,7 +189,7 @@ def parse_common_organization_path(path: str) -> Dict[str, str]: @staticmethod def common_project_path(project: str,) -> str: - """Return a fully-qualified project string.""" + """Returns a fully-qualified project string.""" return "projects/{project}".format(project=project,) @staticmethod @@ -200,7 +200,7 @@ def parse_common_project_path(path: str) -> Dict[str, str]: @staticmethod def common_location_path(project: str, location: str,) -> str: - """Return a fully-qualified location string.""" + """Returns a fully-qualified location string.""" return "projects/{project}/locations/{location}".format( project=project, location=location, ) @@ -214,12 +214,12 @@ def parse_common_location_path(path: str) -> Dict[str, str]: def __init__( self, *, - credentials: Optional[credentials.Credentials] = None, + credentials: Optional[ga_credentials.Credentials] = None, transport: Union[str, TextToSpeechTransport, None] = None, client_options: Optional[client_options_lib.ClientOptions] = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: - """Instantiate the text to speech client. + """Instantiates the text to speech client. Args: credentials (Optional[google.auth.credentials.Credentials]): The @@ -274,9 +274,10 @@ def __init__( client_cert_source_func = client_options.client_cert_source else: is_mtls = mtls.has_default_client_cert_source() - client_cert_source_func = ( - mtls.default_client_cert_source() if is_mtls else None - ) + if is_mtls: + client_cert_source_func = mtls.default_client_cert_source() + else: + client_cert_source_func = None # Figure out which api endpoint to use. if client_options.api_endpoint is not None: @@ -288,12 +289,14 @@ def __init__( elif use_mtls_env == "always": api_endpoint = self.DEFAULT_MTLS_ENDPOINT elif use_mtls_env == "auto": - api_endpoint = ( - self.DEFAULT_MTLS_ENDPOINT if is_mtls else self.DEFAULT_ENDPOINT - ) + if is_mtls: + api_endpoint = self.DEFAULT_MTLS_ENDPOINT + else: + api_endpoint = self.DEFAULT_ENDPOINT else: raise MutualTLSChannelError( - "Unsupported GOOGLE_API_USE_MTLS_ENDPOINT value. Accepted values: never, auto, always" + "Unsupported GOOGLE_API_USE_MTLS_ENDPOINT value. Accepted " + "values: never, auto, always" ) # Save or instantiate the transport. @@ -308,8 +311,8 @@ def __init__( ) if client_options.scopes: raise ValueError( - "When providing a transport instance, " - "provide its scopes directly." + "When providing a transport instance, provide its scopes " + "directly." ) self._transport = transport else: @@ -355,7 +358,6 @@ def list_voices( This corresponds to the ``language_code`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - retry (google.api_core.retry.Retry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. @@ -384,10 +386,8 @@ def list_voices( # there are no flattened fields. if not isinstance(request, cloud_tts.ListVoicesRequest): request = cloud_tts.ListVoicesRequest(request) - # If we have keyword arguments corresponding to fields on the # request, apply these. - if language_code is not None: request.language_code = language_code @@ -440,7 +440,6 @@ def synthesize_speech( This corresponds to the ``audio_config`` field on the ``request`` instance; if ``request`` is provided, this should not be set. - retry (google.api_core.retry.Retry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. @@ -469,10 +468,8 @@ def synthesize_speech( # there are no flattened fields. if not isinstance(request, cloud_tts.SynthesizeSpeechRequest): request = cloud_tts.SynthesizeSpeechRequest(request) - # If we have keyword arguments corresponding to fields on the # request, apply these. - if input is not None: request.input = input if voice is not None: diff --git a/google/cloud/texttospeech_v1beta1/services/text_to_speech/transports/__init__.py b/google/cloud/texttospeech_v1beta1/services/text_to_speech/transports/__init__.py index ce3b91f1..ac87dc04 100644 --- a/google/cloud/texttospeech_v1beta1/services/text_to_speech/transports/__init__.py +++ b/google/cloud/texttospeech_v1beta1/services/text_to_speech/transports/__init__.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- - # Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,7 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. # - from collections import OrderedDict from typing import Dict, Type diff --git a/google/cloud/texttospeech_v1beta1/services/text_to_speech/transports/base.py b/google/cloud/texttospeech_v1beta1/services/text_to_speech/transports/base.py index caaad3bf..39d277e2 100644 --- a/google/cloud/texttospeech_v1beta1/services/text_to_speech/transports/base.py +++ b/google/cloud/texttospeech_v1beta1/services/text_to_speech/transports/base.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- - # Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,20 +13,20 @@ # See the License for the specific language governing permissions and # limitations under the License. # - import abc -import typing +from typing import Awaitable, Callable, Dict, Optional, Sequence, Union +import packaging.version import pkg_resources -from google import auth # type: ignore -from google.api_core import exceptions # type: ignore +import google.auth # type: ignore +import google.api_core # type: ignore +from google.api_core import exceptions as core_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 import credentials as ga_credentials # type: ignore from google.cloud.texttospeech_v1beta1.types import cloud_tts - try: DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( gapic_version=pkg_resources.get_distribution( @@ -37,27 +36,41 @@ except pkg_resources.DistributionNotFound: DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() +try: + # google.auth.__version__ was added in 1.26.0 + _GOOGLE_AUTH_VERSION = google.auth.__version__ +except AttributeError: + try: # try pkg_resources if it is available + _GOOGLE_AUTH_VERSION = pkg_resources.get_distribution("google-auth").version + except pkg_resources.DistributionNotFound: # pragma: NO COVER + _GOOGLE_AUTH_VERSION = None + +_API_CORE_VERSION = google.api_core.__version__ + class TextToSpeechTransport(abc.ABC): """Abstract transport class for TextToSpeech.""" AUTH_SCOPES = ("https://www.googleapis.com/auth/cloud-platform",) + DEFAULT_HOST: str = "texttospeech.googleapis.com" + def __init__( self, *, - host: str = "texttospeech.googleapis.com", - credentials: credentials.Credentials = None, - credentials_file: typing.Optional[str] = None, - scopes: typing.Optional[typing.Sequence[str]] = AUTH_SCOPES, - quota_project_id: typing.Optional[str] = None, + host: str = DEFAULT_HOST, + credentials: ga_credentials.Credentials = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, **kwargs, ) -> None: """Instantiate the transport. Args: - host (Optional[str]): The hostname to connect to. + host (Optional[str]): + The hostname to connect to. credentials (Optional[google.auth.credentials.Credentials]): The authorization credentials to attach to requests. These credentials identify the application to the service; if none @@ -66,7 +79,7 @@ def __init__( credentials_file (Optional[str]): A file with credentials that can be loaded with :func:`google.auth.load_credentials_from_file`. This argument is mutually exclusive with credentials. - scope (Optional[Sequence[str]]): A list of scopes. + scopes (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): @@ -80,29 +93,76 @@ def __init__( host += ":443" self._host = host + scopes_kwargs = self._get_scopes_kwargs(self._host, scopes) + # Save the scopes. self._scopes = scopes or self.AUTH_SCOPES # If no credentials are provided, then determine the appropriate # defaults. if credentials and credentials_file: - raise exceptions.DuplicateCredentialArgs( + raise core_exceptions.DuplicateCredentialArgs( "'credentials_file' and 'credentials' are mutually exclusive" ) if credentials_file is not None: - credentials, _ = auth.load_credentials_from_file( - credentials_file, scopes=self._scopes, quota_project_id=quota_project_id + credentials, _ = google.auth.load_credentials_from_file( + credentials_file, **scopes_kwargs, quota_project_id=quota_project_id ) elif credentials is None: - credentials, _ = auth.default( - scopes=self._scopes, quota_project_id=quota_project_id + credentials, _ = google.auth.default( + **scopes_kwargs, quota_project_id=quota_project_id ) # Save the credentials. self._credentials = credentials + # TODO(busunkim): These two class methods are in the base transport + # to avoid duplicating code across the transport classes. These functions + # should be deleted once the minimum required versions of google-api-core + # and google-auth are increased. + + # TODO: Remove this function once google-auth >= 1.25.0 is required + @classmethod + def _get_scopes_kwargs( + cls, host: str, scopes: Optional[Sequence[str]] + ) -> Dict[str, Optional[Sequence[str]]]: + """Returns scopes kwargs to pass to google-auth methods depending on the google-auth version""" + + scopes_kwargs = {} + + if _GOOGLE_AUTH_VERSION and ( + packaging.version.parse(_GOOGLE_AUTH_VERSION) + >= packaging.version.parse("1.25.0") + ): + scopes_kwargs = {"scopes": scopes, "default_scopes": cls.AUTH_SCOPES} + else: + scopes_kwargs = {"scopes": scopes or cls.AUTH_SCOPES} + + return scopes_kwargs + + # TODO: Remove this function once google-api-core >= 1.26.0 is required + @classmethod + def _get_self_signed_jwt_kwargs( + cls, host: str, scopes: Optional[Sequence[str]] + ) -> Dict[str, Union[Optional[Sequence[str]], str]]: + """Returns kwargs to pass to grpc_helpers.create_channel depending on the google-api-core version""" + + self_signed_jwt_kwargs: Dict[str, Union[Optional[Sequence[str]], str]] = {} + + if _API_CORE_VERSION and ( + packaging.version.parse(_API_CORE_VERSION) + >= packaging.version.parse("1.26.0") + ): + self_signed_jwt_kwargs["default_scopes"] = cls.AUTH_SCOPES + self_signed_jwt_kwargs["scopes"] = scopes + self_signed_jwt_kwargs["default_host"] = cls.DEFAULT_HOST + else: + self_signed_jwt_kwargs["scopes"] = scopes or cls.AUTH_SCOPES + + return self_signed_jwt_kwargs + def _prep_wrapped_messages(self, client_info): # Precompute the wrapped methods. self._wrapped_methods = { @@ -117,22 +177,20 @@ def _prep_wrapped_messages(self, client_info): @property def list_voices( self, - ) -> typing.Callable[ + ) -> Callable[ [cloud_tts.ListVoicesRequest], - typing.Union[ - cloud_tts.ListVoicesResponse, typing.Awaitable[cloud_tts.ListVoicesResponse] - ], + Union[cloud_tts.ListVoicesResponse, Awaitable[cloud_tts.ListVoicesResponse]], ]: raise NotImplementedError() @property def synthesize_speech( self, - ) -> typing.Callable[ + ) -> Callable[ [cloud_tts.SynthesizeSpeechRequest], - typing.Union[ + Union[ cloud_tts.SynthesizeSpeechResponse, - typing.Awaitable[cloud_tts.SynthesizeSpeechResponse], + Awaitable[cloud_tts.SynthesizeSpeechResponse], ], ]: raise NotImplementedError() diff --git a/google/cloud/texttospeech_v1beta1/services/text_to_speech/transports/grpc.py b/google/cloud/texttospeech_v1beta1/services/text_to_speech/transports/grpc.py index fb5c34fb..768d50fb 100644 --- a/google/cloud/texttospeech_v1beta1/services/text_to_speech/transports/grpc.py +++ b/google/cloud/texttospeech_v1beta1/services/text_to_speech/transports/grpc.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- - # Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,20 +13,18 @@ # See the License for the specific language governing permissions and # limitations under the License. # - import warnings -from typing import Callable, Dict, Optional, Sequence, Tuple +from typing import Callable, Dict, Optional, Sequence, Tuple, Union from google.api_core import grpc_helpers # type: ignore from google.api_core import gapic_v1 # type: ignore -from google import auth # type: ignore -from google.auth import credentials # type: ignore +import google.auth # type: ignore +from google.auth import credentials as ga_credentials # type: ignore from google.auth.transport.grpc import SslCredentials # type: ignore import grpc # type: ignore from google.cloud.texttospeech_v1beta1.types import cloud_tts - from .base import TextToSpeechTransport, DEFAULT_CLIENT_INFO @@ -50,7 +47,7 @@ def __init__( self, *, host: str = "texttospeech.googleapis.com", - credentials: credentials.Credentials = None, + credentials: ga_credentials.Credentials = None, credentials_file: str = None, scopes: Sequence[str] = None, channel: grpc.Channel = None, @@ -64,7 +61,8 @@ def __init__( """Instantiate the transport. Args: - host (Optional[str]): The hostname to connect to. + host (Optional[str]): + The hostname to connect to. credentials (Optional[google.auth.credentials.Credentials]): The authorization credentials to attach to requests. These credentials identify the application to the service; if none @@ -174,7 +172,7 @@ def __init__( def create_channel( cls, host: str = "texttospeech.googleapis.com", - credentials: credentials.Credentials = None, + credentials: ga_credentials.Credentials = None, credentials_file: str = None, scopes: Optional[Sequence[str]] = None, quota_project_id: Optional[str] = None, @@ -205,13 +203,15 @@ def create_channel( google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` and ``credentials_file`` are passed. """ - scopes = scopes or cls.AUTH_SCOPES + + self_signed_jwt_kwargs = cls._get_self_signed_jwt_kwargs(host, scopes) + return grpc_helpers.create_channel( host, credentials=credentials, credentials_file=credentials_file, - scopes=scopes, quota_project_id=quota_project_id, + **self_signed_jwt_kwargs, **kwargs, ) diff --git a/google/cloud/texttospeech_v1beta1/services/text_to_speech/transports/grpc_asyncio.py b/google/cloud/texttospeech_v1beta1/services/text_to_speech/transports/grpc_asyncio.py index 05b48c8e..bcd5ad17 100644 --- a/google/cloud/texttospeech_v1beta1/services/text_to_speech/transports/grpc_asyncio.py +++ b/google/cloud/texttospeech_v1beta1/services/text_to_speech/transports/grpc_asyncio.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- - # Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,21 +13,19 @@ # See the License for the specific language governing permissions and # limitations under the License. # - import warnings -from typing import Awaitable, Callable, Dict, Optional, Sequence, Tuple +from typing import Awaitable, Callable, Dict, Optional, Sequence, Tuple, Union from google.api_core import gapic_v1 # type: ignore from google.api_core import grpc_helpers_async # type: ignore -from google import auth # type: ignore -from google.auth import credentials # type: ignore +from google.auth import credentials as ga_credentials # type: ignore from google.auth.transport.grpc import SslCredentials # type: ignore +import packaging.version import grpc # type: ignore from grpc.experimental import aio # type: ignore from google.cloud.texttospeech_v1beta1.types import cloud_tts - from .base import TextToSpeechTransport, DEFAULT_CLIENT_INFO from .grpc import TextToSpeechGrpcTransport @@ -53,7 +50,7 @@ class TextToSpeechGrpcAsyncIOTransport(TextToSpeechTransport): def create_channel( cls, host: str = "texttospeech.googleapis.com", - credentials: credentials.Credentials = None, + credentials: ga_credentials.Credentials = None, credentials_file: Optional[str] = None, scopes: Optional[Sequence[str]] = None, quota_project_id: Optional[str] = None, @@ -80,13 +77,15 @@ def create_channel( Returns: aio.Channel: A gRPC AsyncIO channel object. """ - scopes = scopes or cls.AUTH_SCOPES + + self_signed_jwt_kwargs = cls._get_self_signed_jwt_kwargs(host, scopes) + return grpc_helpers_async.create_channel( host, credentials=credentials, credentials_file=credentials_file, - scopes=scopes, quota_project_id=quota_project_id, + **self_signed_jwt_kwargs, **kwargs, ) @@ -94,7 +93,7 @@ def __init__( self, *, host: str = "texttospeech.googleapis.com", - credentials: credentials.Credentials = None, + credentials: ga_credentials.Credentials = None, credentials_file: Optional[str] = None, scopes: Optional[Sequence[str]] = None, channel: aio.Channel = None, @@ -108,7 +107,8 @@ def __init__( """Instantiate the transport. Args: - host (Optional[str]): The hostname to connect to. + host (Optional[str]): + The hostname to connect to. credentials (Optional[google.auth.credentials.Credentials]): The authorization credentials to attach to requests. These credentials identify the application to the service; if none @@ -166,7 +166,6 @@ def __init__( # If a channel was explicitly provided, set it. self._grpc_channel = channel self._ssl_channel_credentials = None - else: if api_mtls_endpoint: host = api_mtls_endpoint diff --git a/google/cloud/texttospeech_v1beta1/types/__init__.py b/google/cloud/texttospeech_v1beta1/types/__init__.py index bbb6eb00..34bfb0ec 100644 --- a/google/cloud/texttospeech_v1beta1/types/__init__.py +++ b/google/cloud/texttospeech_v1beta1/types/__init__.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- - # Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,7 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. # - from .cloud_tts import ( AudioConfig, ListVoicesRequest, diff --git a/google/cloud/texttospeech_v1beta1/types/cloud_tts.py b/google/cloud/texttospeech_v1beta1/types/cloud_tts.py index c49de4a4..2ce70c32 100644 --- a/google/cloud/texttospeech_v1beta1/types/cloud_tts.py +++ b/google/cloud/texttospeech_v1beta1/types/cloud_tts.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- - # Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,7 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. # - import proto # type: ignore @@ -78,12 +76,11 @@ class ListVoicesRequest(proto.Message): voices. """ - language_code = proto.Field(proto.STRING, number=1) + language_code = proto.Field(proto.STRING, number=1,) class ListVoicesResponse(proto.Message): r"""The message returned to the client by the ``ListVoices`` method. - Attributes: voices (Sequence[google.cloud.texttospeech_v1beta1.types.Voice]): The list of voices. @@ -94,7 +91,6 @@ class ListVoicesResponse(proto.Message): class Voice(proto.Message): r"""Description of a voice supported by the TTS service. - Attributes: language_codes (Sequence[str]): The languages that this voice supports, expressed as @@ -110,13 +106,10 @@ class Voice(proto.Message): voice. """ - language_codes = proto.RepeatedField(proto.STRING, number=1) - - name = proto.Field(proto.STRING, number=2) - + language_codes = proto.RepeatedField(proto.STRING, number=1,) + name = proto.Field(proto.STRING, number=2,) ssml_gender = proto.Field(proto.ENUM, number=3, enum="SsmlVoiceGender",) - - natural_sample_rate_hertz = proto.Field(proto.INT32, number=4) + natural_sample_rate_hertz = proto.Field(proto.INT32, number=4,) class SynthesizeSpeechRequest(proto.Message): @@ -146,11 +139,8 @@ class TimepointType(proto.Enum): SSML_MARK = 1 input = proto.Field(proto.MESSAGE, number=1, message="SynthesisInput",) - voice = proto.Field(proto.MESSAGE, number=2, message="VoiceSelectionParams",) - audio_config = proto.Field(proto.MESSAGE, number=3, message="AudioConfig",) - enable_time_pointing = proto.RepeatedField( proto.ENUM, number=4, enum=TimepointType, ) @@ -173,14 +163,12 @@ class SynthesisInput(proto.Message): `SSML `__. """ - text = proto.Field(proto.STRING, number=1, oneof="input_source") - - ssml = proto.Field(proto.STRING, number=2, oneof="input_source") + text = proto.Field(proto.STRING, number=1, oneof="input_source",) + ssml = proto.Field(proto.STRING, number=2, oneof="input_source",) class VoiceSelectionParams(proto.Message): r"""Description of which voice to use for a synthesis request. - Attributes: language_code (str): Required. The language (and potentially also the region) of @@ -210,16 +198,13 @@ class VoiceSelectionParams(proto.Message): different gender rather than failing the request. """ - language_code = proto.Field(proto.STRING, number=1) - - name = proto.Field(proto.STRING, number=2) - + language_code = proto.Field(proto.STRING, number=1,) + name = proto.Field(proto.STRING, number=2,) ssml_gender = proto.Field(proto.ENUM, number=3, enum="SsmlVoiceGender",) class AudioConfig(proto.Message): r"""Description of audio data to be synthesized. - Attributes: audio_encoding (google.cloud.texttospeech_v1beta1.types.AudioEncoding): Required. The format of the audio byte @@ -265,16 +250,11 @@ class AudioConfig(proto.Message): """ audio_encoding = proto.Field(proto.ENUM, number=1, enum="AudioEncoding",) - - speaking_rate = proto.Field(proto.DOUBLE, number=2) - - pitch = proto.Field(proto.DOUBLE, number=3) - - volume_gain_db = proto.Field(proto.DOUBLE, number=4) - - sample_rate_hertz = proto.Field(proto.INT32, number=5) - - effects_profile_id = proto.RepeatedField(proto.STRING, number=6) + speaking_rate = proto.Field(proto.DOUBLE, number=2,) + pitch = proto.Field(proto.DOUBLE, number=3,) + volume_gain_db = proto.Field(proto.DOUBLE, number=4,) + sample_rate_hertz = proto.Field(proto.INT32, number=5,) + effects_profile_id = proto.RepeatedField(proto.STRING, number=6,) class SynthesizeSpeechResponse(proto.Message): @@ -297,10 +277,8 @@ class SynthesizeSpeechResponse(proto.Message): The audio metadata of ``audio_content``. """ - audio_content = proto.Field(proto.BYTES, number=1) - + audio_content = proto.Field(proto.BYTES, number=1,) timepoints = proto.RepeatedField(proto.MESSAGE, number=2, message="Timepoint",) - audio_config = proto.Field(proto.MESSAGE, number=4, message="AudioConfig",) @@ -317,9 +295,8 @@ class Timepoint(proto.Message): synthesized audio. """ - mark_name = proto.Field(proto.STRING, number=4) - - time_seconds = proto.Field(proto.DOUBLE, number=3) + mark_name = proto.Field(proto.STRING, number=4,) + time_seconds = proto.Field(proto.DOUBLE, number=3,) __all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/scripts/fixup_texttospeech_v1_keywords.py b/scripts/fixup_texttospeech_v1_keywords.py index 09616e09..c5867870 100644 --- a/scripts/fixup_texttospeech_v1_keywords.py +++ b/scripts/fixup_texttospeech_v1_keywords.py @@ -1,6 +1,5 @@ #! /usr/bin/env python3 # -*- coding: utf-8 -*- - # Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,7 +14,6 @@ # See the License for the specific language governing permissions and # limitations under the License. # - import argparse import os import libcst as cst @@ -41,9 +39,8 @@ def partition( class texttospeechCallTransformer(cst.CSTTransformer): CTRL_PARAMS: Tuple[str] = ('retry', 'timeout', 'metadata') METHOD_TO_PARAMS: Dict[str, Tuple[str]] = { - 'list_voices': ('language_code', ), - 'synthesize_speech': ('input', 'voice', 'audio_config', ), - + 'list_voices': ('language_code', ), + 'synthesize_speech': ('input', 'voice', 'audio_config', ), } def leave_Call(self, original: cst.Call, updated: cst.Call) -> cst.CSTNode: @@ -74,7 +71,7 @@ def leave_Call(self, original: cst.Call, updated: cst.Call) -> cst.CSTNode: value=cst.Dict([ cst.DictElement( cst.SimpleString("'{}'".format(name)), - cst.Element(value=arg.value) +cst.Element(value=arg.value) ) # Note: the args + kwargs looks silly, but keep in mind that # the control parameters had to be stripped out, and that diff --git a/scripts/fixup_texttospeech_v1beta1_keywords.py b/scripts/fixup_texttospeech_v1beta1_keywords.py index a69becfd..b67e4e1e 100644 --- a/scripts/fixup_texttospeech_v1beta1_keywords.py +++ b/scripts/fixup_texttospeech_v1beta1_keywords.py @@ -1,6 +1,5 @@ #! /usr/bin/env python3 # -*- coding: utf-8 -*- - # Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,7 +14,6 @@ # See the License for the specific language governing permissions and # limitations under the License. # - import argparse import os import libcst as cst @@ -41,9 +39,8 @@ def partition( class texttospeechCallTransformer(cst.CSTTransformer): CTRL_PARAMS: Tuple[str] = ('retry', 'timeout', 'metadata') METHOD_TO_PARAMS: Dict[str, Tuple[str]] = { - 'list_voices': ('language_code', ), - 'synthesize_speech': ('input', 'voice', 'audio_config', 'enable_time_pointing', ), - + 'list_voices': ('language_code', ), + 'synthesize_speech': ('input', 'voice', 'audio_config', 'enable_time_pointing', ), } def leave_Call(self, original: cst.Call, updated: cst.Call) -> cst.CSTNode: @@ -74,7 +71,7 @@ def leave_Call(self, original: cst.Call, updated: cst.Call) -> cst.CSTNode: value=cst.Dict([ cst.DictElement( cst.SimpleString("'{}'".format(name)), - cst.Element(value=arg.value) +cst.Element(value=arg.value) ) # Note: the args + kwargs looks silly, but keep in mind that # the control parameters had to be stripped out, and that diff --git a/setup.py b/setup.py index 054405dc..ef28a512 100644 --- a/setup.py +++ b/setup.py @@ -44,6 +44,7 @@ dependencies = [ "google-api-core[grpc] >= 1.22.2, < 2.0.0dev", "proto-plus >= 1.4.0", + "packaging >= 14.3", ] extras = {} diff --git a/testing/constraints-3.6.txt b/testing/constraints-3.6.txt index a37a34af..1bcef21b 100644 --- a/testing/constraints-3.6.txt +++ b/testing/constraints-3.6.txt @@ -7,3 +7,5 @@ # Then this file should have foo==1.14.0 google-api-core==1.22.2 proto-plus==1.4.0 +packaging==14.3 +google-auth==1.24.0 # TODO: remove when google-auth>=1.25.0 is transitively required through google-api-core diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 00000000..4de65971 --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# diff --git a/tests/unit/__init__.py b/tests/unit/__init__.py new file mode 100644 index 00000000..4de65971 --- /dev/null +++ b/tests/unit/__init__.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# diff --git a/tests/unit/gapic/__init__.py b/tests/unit/gapic/__init__.py new file mode 100644 index 00000000..4de65971 --- /dev/null +++ b/tests/unit/gapic/__init__.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# diff --git a/tests/unit/gapic/texttospeech_v1/__init__.py b/tests/unit/gapic/texttospeech_v1/__init__.py index 42ffdf2b..4de65971 100644 --- a/tests/unit/gapic/texttospeech_v1/__init__.py +++ b/tests/unit/gapic/texttospeech_v1/__init__.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- - # Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/tests/unit/gapic/texttospeech_v1/test_text_to_speech.py b/tests/unit/gapic/texttospeech_v1/test_text_to_speech.py index 9c6c48ba..9f880699 100644 --- a/tests/unit/gapic/texttospeech_v1/test_text_to_speech.py +++ b/tests/unit/gapic/texttospeech_v1/test_text_to_speech.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- - # Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,9 +13,9 @@ # See the License for the specific language governing permissions and # limitations under the License. # - import os import mock +import packaging.version import grpc from grpc.experimental import aio @@ -24,19 +23,49 @@ import pytest from proto.marshal.rules.dates import DurationRule, TimestampRule -from google import auth + from google.api_core import client_options -from google.api_core import exceptions +from google.api_core import exceptions as core_exceptions from google.api_core import gapic_v1 from google.api_core import grpc_helpers from google.api_core import grpc_helpers_async -from google.auth import credentials +from google.auth import credentials as ga_credentials from google.auth.exceptions import MutualTLSChannelError from google.cloud.texttospeech_v1.services.text_to_speech import TextToSpeechAsyncClient from google.cloud.texttospeech_v1.services.text_to_speech import TextToSpeechClient from google.cloud.texttospeech_v1.services.text_to_speech import transports +from google.cloud.texttospeech_v1.services.text_to_speech.transports.base import ( + _API_CORE_VERSION, +) +from google.cloud.texttospeech_v1.services.text_to_speech.transports.base import ( + _GOOGLE_AUTH_VERSION, +) from google.cloud.texttospeech_v1.types import cloud_tts from google.oauth2 import service_account +import google.auth + + +# TODO(busunkim): Once google-api-core >= 1.26.0 is required: +# - Delete all the api-core and auth "less than" test cases +# - Delete these pytest markers (Make the "greater than or equal to" tests the default). +requires_google_auth_lt_1_25_0 = pytest.mark.skipif( + packaging.version.parse(_GOOGLE_AUTH_VERSION) >= packaging.version.parse("1.25.0"), + reason="This test requires google-auth < 1.25.0", +) +requires_google_auth_gte_1_25_0 = pytest.mark.skipif( + packaging.version.parse(_GOOGLE_AUTH_VERSION) < packaging.version.parse("1.25.0"), + reason="This test requires google-auth >= 1.25.0", +) + +requires_api_core_lt_1_26_0 = pytest.mark.skipif( + packaging.version.parse(_API_CORE_VERSION) >= packaging.version.parse("1.26.0"), + reason="This test requires google-api-core < 1.26.0", +) + +requires_api_core_gte_1_26_0 = pytest.mark.skipif( + packaging.version.parse(_API_CORE_VERSION) < packaging.version.parse("1.26.0"), + reason="This test requires google-api-core >= 1.26.0", +) def client_cert_source_callback(): @@ -82,7 +111,7 @@ def test__get_default_mtls_endpoint(): @pytest.mark.parametrize("client_class", [TextToSpeechClient, TextToSpeechAsyncClient,]) def test_text_to_speech_client_from_service_account_info(client_class): - creds = credentials.AnonymousCredentials() + creds = ga_credentials.AnonymousCredentials() with mock.patch.object( service_account.Credentials, "from_service_account_info" ) as factory: @@ -97,7 +126,7 @@ def test_text_to_speech_client_from_service_account_info(client_class): @pytest.mark.parametrize("client_class", [TextToSpeechClient, TextToSpeechAsyncClient,]) def test_text_to_speech_client_from_service_account_file(client_class): - creds = credentials.AnonymousCredentials() + creds = ga_credentials.AnonymousCredentials() with mock.patch.object( service_account.Credentials, "from_service_account_file" ) as factory: @@ -148,7 +177,7 @@ def test_text_to_speech_client_client_options( ): # Check that if channel is provided we won't create a new one. with mock.patch.object(TextToSpeechClient, "get_transport_class") as gtc: - transport = transport_class(credentials=credentials.AnonymousCredentials()) + transport = transport_class(credentials=ga_credentials.AnonymousCredentials()) client = client_class(transport=transport) gtc.assert_not_called() @@ -430,7 +459,7 @@ def test_text_to_speech_client_client_options_from_dict(): def test_list_voices(transport: str = "grpc", request_type=cloud_tts.ListVoicesRequest): client = TextToSpeechClient( - credentials=credentials.AnonymousCredentials(), transport=transport, + credentials=ga_credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, @@ -441,17 +470,14 @@ def test_list_voices(transport: str = "grpc", request_type=cloud_tts.ListVoicesR with mock.patch.object(type(client.transport.list_voices), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = cloud_tts.ListVoicesResponse() - response = client.list_voices(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0] == cloud_tts.ListVoicesRequest() # Establish that the response is the type that we expect. - assert isinstance(response, cloud_tts.ListVoicesResponse) @@ -463,7 +489,7 @@ def test_list_voices_empty_call(): # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. client = TextToSpeechClient( - credentials=credentials.AnonymousCredentials(), transport="grpc", + credentials=ga_credentials.AnonymousCredentials(), transport="grpc", ) # Mock the actual call within the gRPC stub, and fake the request. @@ -471,7 +497,6 @@ def test_list_voices_empty_call(): client.list_voices() call.assert_called() _, args, _ = call.mock_calls[0] - assert args[0] == cloud_tts.ListVoicesRequest() @@ -480,7 +505,7 @@ async def test_list_voices_async( transport: str = "grpc_asyncio", request_type=cloud_tts.ListVoicesRequest ): client = TextToSpeechAsyncClient( - credentials=credentials.AnonymousCredentials(), transport=transport, + credentials=ga_credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, @@ -493,13 +518,11 @@ async def test_list_voices_async( call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( cloud_tts.ListVoicesResponse() ) - response = await client.list_voices(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0] == cloud_tts.ListVoicesRequest() # Establish that the response is the type that we expect. @@ -512,13 +535,12 @@ async def test_list_voices_async_from_dict(): def test_list_voices_flattened(): - client = TextToSpeechClient(credentials=credentials.AnonymousCredentials(),) + client = TextToSpeechClient(credentials=ga_credentials.AnonymousCredentials(),) # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.list_voices), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = cloud_tts.ListVoicesResponse() - # Call the method with a truthy value for each flattened field, # using the keyword arguments to the method. client.list_voices(language_code="language_code_value",) @@ -527,12 +549,11 @@ def test_list_voices_flattened(): # request object values. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0].language_code == "language_code_value" def test_list_voices_flattened_error(): - client = TextToSpeechClient(credentials=credentials.AnonymousCredentials(),) + client = TextToSpeechClient(credentials=ga_credentials.AnonymousCredentials(),) # Attempting to call a method with both a request object and flattened # fields is an error. @@ -544,7 +565,7 @@ def test_list_voices_flattened_error(): @pytest.mark.asyncio async def test_list_voices_flattened_async(): - client = TextToSpeechAsyncClient(credentials=credentials.AnonymousCredentials(),) + client = TextToSpeechAsyncClient(credentials=ga_credentials.AnonymousCredentials(),) # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.list_voices), "__call__") as call: @@ -562,13 +583,12 @@ async def test_list_voices_flattened_async(): # request object values. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0].language_code == "language_code_value" @pytest.mark.asyncio async def test_list_voices_flattened_error_async(): - client = TextToSpeechAsyncClient(credentials=credentials.AnonymousCredentials(),) + client = TextToSpeechAsyncClient(credentials=ga_credentials.AnonymousCredentials(),) # Attempting to call a method with both a request object and flattened # fields is an error. @@ -582,7 +602,7 @@ def test_synthesize_speech( transport: str = "grpc", request_type=cloud_tts.SynthesizeSpeechRequest ): client = TextToSpeechClient( - credentials=credentials.AnonymousCredentials(), transport=transport, + credentials=ga_credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, @@ -597,19 +617,15 @@ def test_synthesize_speech( call.return_value = cloud_tts.SynthesizeSpeechResponse( audio_content=b"audio_content_blob", ) - response = client.synthesize_speech(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0] == cloud_tts.SynthesizeSpeechRequest() # Establish that the response is the type that we expect. - assert isinstance(response, cloud_tts.SynthesizeSpeechResponse) - assert response.audio_content == b"audio_content_blob" @@ -621,7 +637,7 @@ def test_synthesize_speech_empty_call(): # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. client = TextToSpeechClient( - credentials=credentials.AnonymousCredentials(), transport="grpc", + credentials=ga_credentials.AnonymousCredentials(), transport="grpc", ) # Mock the actual call within the gRPC stub, and fake the request. @@ -631,7 +647,6 @@ def test_synthesize_speech_empty_call(): client.synthesize_speech() call.assert_called() _, args, _ = call.mock_calls[0] - assert args[0] == cloud_tts.SynthesizeSpeechRequest() @@ -640,7 +655,7 @@ async def test_synthesize_speech_async( transport: str = "grpc_asyncio", request_type=cloud_tts.SynthesizeSpeechRequest ): client = TextToSpeechAsyncClient( - credentials=credentials.AnonymousCredentials(), transport=transport, + credentials=ga_credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, @@ -655,18 +670,15 @@ async def test_synthesize_speech_async( call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( cloud_tts.SynthesizeSpeechResponse(audio_content=b"audio_content_blob",) ) - response = await client.synthesize_speech(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0] == cloud_tts.SynthesizeSpeechRequest() # Establish that the response is the type that we expect. assert isinstance(response, cloud_tts.SynthesizeSpeechResponse) - assert response.audio_content == b"audio_content_blob" @@ -676,7 +688,7 @@ async def test_synthesize_speech_async_from_dict(): def test_synthesize_speech_flattened(): - client = TextToSpeechClient(credentials=credentials.AnonymousCredentials(),) + client = TextToSpeechClient(credentials=ga_credentials.AnonymousCredentials(),) # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( @@ -684,7 +696,6 @@ def test_synthesize_speech_flattened(): ) as call: # Designate an appropriate return value for the call. call.return_value = cloud_tts.SynthesizeSpeechResponse() - # Call the method with a truthy value for each flattened field, # using the keyword arguments to the method. client.synthesize_speech( @@ -699,20 +710,17 @@ def test_synthesize_speech_flattened(): # request object values. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0].input == cloud_tts.SynthesisInput(text="text_value") - assert args[0].voice == cloud_tts.VoiceSelectionParams( language_code="language_code_value" ) - assert args[0].audio_config == cloud_tts.AudioConfig( audio_encoding=cloud_tts.AudioEncoding.LINEAR16 ) def test_synthesize_speech_flattened_error(): - client = TextToSpeechClient(credentials=credentials.AnonymousCredentials(),) + client = TextToSpeechClient(credentials=ga_credentials.AnonymousCredentials(),) # Attempting to call a method with both a request object and flattened # fields is an error. @@ -729,7 +737,7 @@ def test_synthesize_speech_flattened_error(): @pytest.mark.asyncio async def test_synthesize_speech_flattened_async(): - client = TextToSpeechAsyncClient(credentials=credentials.AnonymousCredentials(),) + client = TextToSpeechAsyncClient(credentials=ga_credentials.AnonymousCredentials(),) # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( @@ -755,13 +763,10 @@ async def test_synthesize_speech_flattened_async(): # request object values. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0].input == cloud_tts.SynthesisInput(text="text_value") - assert args[0].voice == cloud_tts.VoiceSelectionParams( language_code="language_code_value" ) - assert args[0].audio_config == cloud_tts.AudioConfig( audio_encoding=cloud_tts.AudioEncoding.LINEAR16 ) @@ -769,7 +774,7 @@ async def test_synthesize_speech_flattened_async(): @pytest.mark.asyncio async def test_synthesize_speech_flattened_error_async(): - client = TextToSpeechAsyncClient(credentials=credentials.AnonymousCredentials(),) + client = TextToSpeechAsyncClient(credentials=ga_credentials.AnonymousCredentials(),) # Attempting to call a method with both a request object and flattened # fields is an error. @@ -787,16 +792,16 @@ async def test_synthesize_speech_flattened_error_async(): def test_credentials_transport_error(): # It is an error to provide credentials and a transport instance. transport = transports.TextToSpeechGrpcTransport( - credentials=credentials.AnonymousCredentials(), + credentials=ga_credentials.AnonymousCredentials(), ) with pytest.raises(ValueError): client = TextToSpeechClient( - credentials=credentials.AnonymousCredentials(), transport=transport, + credentials=ga_credentials.AnonymousCredentials(), transport=transport, ) # It is an error to provide a credentials file and a transport instance. transport = transports.TextToSpeechGrpcTransport( - credentials=credentials.AnonymousCredentials(), + credentials=ga_credentials.AnonymousCredentials(), ) with pytest.raises(ValueError): client = TextToSpeechClient( @@ -806,7 +811,7 @@ def test_credentials_transport_error(): # It is an error to provide scopes and a transport instance. transport = transports.TextToSpeechGrpcTransport( - credentials=credentials.AnonymousCredentials(), + credentials=ga_credentials.AnonymousCredentials(), ) with pytest.raises(ValueError): client = TextToSpeechClient( @@ -817,7 +822,7 @@ def test_credentials_transport_error(): def test_transport_instance(): # A client may be instantiated with a custom transport instance. transport = transports.TextToSpeechGrpcTransport( - credentials=credentials.AnonymousCredentials(), + credentials=ga_credentials.AnonymousCredentials(), ) client = TextToSpeechClient(transport=transport) assert client.transport is transport @@ -826,13 +831,13 @@ def test_transport_instance(): def test_transport_get_channel(): # A client may be instantiated with a custom transport instance. transport = transports.TextToSpeechGrpcTransport( - credentials=credentials.AnonymousCredentials(), + credentials=ga_credentials.AnonymousCredentials(), ) channel = transport.grpc_channel assert channel transport = transports.TextToSpeechGrpcAsyncIOTransport( - credentials=credentials.AnonymousCredentials(), + credentials=ga_credentials.AnonymousCredentials(), ) channel = transport.grpc_channel assert channel @@ -847,23 +852,23 @@ def test_transport_get_channel(): ) 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) + with mock.patch.object(google.auth, "default") as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) transport_class() adc.assert_called_once() def test_transport_grpc_default(): # A client should use the gRPC transport by default. - client = TextToSpeechClient(credentials=credentials.AnonymousCredentials(),) + client = TextToSpeechClient(credentials=ga_credentials.AnonymousCredentials(),) assert isinstance(client.transport, transports.TextToSpeechGrpcTransport,) def test_text_to_speech_base_transport_error(): # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(exceptions.DuplicateCredentialArgs): + with pytest.raises(core_exceptions.DuplicateCredentialArgs): transport = transports.TextToSpeechTransport( - credentials=credentials.AnonymousCredentials(), + credentials=ga_credentials.AnonymousCredentials(), credentials_file="credentials.json", ) @@ -875,7 +880,7 @@ def test_text_to_speech_base_transport(): ) as Transport: Transport.return_value = None transport = transports.TextToSpeechTransport( - credentials=credentials.AnonymousCredentials(), + credentials=ga_credentials.AnonymousCredentials(), ) # Every method on the transport should just blindly @@ -889,15 +894,37 @@ def test_text_to_speech_base_transport(): getattr(transport, method)(request=object()) +@requires_google_auth_gte_1_25_0 def test_text_to_speech_base_transport_with_credentials_file(): # Instantiate the base transport with a credentials file with mock.patch.object( - auth, "load_credentials_from_file" + google.auth, "load_credentials_from_file", autospec=True + ) as load_creds, mock.patch( + "google.cloud.texttospeech_v1.services.text_to_speech.transports.TextToSpeechTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.TextToSpeechTransport( + credentials_file="credentials.json", quota_project_id="octopus", + ) + load_creds.assert_called_once_with( + "credentials.json", + scopes=None, + default_scopes=("https://www.googleapis.com/auth/cloud-platform",), + quota_project_id="octopus", + ) + + +@requires_google_auth_lt_1_25_0 +def test_text_to_speech_base_transport_with_credentials_file_old_google_auth(): + # Instantiate the base transport with a credentials file + with mock.patch.object( + google.auth, "load_credentials_from_file", autospec=True ) as load_creds, mock.patch( "google.cloud.texttospeech_v1.services.text_to_speech.transports.TextToSpeechTransport._prep_wrapped_messages" ) as Transport: Transport.return_value = None - load_creds.return_value = (credentials.AnonymousCredentials(), None) + load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) transport = transports.TextToSpeechTransport( credentials_file="credentials.json", quota_project_id="octopus", ) @@ -910,19 +937,33 @@ def test_text_to_speech_base_transport_with_credentials_file(): def test_text_to_speech_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( + with mock.patch.object(google.auth, "default", autospec=True) as adc, mock.patch( "google.cloud.texttospeech_v1.services.text_to_speech.transports.TextToSpeechTransport._prep_wrapped_messages" ) as Transport: Transport.return_value = None - adc.return_value = (credentials.AnonymousCredentials(), None) + adc.return_value = (ga_credentials.AnonymousCredentials(), None) transport = transports.TextToSpeechTransport() adc.assert_called_once() +@requires_google_auth_gte_1_25_0 def test_text_to_speech_auth_adc(): # If no credentials are provided, we should use ADC credentials. - with mock.patch.object(auth, "default") as adc: - adc.return_value = (credentials.AnonymousCredentials(), None) + with mock.patch.object(google.auth, "default", autospec=True) as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + TextToSpeechClient() + adc.assert_called_once_with( + scopes=None, + default_scopes=("https://www.googleapis.com/auth/cloud-platform",), + quota_project_id=None, + ) + + +@requires_google_auth_lt_1_25_0 +def test_text_to_speech_auth_adc_old_google_auth(): + # If no credentials are provided, we should use ADC credentials. + with mock.patch.object(google.auth, "default", autospec=True) as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) TextToSpeechClient() adc.assert_called_once_with( scopes=("https://www.googleapis.com/auth/cloud-platform",), @@ -930,26 +971,162 @@ def test_text_to_speech_auth_adc(): ) -def test_text_to_speech_transport_auth_adc(): +@pytest.mark.parametrize( + "transport_class", + [ + transports.TextToSpeechGrpcTransport, + transports.TextToSpeechGrpcAsyncIOTransport, + ], +) +@requires_google_auth_gte_1_25_0 +def test_text_to_speech_transport_auth_adc(transport_class): # If credentials and host are not provided, the transport class should use # ADC credentials. - with mock.patch.object(auth, "default") as adc: - adc.return_value = (credentials.AnonymousCredentials(), None) - transports.TextToSpeechGrpcTransport( - host="squid.clam.whelk", quota_project_id="octopus" + with mock.patch.object(google.auth, "default", autospec=True) as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class(quota_project_id="octopus", scopes=["1", "2"]) + adc.assert_called_once_with( + scopes=["1", "2"], + default_scopes=("https://www.googleapis.com/auth/cloud-platform",), + quota_project_id="octopus", ) + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.TextToSpeechGrpcTransport, + transports.TextToSpeechGrpcAsyncIOTransport, + ], +) +@requires_google_auth_lt_1_25_0 +def test_text_to_speech_transport_auth_adc_old_google_auth(transport_class): + # If credentials and host are not provided, the transport class should use + # ADC credentials. + with mock.patch.object(google.auth, "default", autospec=True) as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class(quota_project_id="octopus") adc.assert_called_once_with( scopes=("https://www.googleapis.com/auth/cloud-platform",), quota_project_id="octopus", ) +@pytest.mark.parametrize( + "transport_class,grpc_helpers", + [ + (transports.TextToSpeechGrpcTransport, grpc_helpers), + (transports.TextToSpeechGrpcAsyncIOTransport, grpc_helpers_async), + ], +) +@requires_api_core_gte_1_26_0 +def test_text_to_speech_transport_create_channel(transport_class, grpc_helpers): + # If credentials and host are not provided, the transport class should use + # ADC credentials. + with mock.patch.object( + google.auth, "default", autospec=True + ) as adc, mock.patch.object( + grpc_helpers, "create_channel", autospec=True + ) as create_channel: + creds = ga_credentials.AnonymousCredentials() + adc.return_value = (creds, None) + transport_class(quota_project_id="octopus", scopes=["1", "2"]) + + create_channel.assert_called_with( + "texttospeech.googleapis.com:443", + credentials=creds, + credentials_file=None, + quota_project_id="octopus", + default_scopes=("https://www.googleapis.com/auth/cloud-platform",), + scopes=["1", "2"], + default_host="texttospeech.googleapis.com", + ssl_credentials=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + +@pytest.mark.parametrize( + "transport_class,grpc_helpers", + [ + (transports.TextToSpeechGrpcTransport, grpc_helpers), + (transports.TextToSpeechGrpcAsyncIOTransport, grpc_helpers_async), + ], +) +@requires_api_core_lt_1_26_0 +def test_text_to_speech_transport_create_channel_old_api_core( + transport_class, grpc_helpers +): + # If credentials and host are not provided, the transport class should use + # ADC credentials. + with mock.patch.object( + google.auth, "default", autospec=True + ) as adc, mock.patch.object( + grpc_helpers, "create_channel", autospec=True + ) as create_channel: + creds = ga_credentials.AnonymousCredentials() + adc.return_value = (creds, None) + transport_class(quota_project_id="octopus") + + create_channel.assert_called_with( + "texttospeech.googleapis.com:443", + credentials=creds, + credentials_file=None, + quota_project_id="octopus", + scopes=("https://www.googleapis.com/auth/cloud-platform",), + ssl_credentials=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + +@pytest.mark.parametrize( + "transport_class,grpc_helpers", + [ + (transports.TextToSpeechGrpcTransport, grpc_helpers), + (transports.TextToSpeechGrpcAsyncIOTransport, grpc_helpers_async), + ], +) +@requires_api_core_lt_1_26_0 +def test_text_to_speech_transport_create_channel_user_scopes( + transport_class, grpc_helpers +): + # If credentials and host are not provided, the transport class should use + # ADC credentials. + with mock.patch.object( + google.auth, "default", autospec=True + ) as adc, mock.patch.object( + grpc_helpers, "create_channel", autospec=True + ) as create_channel: + creds = ga_credentials.AnonymousCredentials() + adc.return_value = (creds, None) + + transport_class(quota_project_id="octopus", scopes=["1", "2"]) + + create_channel.assert_called_with( + "texttospeech.googleapis.com:443", + credentials=creds, + credentials_file=None, + quota_project_id="octopus", + scopes=["1", "2"], + ssl_credentials=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + @pytest.mark.parametrize( "transport_class", [transports.TextToSpeechGrpcTransport, transports.TextToSpeechGrpcAsyncIOTransport], ) def test_text_to_speech_grpc_transport_client_cert_source_for_mtls(transport_class): - cred = credentials.AnonymousCredentials() + cred = ga_credentials.AnonymousCredentials() # Check ssl_channel_credentials is used if provided. with mock.patch.object(transport_class, "create_channel") as mock_create_channel: @@ -988,7 +1165,7 @@ def test_text_to_speech_grpc_transport_client_cert_source_for_mtls(transport_cla def test_text_to_speech_host_no_port(): client = TextToSpeechClient( - credentials=credentials.AnonymousCredentials(), + credentials=ga_credentials.AnonymousCredentials(), client_options=client_options.ClientOptions( api_endpoint="texttospeech.googleapis.com" ), @@ -998,7 +1175,7 @@ def test_text_to_speech_host_no_port(): def test_text_to_speech_host_with_port(): client = TextToSpeechClient( - credentials=credentials.AnonymousCredentials(), + credentials=ga_credentials.AnonymousCredentials(), client_options=client_options.ClientOptions( api_endpoint="texttospeech.googleapis.com:8000" ), @@ -1049,9 +1226,9 @@ def test_text_to_speech_transport_channel_mtls_with_client_cert_source(transport mock_grpc_channel = mock.Mock() grpc_create_channel.return_value = mock_grpc_channel - cred = credentials.AnonymousCredentials() + cred = ga_credentials.AnonymousCredentials() with pytest.warns(DeprecationWarning): - with mock.patch.object(auth, "default") as adc: + with mock.patch.object(google.auth, "default") as adc: adc.return_value = (cred, None) transport = transport_class( host="squid.clam.whelk", @@ -1124,7 +1301,6 @@ def test_text_to_speech_transport_channel_mtls_with_adc(transport_class): def test_common_billing_account_path(): billing_account = "squid" - expected = "billingAccounts/{billing_account}".format( billing_account=billing_account, ) @@ -1145,7 +1321,6 @@ def test_parse_common_billing_account_path(): def test_common_folder_path(): folder = "whelk" - expected = "folders/{folder}".format(folder=folder,) actual = TextToSpeechClient.common_folder_path(folder) assert expected == actual @@ -1164,7 +1339,6 @@ def test_parse_common_folder_path(): def test_common_organization_path(): organization = "oyster" - expected = "organizations/{organization}".format(organization=organization,) actual = TextToSpeechClient.common_organization_path(organization) assert expected == actual @@ -1183,7 +1357,6 @@ def test_parse_common_organization_path(): def test_common_project_path(): project = "cuttlefish" - expected = "projects/{project}".format(project=project,) actual = TextToSpeechClient.common_project_path(project) assert expected == actual @@ -1203,7 +1376,6 @@ def test_parse_common_project_path(): def test_common_location_path(): project = "winkle" location = "nautilus" - expected = "projects/{project}/locations/{location}".format( project=project, location=location, ) @@ -1230,7 +1402,7 @@ def test_client_withDEFAULT_CLIENT_INFO(): transports.TextToSpeechTransport, "_prep_wrapped_messages" ) as prep: client = TextToSpeechClient( - credentials=credentials.AnonymousCredentials(), client_info=client_info, + credentials=ga_credentials.AnonymousCredentials(), client_info=client_info, ) prep.assert_called_once_with(client_info) @@ -1239,6 +1411,6 @@ def test_client_withDEFAULT_CLIENT_INFO(): ) as prep: transport_class = TextToSpeechClient.get_transport_class() transport = transport_class( - credentials=credentials.AnonymousCredentials(), client_info=client_info, + credentials=ga_credentials.AnonymousCredentials(), client_info=client_info, ) prep.assert_called_once_with(client_info) diff --git a/tests/unit/gapic/texttospeech_v1beta1/__init__.py b/tests/unit/gapic/texttospeech_v1beta1/__init__.py index 42ffdf2b..4de65971 100644 --- a/tests/unit/gapic/texttospeech_v1beta1/__init__.py +++ b/tests/unit/gapic/texttospeech_v1beta1/__init__.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- - # Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/tests/unit/gapic/texttospeech_v1beta1/test_text_to_speech.py b/tests/unit/gapic/texttospeech_v1beta1/test_text_to_speech.py index a716482e..536f5b17 100644 --- a/tests/unit/gapic/texttospeech_v1beta1/test_text_to_speech.py +++ b/tests/unit/gapic/texttospeech_v1beta1/test_text_to_speech.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- - # Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,9 +13,9 @@ # See the License for the specific language governing permissions and # limitations under the License. # - import os import mock +import packaging.version import grpc from grpc.experimental import aio @@ -24,21 +23,51 @@ import pytest from proto.marshal.rules.dates import DurationRule, TimestampRule -from google import auth + from google.api_core import client_options -from google.api_core import exceptions +from google.api_core import exceptions as core_exceptions from google.api_core import gapic_v1 from google.api_core import grpc_helpers from google.api_core import grpc_helpers_async -from google.auth import credentials +from google.auth import credentials as ga_credentials from google.auth.exceptions import MutualTLSChannelError from google.cloud.texttospeech_v1beta1.services.text_to_speech import ( TextToSpeechAsyncClient, ) from google.cloud.texttospeech_v1beta1.services.text_to_speech import TextToSpeechClient from google.cloud.texttospeech_v1beta1.services.text_to_speech import transports +from google.cloud.texttospeech_v1beta1.services.text_to_speech.transports.base import ( + _API_CORE_VERSION, +) +from google.cloud.texttospeech_v1beta1.services.text_to_speech.transports.base import ( + _GOOGLE_AUTH_VERSION, +) from google.cloud.texttospeech_v1beta1.types import cloud_tts from google.oauth2 import service_account +import google.auth + + +# TODO(busunkim): Once google-api-core >= 1.26.0 is required: +# - Delete all the api-core and auth "less than" test cases +# - Delete these pytest markers (Make the "greater than or equal to" tests the default). +requires_google_auth_lt_1_25_0 = pytest.mark.skipif( + packaging.version.parse(_GOOGLE_AUTH_VERSION) >= packaging.version.parse("1.25.0"), + reason="This test requires google-auth < 1.25.0", +) +requires_google_auth_gte_1_25_0 = pytest.mark.skipif( + packaging.version.parse(_GOOGLE_AUTH_VERSION) < packaging.version.parse("1.25.0"), + reason="This test requires google-auth >= 1.25.0", +) + +requires_api_core_lt_1_26_0 = pytest.mark.skipif( + packaging.version.parse(_API_CORE_VERSION) >= packaging.version.parse("1.26.0"), + reason="This test requires google-api-core < 1.26.0", +) + +requires_api_core_gte_1_26_0 = pytest.mark.skipif( + packaging.version.parse(_API_CORE_VERSION) < packaging.version.parse("1.26.0"), + reason="This test requires google-api-core >= 1.26.0", +) def client_cert_source_callback(): @@ -84,7 +113,7 @@ def test__get_default_mtls_endpoint(): @pytest.mark.parametrize("client_class", [TextToSpeechClient, TextToSpeechAsyncClient,]) def test_text_to_speech_client_from_service_account_info(client_class): - creds = credentials.AnonymousCredentials() + creds = ga_credentials.AnonymousCredentials() with mock.patch.object( service_account.Credentials, "from_service_account_info" ) as factory: @@ -99,7 +128,7 @@ def test_text_to_speech_client_from_service_account_info(client_class): @pytest.mark.parametrize("client_class", [TextToSpeechClient, TextToSpeechAsyncClient,]) def test_text_to_speech_client_from_service_account_file(client_class): - creds = credentials.AnonymousCredentials() + creds = ga_credentials.AnonymousCredentials() with mock.patch.object( service_account.Credentials, "from_service_account_file" ) as factory: @@ -150,7 +179,7 @@ def test_text_to_speech_client_client_options( ): # Check that if channel is provided we won't create a new one. with mock.patch.object(TextToSpeechClient, "get_transport_class") as gtc: - transport = transport_class(credentials=credentials.AnonymousCredentials()) + transport = transport_class(credentials=ga_credentials.AnonymousCredentials()) client = client_class(transport=transport) gtc.assert_not_called() @@ -432,7 +461,7 @@ def test_text_to_speech_client_client_options_from_dict(): def test_list_voices(transport: str = "grpc", request_type=cloud_tts.ListVoicesRequest): client = TextToSpeechClient( - credentials=credentials.AnonymousCredentials(), transport=transport, + credentials=ga_credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, @@ -443,17 +472,14 @@ def test_list_voices(transport: str = "grpc", request_type=cloud_tts.ListVoicesR with mock.patch.object(type(client.transport.list_voices), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = cloud_tts.ListVoicesResponse() - response = client.list_voices(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0] == cloud_tts.ListVoicesRequest() # Establish that the response is the type that we expect. - assert isinstance(response, cloud_tts.ListVoicesResponse) @@ -465,7 +491,7 @@ def test_list_voices_empty_call(): # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. client = TextToSpeechClient( - credentials=credentials.AnonymousCredentials(), transport="grpc", + credentials=ga_credentials.AnonymousCredentials(), transport="grpc", ) # Mock the actual call within the gRPC stub, and fake the request. @@ -473,7 +499,6 @@ def test_list_voices_empty_call(): client.list_voices() call.assert_called() _, args, _ = call.mock_calls[0] - assert args[0] == cloud_tts.ListVoicesRequest() @@ -482,7 +507,7 @@ async def test_list_voices_async( transport: str = "grpc_asyncio", request_type=cloud_tts.ListVoicesRequest ): client = TextToSpeechAsyncClient( - credentials=credentials.AnonymousCredentials(), transport=transport, + credentials=ga_credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, @@ -495,13 +520,11 @@ async def test_list_voices_async( call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( cloud_tts.ListVoicesResponse() ) - response = await client.list_voices(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0] == cloud_tts.ListVoicesRequest() # Establish that the response is the type that we expect. @@ -514,13 +537,12 @@ async def test_list_voices_async_from_dict(): def test_list_voices_flattened(): - client = TextToSpeechClient(credentials=credentials.AnonymousCredentials(),) + client = TextToSpeechClient(credentials=ga_credentials.AnonymousCredentials(),) # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.list_voices), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = cloud_tts.ListVoicesResponse() - # Call the method with a truthy value for each flattened field, # using the keyword arguments to the method. client.list_voices(language_code="language_code_value",) @@ -529,12 +551,11 @@ def test_list_voices_flattened(): # request object values. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0].language_code == "language_code_value" def test_list_voices_flattened_error(): - client = TextToSpeechClient(credentials=credentials.AnonymousCredentials(),) + client = TextToSpeechClient(credentials=ga_credentials.AnonymousCredentials(),) # Attempting to call a method with both a request object and flattened # fields is an error. @@ -546,7 +567,7 @@ def test_list_voices_flattened_error(): @pytest.mark.asyncio async def test_list_voices_flattened_async(): - client = TextToSpeechAsyncClient(credentials=credentials.AnonymousCredentials(),) + client = TextToSpeechAsyncClient(credentials=ga_credentials.AnonymousCredentials(),) # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.list_voices), "__call__") as call: @@ -564,13 +585,12 @@ async def test_list_voices_flattened_async(): # request object values. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0].language_code == "language_code_value" @pytest.mark.asyncio async def test_list_voices_flattened_error_async(): - client = TextToSpeechAsyncClient(credentials=credentials.AnonymousCredentials(),) + client = TextToSpeechAsyncClient(credentials=ga_credentials.AnonymousCredentials(),) # Attempting to call a method with both a request object and flattened # fields is an error. @@ -584,7 +604,7 @@ def test_synthesize_speech( transport: str = "grpc", request_type=cloud_tts.SynthesizeSpeechRequest ): client = TextToSpeechClient( - credentials=credentials.AnonymousCredentials(), transport=transport, + credentials=ga_credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, @@ -599,19 +619,15 @@ def test_synthesize_speech( call.return_value = cloud_tts.SynthesizeSpeechResponse( audio_content=b"audio_content_blob", ) - response = client.synthesize_speech(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0] == cloud_tts.SynthesizeSpeechRequest() # Establish that the response is the type that we expect. - assert isinstance(response, cloud_tts.SynthesizeSpeechResponse) - assert response.audio_content == b"audio_content_blob" @@ -623,7 +639,7 @@ def test_synthesize_speech_empty_call(): # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. client = TextToSpeechClient( - credentials=credentials.AnonymousCredentials(), transport="grpc", + credentials=ga_credentials.AnonymousCredentials(), transport="grpc", ) # Mock the actual call within the gRPC stub, and fake the request. @@ -633,7 +649,6 @@ def test_synthesize_speech_empty_call(): client.synthesize_speech() call.assert_called() _, args, _ = call.mock_calls[0] - assert args[0] == cloud_tts.SynthesizeSpeechRequest() @@ -642,7 +657,7 @@ async def test_synthesize_speech_async( transport: str = "grpc_asyncio", request_type=cloud_tts.SynthesizeSpeechRequest ): client = TextToSpeechAsyncClient( - credentials=credentials.AnonymousCredentials(), transport=transport, + credentials=ga_credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, @@ -657,18 +672,15 @@ async def test_synthesize_speech_async( call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( cloud_tts.SynthesizeSpeechResponse(audio_content=b"audio_content_blob",) ) - response = await client.synthesize_speech(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0] == cloud_tts.SynthesizeSpeechRequest() # Establish that the response is the type that we expect. assert isinstance(response, cloud_tts.SynthesizeSpeechResponse) - assert response.audio_content == b"audio_content_blob" @@ -678,7 +690,7 @@ async def test_synthesize_speech_async_from_dict(): def test_synthesize_speech_flattened(): - client = TextToSpeechClient(credentials=credentials.AnonymousCredentials(),) + client = TextToSpeechClient(credentials=ga_credentials.AnonymousCredentials(),) # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( @@ -686,7 +698,6 @@ def test_synthesize_speech_flattened(): ) as call: # Designate an appropriate return value for the call. call.return_value = cloud_tts.SynthesizeSpeechResponse() - # Call the method with a truthy value for each flattened field, # using the keyword arguments to the method. client.synthesize_speech( @@ -701,20 +712,17 @@ def test_synthesize_speech_flattened(): # request object values. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0].input == cloud_tts.SynthesisInput(text="text_value") - assert args[0].voice == cloud_tts.VoiceSelectionParams( language_code="language_code_value" ) - assert args[0].audio_config == cloud_tts.AudioConfig( audio_encoding=cloud_tts.AudioEncoding.LINEAR16 ) def test_synthesize_speech_flattened_error(): - client = TextToSpeechClient(credentials=credentials.AnonymousCredentials(),) + client = TextToSpeechClient(credentials=ga_credentials.AnonymousCredentials(),) # Attempting to call a method with both a request object and flattened # fields is an error. @@ -731,7 +739,7 @@ def test_synthesize_speech_flattened_error(): @pytest.mark.asyncio async def test_synthesize_speech_flattened_async(): - client = TextToSpeechAsyncClient(credentials=credentials.AnonymousCredentials(),) + client = TextToSpeechAsyncClient(credentials=ga_credentials.AnonymousCredentials(),) # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( @@ -757,13 +765,10 @@ async def test_synthesize_speech_flattened_async(): # request object values. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0].input == cloud_tts.SynthesisInput(text="text_value") - assert args[0].voice == cloud_tts.VoiceSelectionParams( language_code="language_code_value" ) - assert args[0].audio_config == cloud_tts.AudioConfig( audio_encoding=cloud_tts.AudioEncoding.LINEAR16 ) @@ -771,7 +776,7 @@ async def test_synthesize_speech_flattened_async(): @pytest.mark.asyncio async def test_synthesize_speech_flattened_error_async(): - client = TextToSpeechAsyncClient(credentials=credentials.AnonymousCredentials(),) + client = TextToSpeechAsyncClient(credentials=ga_credentials.AnonymousCredentials(),) # Attempting to call a method with both a request object and flattened # fields is an error. @@ -789,16 +794,16 @@ async def test_synthesize_speech_flattened_error_async(): def test_credentials_transport_error(): # It is an error to provide credentials and a transport instance. transport = transports.TextToSpeechGrpcTransport( - credentials=credentials.AnonymousCredentials(), + credentials=ga_credentials.AnonymousCredentials(), ) with pytest.raises(ValueError): client = TextToSpeechClient( - credentials=credentials.AnonymousCredentials(), transport=transport, + credentials=ga_credentials.AnonymousCredentials(), transport=transport, ) # It is an error to provide a credentials file and a transport instance. transport = transports.TextToSpeechGrpcTransport( - credentials=credentials.AnonymousCredentials(), + credentials=ga_credentials.AnonymousCredentials(), ) with pytest.raises(ValueError): client = TextToSpeechClient( @@ -808,7 +813,7 @@ def test_credentials_transport_error(): # It is an error to provide scopes and a transport instance. transport = transports.TextToSpeechGrpcTransport( - credentials=credentials.AnonymousCredentials(), + credentials=ga_credentials.AnonymousCredentials(), ) with pytest.raises(ValueError): client = TextToSpeechClient( @@ -819,7 +824,7 @@ def test_credentials_transport_error(): def test_transport_instance(): # A client may be instantiated with a custom transport instance. transport = transports.TextToSpeechGrpcTransport( - credentials=credentials.AnonymousCredentials(), + credentials=ga_credentials.AnonymousCredentials(), ) client = TextToSpeechClient(transport=transport) assert client.transport is transport @@ -828,13 +833,13 @@ def test_transport_instance(): def test_transport_get_channel(): # A client may be instantiated with a custom transport instance. transport = transports.TextToSpeechGrpcTransport( - credentials=credentials.AnonymousCredentials(), + credentials=ga_credentials.AnonymousCredentials(), ) channel = transport.grpc_channel assert channel transport = transports.TextToSpeechGrpcAsyncIOTransport( - credentials=credentials.AnonymousCredentials(), + credentials=ga_credentials.AnonymousCredentials(), ) channel = transport.grpc_channel assert channel @@ -849,23 +854,23 @@ def test_transport_get_channel(): ) 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) + with mock.patch.object(google.auth, "default") as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) transport_class() adc.assert_called_once() def test_transport_grpc_default(): # A client should use the gRPC transport by default. - client = TextToSpeechClient(credentials=credentials.AnonymousCredentials(),) + client = TextToSpeechClient(credentials=ga_credentials.AnonymousCredentials(),) assert isinstance(client.transport, transports.TextToSpeechGrpcTransport,) def test_text_to_speech_base_transport_error(): # Passing both a credentials object and credentials_file should raise an error - with pytest.raises(exceptions.DuplicateCredentialArgs): + with pytest.raises(core_exceptions.DuplicateCredentialArgs): transport = transports.TextToSpeechTransport( - credentials=credentials.AnonymousCredentials(), + credentials=ga_credentials.AnonymousCredentials(), credentials_file="credentials.json", ) @@ -877,7 +882,7 @@ def test_text_to_speech_base_transport(): ) as Transport: Transport.return_value = None transport = transports.TextToSpeechTransport( - credentials=credentials.AnonymousCredentials(), + credentials=ga_credentials.AnonymousCredentials(), ) # Every method on the transport should just blindly @@ -891,15 +896,37 @@ def test_text_to_speech_base_transport(): getattr(transport, method)(request=object()) +@requires_google_auth_gte_1_25_0 def test_text_to_speech_base_transport_with_credentials_file(): # Instantiate the base transport with a credentials file with mock.patch.object( - auth, "load_credentials_from_file" + google.auth, "load_credentials_from_file", autospec=True + ) as load_creds, mock.patch( + "google.cloud.texttospeech_v1beta1.services.text_to_speech.transports.TextToSpeechTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.TextToSpeechTransport( + credentials_file="credentials.json", quota_project_id="octopus", + ) + load_creds.assert_called_once_with( + "credentials.json", + scopes=None, + default_scopes=("https://www.googleapis.com/auth/cloud-platform",), + quota_project_id="octopus", + ) + + +@requires_google_auth_lt_1_25_0 +def test_text_to_speech_base_transport_with_credentials_file_old_google_auth(): + # Instantiate the base transport with a credentials file + with mock.patch.object( + google.auth, "load_credentials_from_file", autospec=True ) as load_creds, mock.patch( "google.cloud.texttospeech_v1beta1.services.text_to_speech.transports.TextToSpeechTransport._prep_wrapped_messages" ) as Transport: Transport.return_value = None - load_creds.return_value = (credentials.AnonymousCredentials(), None) + load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) transport = transports.TextToSpeechTransport( credentials_file="credentials.json", quota_project_id="octopus", ) @@ -912,19 +939,33 @@ def test_text_to_speech_base_transport_with_credentials_file(): def test_text_to_speech_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( + with mock.patch.object(google.auth, "default", autospec=True) as adc, mock.patch( "google.cloud.texttospeech_v1beta1.services.text_to_speech.transports.TextToSpeechTransport._prep_wrapped_messages" ) as Transport: Transport.return_value = None - adc.return_value = (credentials.AnonymousCredentials(), None) + adc.return_value = (ga_credentials.AnonymousCredentials(), None) transport = transports.TextToSpeechTransport() adc.assert_called_once() +@requires_google_auth_gte_1_25_0 def test_text_to_speech_auth_adc(): # If no credentials are provided, we should use ADC credentials. - with mock.patch.object(auth, "default") as adc: - adc.return_value = (credentials.AnonymousCredentials(), None) + with mock.patch.object(google.auth, "default", autospec=True) as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + TextToSpeechClient() + adc.assert_called_once_with( + scopes=None, + default_scopes=("https://www.googleapis.com/auth/cloud-platform",), + quota_project_id=None, + ) + + +@requires_google_auth_lt_1_25_0 +def test_text_to_speech_auth_adc_old_google_auth(): + # If no credentials are provided, we should use ADC credentials. + with mock.patch.object(google.auth, "default", autospec=True) as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) TextToSpeechClient() adc.assert_called_once_with( scopes=("https://www.googleapis.com/auth/cloud-platform",), @@ -932,26 +973,162 @@ def test_text_to_speech_auth_adc(): ) -def test_text_to_speech_transport_auth_adc(): +@pytest.mark.parametrize( + "transport_class", + [ + transports.TextToSpeechGrpcTransport, + transports.TextToSpeechGrpcAsyncIOTransport, + ], +) +@requires_google_auth_gte_1_25_0 +def test_text_to_speech_transport_auth_adc(transport_class): # If credentials and host are not provided, the transport class should use # ADC credentials. - with mock.patch.object(auth, "default") as adc: - adc.return_value = (credentials.AnonymousCredentials(), None) - transports.TextToSpeechGrpcTransport( - host="squid.clam.whelk", quota_project_id="octopus" + with mock.patch.object(google.auth, "default", autospec=True) as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class(quota_project_id="octopus", scopes=["1", "2"]) + adc.assert_called_once_with( + scopes=["1", "2"], + default_scopes=("https://www.googleapis.com/auth/cloud-platform",), + quota_project_id="octopus", ) + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.TextToSpeechGrpcTransport, + transports.TextToSpeechGrpcAsyncIOTransport, + ], +) +@requires_google_auth_lt_1_25_0 +def test_text_to_speech_transport_auth_adc_old_google_auth(transport_class): + # If credentials and host are not provided, the transport class should use + # ADC credentials. + with mock.patch.object(google.auth, "default", autospec=True) as adc: + adc.return_value = (ga_credentials.AnonymousCredentials(), None) + transport_class(quota_project_id="octopus") adc.assert_called_once_with( scopes=("https://www.googleapis.com/auth/cloud-platform",), quota_project_id="octopus", ) +@pytest.mark.parametrize( + "transport_class,grpc_helpers", + [ + (transports.TextToSpeechGrpcTransport, grpc_helpers), + (transports.TextToSpeechGrpcAsyncIOTransport, grpc_helpers_async), + ], +) +@requires_api_core_gte_1_26_0 +def test_text_to_speech_transport_create_channel(transport_class, grpc_helpers): + # If credentials and host are not provided, the transport class should use + # ADC credentials. + with mock.patch.object( + google.auth, "default", autospec=True + ) as adc, mock.patch.object( + grpc_helpers, "create_channel", autospec=True + ) as create_channel: + creds = ga_credentials.AnonymousCredentials() + adc.return_value = (creds, None) + transport_class(quota_project_id="octopus", scopes=["1", "2"]) + + create_channel.assert_called_with( + "texttospeech.googleapis.com:443", + credentials=creds, + credentials_file=None, + quota_project_id="octopus", + default_scopes=("https://www.googleapis.com/auth/cloud-platform",), + scopes=["1", "2"], + default_host="texttospeech.googleapis.com", + ssl_credentials=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + +@pytest.mark.parametrize( + "transport_class,grpc_helpers", + [ + (transports.TextToSpeechGrpcTransport, grpc_helpers), + (transports.TextToSpeechGrpcAsyncIOTransport, grpc_helpers_async), + ], +) +@requires_api_core_lt_1_26_0 +def test_text_to_speech_transport_create_channel_old_api_core( + transport_class, grpc_helpers +): + # If credentials and host are not provided, the transport class should use + # ADC credentials. + with mock.patch.object( + google.auth, "default", autospec=True + ) as adc, mock.patch.object( + grpc_helpers, "create_channel", autospec=True + ) as create_channel: + creds = ga_credentials.AnonymousCredentials() + adc.return_value = (creds, None) + transport_class(quota_project_id="octopus") + + create_channel.assert_called_with( + "texttospeech.googleapis.com:443", + credentials=creds, + credentials_file=None, + quota_project_id="octopus", + scopes=("https://www.googleapis.com/auth/cloud-platform",), + ssl_credentials=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + +@pytest.mark.parametrize( + "transport_class,grpc_helpers", + [ + (transports.TextToSpeechGrpcTransport, grpc_helpers), + (transports.TextToSpeechGrpcAsyncIOTransport, grpc_helpers_async), + ], +) +@requires_api_core_lt_1_26_0 +def test_text_to_speech_transport_create_channel_user_scopes( + transport_class, grpc_helpers +): + # If credentials and host are not provided, the transport class should use + # ADC credentials. + with mock.patch.object( + google.auth, "default", autospec=True + ) as adc, mock.patch.object( + grpc_helpers, "create_channel", autospec=True + ) as create_channel: + creds = ga_credentials.AnonymousCredentials() + adc.return_value = (creds, None) + + transport_class(quota_project_id="octopus", scopes=["1", "2"]) + + create_channel.assert_called_with( + "texttospeech.googleapis.com:443", + credentials=creds, + credentials_file=None, + quota_project_id="octopus", + scopes=["1", "2"], + ssl_credentials=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + @pytest.mark.parametrize( "transport_class", [transports.TextToSpeechGrpcTransport, transports.TextToSpeechGrpcAsyncIOTransport], ) def test_text_to_speech_grpc_transport_client_cert_source_for_mtls(transport_class): - cred = credentials.AnonymousCredentials() + cred = ga_credentials.AnonymousCredentials() # Check ssl_channel_credentials is used if provided. with mock.patch.object(transport_class, "create_channel") as mock_create_channel: @@ -990,7 +1167,7 @@ def test_text_to_speech_grpc_transport_client_cert_source_for_mtls(transport_cla def test_text_to_speech_host_no_port(): client = TextToSpeechClient( - credentials=credentials.AnonymousCredentials(), + credentials=ga_credentials.AnonymousCredentials(), client_options=client_options.ClientOptions( api_endpoint="texttospeech.googleapis.com" ), @@ -1000,7 +1177,7 @@ def test_text_to_speech_host_no_port(): def test_text_to_speech_host_with_port(): client = TextToSpeechClient( - credentials=credentials.AnonymousCredentials(), + credentials=ga_credentials.AnonymousCredentials(), client_options=client_options.ClientOptions( api_endpoint="texttospeech.googleapis.com:8000" ), @@ -1051,9 +1228,9 @@ def test_text_to_speech_transport_channel_mtls_with_client_cert_source(transport mock_grpc_channel = mock.Mock() grpc_create_channel.return_value = mock_grpc_channel - cred = credentials.AnonymousCredentials() + cred = ga_credentials.AnonymousCredentials() with pytest.warns(DeprecationWarning): - with mock.patch.object(auth, "default") as adc: + with mock.patch.object(google.auth, "default") as adc: adc.return_value = (cred, None) transport = transport_class( host="squid.clam.whelk", @@ -1126,7 +1303,6 @@ def test_text_to_speech_transport_channel_mtls_with_adc(transport_class): def test_common_billing_account_path(): billing_account = "squid" - expected = "billingAccounts/{billing_account}".format( billing_account=billing_account, ) @@ -1147,7 +1323,6 @@ def test_parse_common_billing_account_path(): def test_common_folder_path(): folder = "whelk" - expected = "folders/{folder}".format(folder=folder,) actual = TextToSpeechClient.common_folder_path(folder) assert expected == actual @@ -1166,7 +1341,6 @@ def test_parse_common_folder_path(): def test_common_organization_path(): organization = "oyster" - expected = "organizations/{organization}".format(organization=organization,) actual = TextToSpeechClient.common_organization_path(organization) assert expected == actual @@ -1185,7 +1359,6 @@ def test_parse_common_organization_path(): def test_common_project_path(): project = "cuttlefish" - expected = "projects/{project}".format(project=project,) actual = TextToSpeechClient.common_project_path(project) assert expected == actual @@ -1205,7 +1378,6 @@ def test_parse_common_project_path(): def test_common_location_path(): project = "winkle" location = "nautilus" - expected = "projects/{project}/locations/{location}".format( project=project, location=location, ) @@ -1232,7 +1404,7 @@ def test_client_withDEFAULT_CLIENT_INFO(): transports.TextToSpeechTransport, "_prep_wrapped_messages" ) as prep: client = TextToSpeechClient( - credentials=credentials.AnonymousCredentials(), client_info=client_info, + credentials=ga_credentials.AnonymousCredentials(), client_info=client_info, ) prep.assert_called_once_with(client_info) @@ -1241,6 +1413,6 @@ def test_client_withDEFAULT_CLIENT_INFO(): ) as prep: transport_class = TextToSpeechClient.get_transport_class() transport = transport_class( - credentials=credentials.AnonymousCredentials(), client_info=client_info, + credentials=ga_credentials.AnonymousCredentials(), client_info=client_info, ) prep.assert_called_once_with(client_info)