From 0630fa0538a633297cae935bd094443d7eeb8d45 Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Thu, 20 May 2021 17:41:12 -0600 Subject: [PATCH] chore: upgrade gapic-generator-python to 0.46.3 (#22) feat: support self-signed JWT flow for service accounts fix: add async client to %name_%version/init.py chore: add autogenerated snippets chore: remove auth, policy, and options from the reserved names list chore: enable GAPIC metadata generation chore: sort subpackages in %namespace/%name/init.py --- google/cloud/servicecontrol/__init__.py | 28 +- google/cloud/servicecontrol_v1/__init__.py | 7 +- .../servicecontrol_v1/gapic_metadata.json | 67 ++++ .../servicecontrol_v1/services/__init__.py | 1 - .../services/quota_controller/__init__.py | 2 - .../services/quota_controller/async_client.py | 25 +- .../services/quota_controller/client.py | 59 +-- .../quota_controller/transports/__init__.py | 2 - .../quota_controller/transports/base.py | 104 ++++-- .../quota_controller/transports/grpc.py | 22 +- .../transports/grpc_asyncio.py | 23 +- .../services/service_controller/__init__.py | 2 - .../service_controller/async_client.py | 27 +- .../services/service_controller/client.py | 61 ++-- .../service_controller/transports/__init__.py | 2 - .../service_controller/transports/base.py | 110 ++++-- .../service_controller/transports/grpc.py | 22 +- .../transports/grpc_asyncio.py | 23 +- .../cloud/servicecontrol_v1/types/__init__.py | 2 - .../servicecontrol_v1/types/check_error.py | 14 +- .../servicecontrol_v1/types/distribution.py | 43 +-- .../servicecontrol_v1/types/http_request.py | 49 +-- .../servicecontrol_v1/types/log_entry.py | 60 +-- .../servicecontrol_v1/types/metric_value.py | 30 +- .../servicecontrol_v1/types/operation.py | 31 +- .../types/quota_controller.py | 38 +- .../types/service_controller.py | 53 +-- scripts/fixup_servicecontrol_v1_keywords.py | 11 +- setup.py | 1 + testing/constraints-3.6.txt | 2 + tests/__init__.py | 15 + tests/unit/__init__.py | 15 + tests/unit/gapic/__init__.py | 15 + .../unit/gapic/servicecontrol_v1/__init__.py | 1 - .../test_quota_controller.py | 317 +++++++++++++--- .../test_service_controller.py | 343 ++++++++++++++---- 36 files changed, 1046 insertions(+), 581 deletions(-) create mode 100644 google/cloud/servicecontrol_v1/gapic_metadata.json create mode 100644 tests/__init__.py create mode 100644 tests/unit/__init__.py create mode 100644 tests/unit/gapic/__init__.py diff --git a/google/cloud/servicecontrol/__init__.py b/google/cloud/servicecontrol/__init__.py index ba8bb9e..ed26273 100644 --- a/google/cloud/servicecontrol/__init__.py +++ b/google/cloud/servicecontrol/__init__.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- - # Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,18 +14,19 @@ # limitations under the License. # -from google.cloud.servicecontrol_v1.services.quota_controller.async_client import ( - QuotaControllerAsyncClient, -) from google.cloud.servicecontrol_v1.services.quota_controller.client import ( QuotaControllerClient, ) -from google.cloud.servicecontrol_v1.services.service_controller.async_client import ( - ServiceControllerAsyncClient, +from google.cloud.servicecontrol_v1.services.quota_controller.async_client import ( + QuotaControllerAsyncClient, ) from google.cloud.servicecontrol_v1.services.service_controller.client import ( ServiceControllerClient, ) +from google.cloud.servicecontrol_v1.services.service_controller.async_client import ( + ServiceControllerAsyncClient, +) + from google.cloud.servicecontrol_v1.types.check_error import CheckError from google.cloud.servicecontrol_v1.types.distribution import Distribution from google.cloud.servicecontrol_v1.types.http_request import HttpRequest @@ -46,11 +46,11 @@ from google.cloud.servicecontrol_v1.types.service_controller import ReportResponse __all__ = ( - "AllocateQuotaRequest", - "AllocateQuotaResponse", + "QuotaControllerClient", + "QuotaControllerAsyncClient", + "ServiceControllerClient", + "ServiceControllerAsyncClient", "CheckError", - "CheckRequest", - "CheckResponse", "Distribution", "HttpRequest", "LogEntry", @@ -59,12 +59,12 @@ "MetricValue", "MetricValueSet", "Operation", - "QuotaControllerAsyncClient", - "QuotaControllerClient", + "AllocateQuotaRequest", + "AllocateQuotaResponse", "QuotaError", "QuotaOperation", + "CheckRequest", + "CheckResponse", "ReportRequest", "ReportResponse", - "ServiceControllerAsyncClient", - "ServiceControllerClient", ) diff --git a/google/cloud/servicecontrol_v1/__init__.py b/google/cloud/servicecontrol_v1/__init__.py index f1c56b2..5d53ac5 100644 --- a/google/cloud/servicecontrol_v1/__init__.py +++ b/google/cloud/servicecontrol_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,7 +15,10 @@ # from .services.quota_controller import QuotaControllerClient +from .services.quota_controller import QuotaControllerAsyncClient from .services.service_controller import ServiceControllerClient +from .services.service_controller import ServiceControllerAsyncClient + from .types.check_error import CheckError from .types.distribution import Distribution from .types.http_request import HttpRequest @@ -35,8 +37,9 @@ from .types.service_controller import ReportRequest from .types.service_controller import ReportResponse - __all__ = ( + "QuotaControllerAsyncClient", + "ServiceControllerAsyncClient", "AllocateQuotaRequest", "AllocateQuotaResponse", "CheckError", diff --git a/google/cloud/servicecontrol_v1/gapic_metadata.json b/google/cloud/servicecontrol_v1/gapic_metadata.json new file mode 100644 index 0000000..3a46912 --- /dev/null +++ b/google/cloud/servicecontrol_v1/gapic_metadata.json @@ -0,0 +1,67 @@ + { + "comment": "This file maps proto services/RPCs to the corresponding library clients/methods", + "language": "python", + "libraryPackage": "google.cloud.servicecontrol_v1", + "protoPackage": "google.api.servicecontrol.v1", + "schema": "1.0", + "services": { + "QuotaController": { + "clients": { + "grpc": { + "libraryClient": "QuotaControllerClient", + "rpcs": { + "AllocateQuota": { + "methods": [ + "allocate_quota" + ] + } + } + }, + "grpc-async": { + "libraryClient": "QuotaControllerAsyncClient", + "rpcs": { + "AllocateQuota": { + "methods": [ + "allocate_quota" + ] + } + } + } + } + }, + "ServiceController": { + "clients": { + "grpc": { + "libraryClient": "ServiceControllerClient", + "rpcs": { + "Check": { + "methods": [ + "check" + ] + }, + "Report": { + "methods": [ + "report" + ] + } + } + }, + "grpc-async": { + "libraryClient": "ServiceControllerAsyncClient", + "rpcs": { + "Check": { + "methods": [ + "check" + ] + }, + "Report": { + "methods": [ + "report" + ] + } + } + } + } + } + } +} diff --git a/google/cloud/servicecontrol_v1/services/__init__.py b/google/cloud/servicecontrol_v1/services/__init__.py index 42ffdf2..4de6597 100644 --- a/google/cloud/servicecontrol_v1/services/__init__.py +++ b/google/cloud/servicecontrol_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/servicecontrol_v1/services/quota_controller/__init__.py b/google/cloud/servicecontrol_v1/services/quota_controller/__init__.py index b9565b6..75db06f 100644 --- a/google/cloud/servicecontrol_v1/services/quota_controller/__init__.py +++ b/google/cloud/servicecontrol_v1/services/quota_controller/__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 QuotaControllerClient from .async_client import QuotaControllerAsyncClient diff --git a/google/cloud/servicecontrol_v1/services/quota_controller/async_client.py b/google/cloud/servicecontrol_v1/services/quota_controller/async_client.py index f701f39..924d723 100644 --- a/google/cloud/servicecontrol_v1/services/quota_controller/async_client.py +++ b/google/cloud/servicecontrol_v1/services/quota_controller/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,15 +20,14 @@ 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.servicecontrol_v1.types import metric_value from google.cloud.servicecontrol_v1.types import quota_controller - from .transports.base import QuotaControllerTransport, DEFAULT_CLIENT_INFO from .transports.grpc_asyncio import QuotaControllerGrpcAsyncIOTransport from .client import QuotaControllerClient @@ -55,24 +52,20 @@ class QuotaControllerAsyncClient: parse_common_billing_account_path = staticmethod( QuotaControllerClient.parse_common_billing_account_path ) - common_folder_path = staticmethod(QuotaControllerClient.common_folder_path) parse_common_folder_path = staticmethod( QuotaControllerClient.parse_common_folder_path ) - common_organization_path = staticmethod( QuotaControllerClient.common_organization_path ) parse_common_organization_path = staticmethod( QuotaControllerClient.parse_common_organization_path ) - common_project_path = staticmethod(QuotaControllerClient.common_project_path) parse_common_project_path = staticmethod( QuotaControllerClient.parse_common_project_path ) - common_location_path = staticmethod(QuotaControllerClient.common_location_path) parse_common_location_path = staticmethod( QuotaControllerClient.parse_common_location_path @@ -80,7 +73,8 @@ class QuotaControllerAsyncClient: @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. @@ -95,7 +89,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 @@ -112,7 +106,7 @@ def from_service_account_file(cls, filename: str, *args, **kwargs): @property def transport(self) -> QuotaControllerTransport: - """Return the transport used by the client instance. + """Returns the transport used by the client instance. Returns: QuotaControllerTransport: The transport used by the client instance. @@ -126,12 +120,12 @@ def transport(self) -> QuotaControllerTransport: def __init__( self, *, - credentials: credentials.Credentials = None, + credentials: ga_credentials.Credentials = None, transport: Union[str, QuotaControllerTransport] = "grpc_asyncio", client_options: ClientOptions = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: - """Instantiate the quota controller client. + """Instantiates the quota controller client. Args: credentials (Optional[google.auth.credentials.Credentials]): The @@ -163,7 +157,6 @@ def __init__( google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport creation failed for any reason. """ - self._client = QuotaControllerClient( credentials=credentials, transport=transport, @@ -196,7 +189,6 @@ async def allocate_quota( request (:class:`google.cloud.servicecontrol_v1.types.AllocateQuotaRequest`): The request object. Request message for the AllocateQuota method. - retry (google.api_core.retry.Retry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. @@ -210,7 +202,6 @@ async def allocate_quota( """ # Create or coerce a protobuf request object. - request = quota_controller.AllocateQuotaRequest(request) # Wrap the RPC method; this adds retry and timeout information, diff --git a/google/cloud/servicecontrol_v1/services/quota_controller/client.py b/google/cloud/servicecontrol_v1/services/quota_controller/client.py index e46f617..5733c03 100644 --- a/google/cloud/servicecontrol_v1/services/quota_controller/client.py +++ b/google/cloud/servicecontrol_v1/services/quota_controller/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,10 +21,10 @@ 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 @@ -34,7 +32,6 @@ from google.cloud.servicecontrol_v1.types import metric_value from google.cloud.servicecontrol_v1.types import quota_controller - from .transports.base import QuotaControllerTransport, DEFAULT_CLIENT_INFO from .transports.grpc import QuotaControllerGrpcTransport from .transports.grpc_asyncio import QuotaControllerGrpcAsyncIOTransport @@ -55,7 +52,7 @@ class QuotaControllerClientMeta(type): _transport_registry["grpc_asyncio"] = QuotaControllerGrpcAsyncIOTransport def get_transport_class(cls, label: str = None,) -> Type[QuotaControllerTransport]: - """Return an appropriate transport class. + """Returns an appropriate transport class. Args: label: The name of the desired transport. If none is @@ -83,7 +80,8 @@ class QuotaControllerClient(metaclass=QuotaControllerClientMeta): @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: @@ -117,7 +115,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. @@ -134,7 +133,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 @@ -153,16 +152,17 @@ def from_service_account_file(cls, filename: str, *args, **kwargs): @property def transport(self) -> QuotaControllerTransport: - """Return the transport used by the client instance. + """Returns the transport used by the client instance. Returns: - QuotaControllerTransport: The transport used by the client instance. + QuotaControllerTransport: 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, ) @@ -175,7 +175,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 @@ -186,7 +186,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 @@ -197,7 +197,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 @@ -208,7 +208,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, ) @@ -222,12 +222,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, QuotaControllerTransport, None] = None, client_options: Optional[client_options_lib.ClientOptions] = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: - """Instantiate the quota controller client. + """Instantiates the quota controller client. Args: credentials (Optional[google.auth.credentials.Credentials]): The @@ -282,9 +282,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: @@ -296,12 +297,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. @@ -316,8 +319,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: @@ -357,7 +360,6 @@ def allocate_quota( request (google.cloud.servicecontrol_v1.types.AllocateQuotaRequest): The request object. Request message for the AllocateQuota method. - retry (google.api_core.retry.Retry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. @@ -371,7 +373,6 @@ def allocate_quota( """ # Create or coerce a protobuf request object. - # Minor optimization to avoid making a copy if the user passes # in a quota_controller.AllocateQuotaRequest. # There's no risk of modifying the input as we've already verified diff --git a/google/cloud/servicecontrol_v1/services/quota_controller/transports/__init__.py b/google/cloud/servicecontrol_v1/services/quota_controller/transports/__init__.py index 3d1fad7..d00d592 100644 --- a/google/cloud/servicecontrol_v1/services/quota_controller/transports/__init__.py +++ b/google/cloud/servicecontrol_v1/services/quota_controller/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/servicecontrol_v1/services/quota_controller/transports/base.py b/google/cloud/servicecontrol_v1/services/quota_controller/transports/base.py index 0645376..a9eef86 100644 --- a/google/cloud/servicecontrol_v1/services/quota_controller/transports/base.py +++ b/google/cloud/servicecontrol_v1/services/quota_controller/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.servicecontrol_v1.types import quota_controller - try: DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( gapic_version=pkg_resources.get_distribution( @@ -37,6 +36,17 @@ 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 QuotaControllerTransport(abc.ABC): """Abstract transport class for QuotaController.""" @@ -46,21 +56,24 @@ class QuotaControllerTransport(abc.ABC): "https://www.googleapis.com/auth/servicecontrol", ) + DEFAULT_HOST: str = "servicecontrol.googleapis.com" + def __init__( self, *, - host: str = "servicecontrol.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 @@ -69,7 +82,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): @@ -83,29 +96,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,11 +177,11 @@ def _prep_wrapped_messages(self, client_info): @property def allocate_quota( self, - ) -> typing.Callable[ + ) -> Callable[ [quota_controller.AllocateQuotaRequest], - typing.Union[ + Union[ quota_controller.AllocateQuotaResponse, - typing.Awaitable[quota_controller.AllocateQuotaResponse], + Awaitable[quota_controller.AllocateQuotaResponse], ], ]: raise NotImplementedError() diff --git a/google/cloud/servicecontrol_v1/services/quota_controller/transports/grpc.py b/google/cloud/servicecontrol_v1/services/quota_controller/transports/grpc.py index 8902bdc..d44597f 100644 --- a/google/cloud/servicecontrol_v1/services/quota_controller/transports/grpc.py +++ b/google/cloud/servicecontrol_v1/services/quota_controller/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.servicecontrol_v1.types import quota_controller - from .base import QuotaControllerTransport, DEFAULT_CLIENT_INFO @@ -54,7 +51,7 @@ def __init__( self, *, host: str = "servicecontrol.googleapis.com", - credentials: credentials.Credentials = None, + credentials: ga_credentials.Credentials = None, credentials_file: str = None, scopes: Sequence[str] = None, channel: grpc.Channel = None, @@ -68,7 +65,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 @@ -178,7 +176,7 @@ def __init__( def create_channel( cls, host: str = "servicecontrol.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, @@ -209,13 +207,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/servicecontrol_v1/services/quota_controller/transports/grpc_asyncio.py b/google/cloud/servicecontrol_v1/services/quota_controller/transports/grpc_asyncio.py index c17c030..d7318e0 100644 --- a/google/cloud/servicecontrol_v1/services/quota_controller/transports/grpc_asyncio.py +++ b/google/cloud/servicecontrol_v1/services/quota_controller/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.servicecontrol_v1.types import quota_controller - from .base import QuotaControllerTransport, DEFAULT_CLIENT_INFO from .grpc import QuotaControllerGrpcTransport @@ -57,7 +54,7 @@ class QuotaControllerGrpcAsyncIOTransport(QuotaControllerTransport): def create_channel( cls, host: str = "servicecontrol.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, @@ -84,13 +81,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, ) @@ -98,7 +97,7 @@ def __init__( self, *, host: str = "servicecontrol.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, @@ -112,7 +111,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 @@ -170,7 +170,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/servicecontrol_v1/services/service_controller/__init__.py b/google/cloud/servicecontrol_v1/services/service_controller/__init__.py index 0867e5d..955da28 100644 --- a/google/cloud/servicecontrol_v1/services/service_controller/__init__.py +++ b/google/cloud/servicecontrol_v1/services/service_controller/__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 ServiceControllerClient from .async_client import ServiceControllerAsyncClient diff --git a/google/cloud/servicecontrol_v1/services/service_controller/async_client.py b/google/cloud/servicecontrol_v1/services/service_controller/async_client.py index 3fd9e27..a03b7d3 100644 --- a/google/cloud/servicecontrol_v1/services/service_controller/async_client.py +++ b/google/cloud/servicecontrol_v1/services/service_controller/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,15 +20,14 @@ 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.servicecontrol_v1.types import check_error from google.cloud.servicecontrol_v1.types import service_controller - from .transports.base import ServiceControllerTransport, DEFAULT_CLIENT_INFO from .transports.grpc_asyncio import ServiceControllerGrpcAsyncIOTransport from .client import ServiceControllerClient @@ -55,24 +52,20 @@ class ServiceControllerAsyncClient: parse_common_billing_account_path = staticmethod( ServiceControllerClient.parse_common_billing_account_path ) - common_folder_path = staticmethod(ServiceControllerClient.common_folder_path) parse_common_folder_path = staticmethod( ServiceControllerClient.parse_common_folder_path ) - common_organization_path = staticmethod( ServiceControllerClient.common_organization_path ) parse_common_organization_path = staticmethod( ServiceControllerClient.parse_common_organization_path ) - common_project_path = staticmethod(ServiceControllerClient.common_project_path) parse_common_project_path = staticmethod( ServiceControllerClient.parse_common_project_path ) - common_location_path = staticmethod(ServiceControllerClient.common_location_path) parse_common_location_path = staticmethod( ServiceControllerClient.parse_common_location_path @@ -80,7 +73,8 @@ class ServiceControllerAsyncClient: @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. @@ -95,7 +89,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 @@ -112,7 +106,7 @@ def from_service_account_file(cls, filename: str, *args, **kwargs): @property def transport(self) -> ServiceControllerTransport: - """Return the transport used by the client instance. + """Returns the transport used by the client instance. Returns: ServiceControllerTransport: The transport used by the client instance. @@ -126,12 +120,12 @@ def transport(self) -> ServiceControllerTransport: def __init__( self, *, - credentials: credentials.Credentials = None, + credentials: ga_credentials.Credentials = None, transport: Union[str, ServiceControllerTransport] = "grpc_asyncio", client_options: ClientOptions = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: - """Instantiate the service controller client. + """Instantiates the service controller client. Args: credentials (Optional[google.auth.credentials.Credentials]): The @@ -163,7 +157,6 @@ def __init__( google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport creation failed for any reason. """ - self._client = ServiceControllerClient( credentials=credentials, transport=transport, @@ -203,7 +196,6 @@ async def check( request (:class:`google.cloud.servicecontrol_v1.types.CheckRequest`): The request object. Request message for the Check method. - retry (google.api_core.retry.Retry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. @@ -217,7 +209,6 @@ async def check( """ # Create or coerce a protobuf request object. - request = service_controller.CheckRequest(request) # Wrap the RPC method; this adds retry and timeout information, @@ -265,7 +256,6 @@ async def report( request (:class:`google.cloud.servicecontrol_v1.types.ReportRequest`): The request object. Request message for the Report method. - retry (google.api_core.retry.Retry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. @@ -279,7 +269,6 @@ async def report( """ # Create or coerce a protobuf request object. - request = service_controller.ReportRequest(request) # Wrap the RPC method; this adds retry and timeout information, diff --git a/google/cloud/servicecontrol_v1/services/service_controller/client.py b/google/cloud/servicecontrol_v1/services/service_controller/client.py index 014b96a..b1a6c4a 100644 --- a/google/cloud/servicecontrol_v1/services/service_controller/client.py +++ b/google/cloud/servicecontrol_v1/services/service_controller/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,10 +21,10 @@ 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 @@ -34,7 +32,6 @@ from google.cloud.servicecontrol_v1.types import check_error from google.cloud.servicecontrol_v1.types import service_controller - from .transports.base import ServiceControllerTransport, DEFAULT_CLIENT_INFO from .transports.grpc import ServiceControllerGrpcTransport from .transports.grpc_asyncio import ServiceControllerGrpcAsyncIOTransport @@ -57,7 +54,7 @@ class ServiceControllerClientMeta(type): def get_transport_class( cls, label: str = None, ) -> Type[ServiceControllerTransport]: - """Return an appropriate transport class. + """Returns an appropriate transport class. Args: label: The name of the desired transport. If none is @@ -85,7 +82,8 @@ class ServiceControllerClient(metaclass=ServiceControllerClientMeta): @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: @@ -119,7 +117,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. @@ -136,7 +135,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 @@ -155,16 +154,17 @@ def from_service_account_file(cls, filename: str, *args, **kwargs): @property def transport(self) -> ServiceControllerTransport: - """Return the transport used by the client instance. + """Returns the transport used by the client instance. Returns: - ServiceControllerTransport: The transport used by the client instance. + ServiceControllerTransport: 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, ) @@ -177,7 +177,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 @@ -188,7 +188,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 @@ -199,7 +199,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 @@ -210,7 +210,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, ) @@ -224,12 +224,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, ServiceControllerTransport, None] = None, client_options: Optional[client_options_lib.ClientOptions] = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: - """Instantiate the service controller client. + """Instantiates the service controller client. Args: credentials (Optional[google.auth.credentials.Credentials]): The @@ -284,9 +284,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: @@ -298,12 +299,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. @@ -318,8 +321,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: @@ -366,7 +369,6 @@ def check( request (google.cloud.servicecontrol_v1.types.CheckRequest): The request object. Request message for the Check method. - retry (google.api_core.retry.Retry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. @@ -380,7 +382,6 @@ def check( """ # Create or coerce a protobuf request object. - # Minor optimization to avoid making a copy if the user passes # in a service_controller.CheckRequest. # There's no risk of modifying the input as we've already verified @@ -429,7 +430,6 @@ def report( request (google.cloud.servicecontrol_v1.types.ReportRequest): The request object. Request message for the Report method. - retry (google.api_core.retry.Retry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. @@ -443,7 +443,6 @@ def report( """ # Create or coerce a protobuf request object. - # Minor optimization to avoid making a copy if the user passes # in a service_controller.ReportRequest. # There's no risk of modifying the input as we've already verified diff --git a/google/cloud/servicecontrol_v1/services/service_controller/transports/__init__.py b/google/cloud/servicecontrol_v1/services/service_controller/transports/__init__.py index 33584ff..1be8f8c 100644 --- a/google/cloud/servicecontrol_v1/services/service_controller/transports/__init__.py +++ b/google/cloud/servicecontrol_v1/services/service_controller/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/servicecontrol_v1/services/service_controller/transports/base.py b/google/cloud/servicecontrol_v1/services/service_controller/transports/base.py index 8afce73..bc31de5 100644 --- a/google/cloud/servicecontrol_v1/services/service_controller/transports/base.py +++ b/google/cloud/servicecontrol_v1/services/service_controller/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.servicecontrol_v1.types import service_controller - try: DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( gapic_version=pkg_resources.get_distribution( @@ -37,6 +36,17 @@ 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 ServiceControllerTransport(abc.ABC): """Abstract transport class for ServiceController.""" @@ -46,21 +56,24 @@ class ServiceControllerTransport(abc.ABC): "https://www.googleapis.com/auth/servicecontrol", ) + DEFAULT_HOST: str = "servicecontrol.googleapis.com" + def __init__( self, *, - host: str = "servicecontrol.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 @@ -69,7 +82,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): @@ -83,29 +96,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 = { @@ -120,11 +180,11 @@ def _prep_wrapped_messages(self, client_info): @property def check( self, - ) -> typing.Callable[ + ) -> Callable[ [service_controller.CheckRequest], - typing.Union[ + Union[ service_controller.CheckResponse, - typing.Awaitable[service_controller.CheckResponse], + Awaitable[service_controller.CheckResponse], ], ]: raise NotImplementedError() @@ -132,11 +192,11 @@ def check( @property def report( self, - ) -> typing.Callable[ + ) -> Callable[ [service_controller.ReportRequest], - typing.Union[ + Union[ service_controller.ReportResponse, - typing.Awaitable[service_controller.ReportResponse], + Awaitable[service_controller.ReportResponse], ], ]: raise NotImplementedError() diff --git a/google/cloud/servicecontrol_v1/services/service_controller/transports/grpc.py b/google/cloud/servicecontrol_v1/services/service_controller/transports/grpc.py index 0e0a289..464aa92 100644 --- a/google/cloud/servicecontrol_v1/services/service_controller/transports/grpc.py +++ b/google/cloud/servicecontrol_v1/services/service_controller/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.servicecontrol_v1.types import service_controller - from .base import ServiceControllerTransport, DEFAULT_CLIENT_INFO @@ -54,7 +51,7 @@ def __init__( self, *, host: str = "servicecontrol.googleapis.com", - credentials: credentials.Credentials = None, + credentials: ga_credentials.Credentials = None, credentials_file: str = None, scopes: Sequence[str] = None, channel: grpc.Channel = None, @@ -68,7 +65,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 @@ -178,7 +176,7 @@ def __init__( def create_channel( cls, host: str = "servicecontrol.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, @@ -209,13 +207,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/servicecontrol_v1/services/service_controller/transports/grpc_asyncio.py b/google/cloud/servicecontrol_v1/services/service_controller/transports/grpc_asyncio.py index 70caee2..bcc9359 100644 --- a/google/cloud/servicecontrol_v1/services/service_controller/transports/grpc_asyncio.py +++ b/google/cloud/servicecontrol_v1/services/service_controller/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.servicecontrol_v1.types import service_controller - from .base import ServiceControllerTransport, DEFAULT_CLIENT_INFO from .grpc import ServiceControllerGrpcTransport @@ -57,7 +54,7 @@ class ServiceControllerGrpcAsyncIOTransport(ServiceControllerTransport): def create_channel( cls, host: str = "servicecontrol.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, @@ -84,13 +81,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, ) @@ -98,7 +97,7 @@ def __init__( self, *, host: str = "servicecontrol.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, @@ -112,7 +111,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 @@ -170,7 +170,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/servicecontrol_v1/types/__init__.py b/google/cloud/servicecontrol_v1/types/__init__.py index 79e0328..82e29a3 100644 --- a/google/cloud/servicecontrol_v1/types/__init__.py +++ b/google/cloud/servicecontrol_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 .check_error import CheckError from .distribution import Distribution from .http_request import HttpRequest diff --git a/google/cloud/servicecontrol_v1/types/check_error.py b/google/cloud/servicecontrol_v1/types/check_error.py index e8f93a8..b8baeb8 100644 --- a/google/cloud/servicecontrol_v1/types/check_error.py +++ b/google/cloud/servicecontrol_v1/types/check_error.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- - # Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,11 +13,9 @@ # See the License for the specific language governing permissions and # limitations under the License. # - import proto # type: ignore - -from google.rpc import status_pb2 as gr_status # type: ignore +from google.rpc import status_pb2 # type: ignore __protobuf__ = proto.module( @@ -74,12 +71,9 @@ class Code(proto.Enum): CLOUD_RESOURCE_MANAGER_BACKEND_UNAVAILABLE = 305 code = proto.Field(proto.ENUM, number=1, enum=Code,) - - subject = proto.Field(proto.STRING, number=4) - - detail = proto.Field(proto.STRING, number=2) - - status = proto.Field(proto.MESSAGE, number=3, message=gr_status.Status,) + subject = proto.Field(proto.STRING, number=4,) + detail = proto.Field(proto.STRING, number=2,) + status = proto.Field(proto.MESSAGE, number=3, message=status_pb2.Status,) __all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/google/cloud/servicecontrol_v1/types/distribution.py b/google/cloud/servicecontrol_v1/types/distribution.py index 1baa86e..c3791df 100644 --- a/google/cloud/servicecontrol_v1/types/distribution.py +++ b/google/cloud/servicecontrol_v1/types/distribution.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 @@ -76,7 +74,6 @@ class Distribution(proto.Message): class LinearBuckets(proto.Message): r"""Describing buckets with constant width. - Attributes: num_finite_buckets (int): The number of finite buckets. With the underflow and @@ -93,15 +90,12 @@ class LinearBuckets(proto.Message): num_finite_buckets, inclusive. """ - num_finite_buckets = proto.Field(proto.INT32, number=1) - - width = proto.Field(proto.DOUBLE, number=2) - - offset = proto.Field(proto.DOUBLE, number=3) + num_finite_buckets = proto.Field(proto.INT32, number=1,) + width = proto.Field(proto.DOUBLE, number=2,) + offset = proto.Field(proto.DOUBLE, number=3,) class ExponentialBuckets(proto.Message): r"""Describing buckets with exponentially growing width. - Attributes: num_finite_buckets (int): The number of finite buckets. With the underflow and @@ -119,15 +113,12 @@ class ExponentialBuckets(proto.Message): ranges from 1 to num_finite_buckets inclusive. Must be > 0. """ - num_finite_buckets = proto.Field(proto.INT32, number=1) - - growth_factor = proto.Field(proto.DOUBLE, number=2) - - scale = proto.Field(proto.DOUBLE, number=3) + num_finite_buckets = proto.Field(proto.INT32, number=1,) + growth_factor = proto.Field(proto.DOUBLE, number=2,) + scale = proto.Field(proto.DOUBLE, number=3,) class ExplicitBuckets(proto.Message): r"""Describing buckets with arbitrary user-provided width. - Attributes: bounds (Sequence[float]): 'bound' is a list of strictly increasing boundaries between @@ -147,28 +138,20 @@ class ExplicitBuckets(proto.Message): bound_size() (overflow) bound[i-1] +inf """ - bounds = proto.RepeatedField(proto.DOUBLE, number=1) - - count = proto.Field(proto.INT64, number=1) - - mean = proto.Field(proto.DOUBLE, number=2) - - minimum = proto.Field(proto.DOUBLE, number=3) - - maximum = proto.Field(proto.DOUBLE, number=4) - - sum_of_squared_deviation = proto.Field(proto.DOUBLE, number=5) - - bucket_counts = proto.RepeatedField(proto.INT64, number=6) + bounds = proto.RepeatedField(proto.DOUBLE, number=1,) + count = proto.Field(proto.INT64, number=1,) + mean = proto.Field(proto.DOUBLE, number=2,) + minimum = proto.Field(proto.DOUBLE, number=3,) + maximum = proto.Field(proto.DOUBLE, number=4,) + sum_of_squared_deviation = proto.Field(proto.DOUBLE, number=5,) + bucket_counts = proto.RepeatedField(proto.INT64, number=6,) linear_buckets = proto.Field( proto.MESSAGE, number=7, oneof="bucket_option", message=LinearBuckets, ) - exponential_buckets = proto.Field( proto.MESSAGE, number=8, oneof="bucket_option", message=ExponentialBuckets, ) - explicit_buckets = proto.Field( proto.MESSAGE, number=9, oneof="bucket_option", message=ExplicitBuckets, ) diff --git a/google/cloud/servicecontrol_v1/types/http_request.py b/google/cloud/servicecontrol_v1/types/http_request.py index 8f97b15..53374bb 100644 --- a/google/cloud/servicecontrol_v1/types/http_request.py +++ b/google/cloud/servicecontrol_v1/types/http_request.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- - # Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,11 +13,9 @@ # See the License for the specific language governing permissions and # limitations under the License. # - import proto # type: ignore - -from google.protobuf import duration_pb2 as duration # type: ignore +from google.protobuf import duration_pb2 # type: ignore __protobuf__ = proto.module( @@ -86,35 +83,21 @@ class HttpRequest(proto.Message): "HTTP/1.1", "HTTP/2", "websocket". """ - request_method = proto.Field(proto.STRING, number=1) - - request_url = proto.Field(proto.STRING, number=2) - - request_size = proto.Field(proto.INT64, number=3) - - status = proto.Field(proto.INT32, number=4) - - response_size = proto.Field(proto.INT64, number=5) - - user_agent = proto.Field(proto.STRING, number=6) - - remote_ip = proto.Field(proto.STRING, number=7) - - server_ip = proto.Field(proto.STRING, number=13) - - referer = proto.Field(proto.STRING, number=8) - - latency = proto.Field(proto.MESSAGE, number=14, message=duration.Duration,) - - cache_lookup = proto.Field(proto.BOOL, number=11) - - cache_hit = proto.Field(proto.BOOL, number=9) - - cache_validated_with_origin_server = proto.Field(proto.BOOL, number=10) - - cache_fill_bytes = proto.Field(proto.INT64, number=12) - - protocol = proto.Field(proto.STRING, number=15) + request_method = proto.Field(proto.STRING, number=1,) + request_url = proto.Field(proto.STRING, number=2,) + request_size = proto.Field(proto.INT64, number=3,) + status = proto.Field(proto.INT32, number=4,) + response_size = proto.Field(proto.INT64, number=5,) + user_agent = proto.Field(proto.STRING, number=6,) + remote_ip = proto.Field(proto.STRING, number=7,) + server_ip = proto.Field(proto.STRING, number=13,) + referer = proto.Field(proto.STRING, number=8,) + latency = proto.Field(proto.MESSAGE, number=14, message=duration_pb2.Duration,) + cache_lookup = proto.Field(proto.BOOL, number=11,) + cache_hit = proto.Field(proto.BOOL, number=9,) + cache_validated_with_origin_server = proto.Field(proto.BOOL, number=10,) + cache_fill_bytes = proto.Field(proto.INT64, number=12,) + protocol = proto.Field(proto.STRING, number=15,) __all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/google/cloud/servicecontrol_v1/types/log_entry.py b/google/cloud/servicecontrol_v1/types/log_entry.py index 09df2ea..80ca9c6 100644 --- a/google/cloud/servicecontrol_v1/types/log_entry.py +++ b/google/cloud/servicecontrol_v1/types/log_entry.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- - # Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,15 +13,13 @@ # See the License for the specific language governing permissions and # limitations under the License. # - import proto # type: ignore - from google.cloud.servicecontrol_v1.types import http_request as gas_http_request -from google.logging.type import log_severity_pb2 as log_severity # type: ignore -from google.protobuf import any_pb2 as gp_any # type: ignore -from google.protobuf import struct_pb2 as struct # type: ignore -from google.protobuf import timestamp_pb2 as gp_timestamp # type: ignore +from google.logging.type import log_severity_pb2 # type: ignore +from google.protobuf import any_pb2 # type: ignore +from google.protobuf import struct_pb2 # type: ignore +from google.protobuf import timestamp_pb2 # type: ignore __protobuf__ = proto.module( @@ -33,7 +30,6 @@ class LogEntry(proto.Message): r"""An individual log entry. - Attributes: name (str): Required. The log to which this log entry belongs. Examples: @@ -80,34 +76,23 @@ class LogEntry(proto.Message): associated with the log entry, if any. """ - name = proto.Field(proto.STRING, number=10) - - timestamp = proto.Field(proto.MESSAGE, number=11, message=gp_timestamp.Timestamp,) - - severity = proto.Field(proto.ENUM, number=12, enum=log_severity.LogSeverity,) - + name = proto.Field(proto.STRING, number=10,) + timestamp = proto.Field(proto.MESSAGE, number=11, message=timestamp_pb2.Timestamp,) + severity = proto.Field(proto.ENUM, number=12, enum=log_severity_pb2.LogSeverity,) http_request = proto.Field( proto.MESSAGE, number=14, message=gas_http_request.HttpRequest, ) - - trace = proto.Field(proto.STRING, number=15) - - insert_id = proto.Field(proto.STRING, number=4) - - labels = proto.MapField(proto.STRING, proto.STRING, number=13) - + trace = proto.Field(proto.STRING, number=15,) + insert_id = proto.Field(proto.STRING, number=4,) + labels = proto.MapField(proto.STRING, proto.STRING, number=13,) proto_payload = proto.Field( - proto.MESSAGE, number=2, oneof="payload", message=gp_any.Any, + proto.MESSAGE, number=2, oneof="payload", message=any_pb2.Any, ) - - text_payload = proto.Field(proto.STRING, number=3, oneof="payload") - + text_payload = proto.Field(proto.STRING, number=3, oneof="payload",) struct_payload = proto.Field( - proto.MESSAGE, number=6, oneof="payload", message=struct.Struct, + proto.MESSAGE, number=6, oneof="payload", message=struct_pb2.Struct, ) - operation = proto.Field(proto.MESSAGE, number=16, message="LogEntryOperation",) - source_location = proto.Field( proto.MESSAGE, number=17, message="LogEntrySourceLocation", ) @@ -135,13 +120,10 @@ class LogEntryOperation(proto.Message): last log entry in the operation. """ - id = proto.Field(proto.STRING, number=1) - - producer = proto.Field(proto.STRING, number=2) - - first = proto.Field(proto.BOOL, number=3) - - last = proto.Field(proto.BOOL, number=4) + id = proto.Field(proto.STRING, number=1,) + producer = proto.Field(proto.STRING, number=2,) + first = proto.Field(proto.BOOL, number=3,) + last = proto.Field(proto.BOOL, number=4,) class LogEntrySourceLocation(proto.Message): @@ -166,11 +148,9 @@ class LogEntrySourceLocation(proto.Message): (Go), ``function`` (Python). """ - file = proto.Field(proto.STRING, number=1) - - line = proto.Field(proto.INT64, number=2) - - function = proto.Field(proto.STRING, number=3) + file = proto.Field(proto.STRING, number=1,) + line = proto.Field(proto.INT64, number=2,) + function = proto.Field(proto.STRING, number=3,) __all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/google/cloud/servicecontrol_v1/types/metric_value.py b/google/cloud/servicecontrol_v1/types/metric_value.py index b457f98..c679029 100644 --- a/google/cloud/servicecontrol_v1/types/metric_value.py +++ b/google/cloud/servicecontrol_v1/types/metric_value.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- - # Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,12 +13,10 @@ # See the License for the specific language governing permissions and # limitations under the License. # - import proto # type: ignore - from google.cloud.servicecontrol_v1.types import distribution -from google.protobuf import timestamp_pb2 as timestamp # type: ignore +from google.protobuf import timestamp_pb2 # type: ignore __protobuf__ = proto.module( @@ -29,7 +26,6 @@ class MetricValue(proto.Message): r"""Represents a single metric value. - Attributes: labels (Sequence[google.cloud.servicecontrol_v1.types.MetricValue.LabelsEntry]): The labels describing the metric value. See comments on @@ -58,20 +54,13 @@ class MetricValue(proto.Message): A distribution value. """ - labels = proto.MapField(proto.STRING, proto.STRING, number=1) - - start_time = proto.Field(proto.MESSAGE, number=2, message=timestamp.Timestamp,) - - end_time = proto.Field(proto.MESSAGE, number=3, message=timestamp.Timestamp,) - - bool_value = proto.Field(proto.BOOL, number=4, oneof="value") - - int64_value = proto.Field(proto.INT64, number=5, oneof="value") - - double_value = proto.Field(proto.DOUBLE, number=6, oneof="value") - - string_value = proto.Field(proto.STRING, number=7, oneof="value") - + labels = proto.MapField(proto.STRING, proto.STRING, number=1,) + start_time = proto.Field(proto.MESSAGE, number=2, message=timestamp_pb2.Timestamp,) + end_time = proto.Field(proto.MESSAGE, number=3, message=timestamp_pb2.Timestamp,) + bool_value = proto.Field(proto.BOOL, number=4, oneof="value",) + int64_value = proto.Field(proto.INT64, number=5, oneof="value",) + double_value = proto.Field(proto.DOUBLE, number=6, oneof="value",) + string_value = proto.Field(proto.STRING, number=7, oneof="value",) distribution_value = proto.Field( proto.MESSAGE, number=8, oneof="value", message=distribution.Distribution, ) @@ -90,8 +79,7 @@ class MetricValueSet(proto.Message): The values in this metric. """ - metric_name = proto.Field(proto.STRING, number=1) - + metric_name = proto.Field(proto.STRING, number=1,) metric_values = proto.RepeatedField(proto.MESSAGE, number=2, message="MetricValue",) diff --git a/google/cloud/servicecontrol_v1/types/operation.py b/google/cloud/servicecontrol_v1/types/operation.py index cbecd4b..69d55c3 100644 --- a/google/cloud/servicecontrol_v1/types/operation.py +++ b/google/cloud/servicecontrol_v1/types/operation.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- - # Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,14 +13,12 @@ # See the License for the specific language governing permissions and # limitations under the License. # - import proto # type: ignore - from google.cloud.servicecontrol_v1.types import log_entry from google.cloud.servicecontrol_v1.types import metric_value -from google.protobuf import any_pb2 as gp_any # type: ignore -from google.protobuf import timestamp_pb2 as timestamp # type: ignore +from google.protobuf import any_pb2 # type: ignore +from google.protobuf import timestamp_pb2 # type: ignore __protobuf__ = proto.module( @@ -31,7 +28,6 @@ class Operation(proto.Message): r"""Represents information regarding an operation. - Attributes: operation_id (str): Identity of the operation. This must be @@ -120,29 +116,20 @@ class Importance(proto.Enum): LOW = 0 HIGH = 1 - operation_id = proto.Field(proto.STRING, number=1) - - operation_name = proto.Field(proto.STRING, number=2) - - consumer_id = proto.Field(proto.STRING, number=3) - - start_time = proto.Field(proto.MESSAGE, number=4, message=timestamp.Timestamp,) - - end_time = proto.Field(proto.MESSAGE, number=5, message=timestamp.Timestamp,) - - labels = proto.MapField(proto.STRING, proto.STRING, number=6) - + operation_id = proto.Field(proto.STRING, number=1,) + operation_name = proto.Field(proto.STRING, number=2,) + consumer_id = proto.Field(proto.STRING, number=3,) + start_time = proto.Field(proto.MESSAGE, number=4, message=timestamp_pb2.Timestamp,) + end_time = proto.Field(proto.MESSAGE, number=5, message=timestamp_pb2.Timestamp,) + labels = proto.MapField(proto.STRING, proto.STRING, number=6,) metric_value_sets = proto.RepeatedField( proto.MESSAGE, number=7, message=metric_value.MetricValueSet, ) - log_entries = proto.RepeatedField( proto.MESSAGE, number=8, message=log_entry.LogEntry, ) - importance = proto.Field(proto.ENUM, number=11, enum=Importance,) - - extensions = proto.RepeatedField(proto.MESSAGE, number=16, message=gp_any.Any,) + extensions = proto.RepeatedField(proto.MESSAGE, number=16, message=any_pb2.Any,) __all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/google/cloud/servicecontrol_v1/types/quota_controller.py b/google/cloud/servicecontrol_v1/types/quota_controller.py index cfa731c..db2c7b1 100644 --- a/google/cloud/servicecontrol_v1/types/quota_controller.py +++ b/google/cloud/servicecontrol_v1/types/quota_controller.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- - # Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,10 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # - import proto # type: ignore - from google.cloud.servicecontrol_v1.types import metric_value @@ -34,7 +31,6 @@ class AllocateQuotaRequest(proto.Message): r"""Request message for the AllocateQuota method. - Attributes: service_name (str): Name of the service as specified in the service @@ -52,16 +48,13 @@ class AllocateQuotaRequest(proto.Message): can be found, the latest one will be used. """ - service_name = proto.Field(proto.STRING, number=1) - + service_name = proto.Field(proto.STRING, number=1,) allocate_operation = proto.Field(proto.MESSAGE, number=2, message="QuotaOperation",) - - service_config_id = proto.Field(proto.STRING, number=4) + service_config_id = proto.Field(proto.STRING, number=4,) class QuotaOperation(proto.Message): r"""Represents information regarding a quota operation. - Attributes: operation_id (str): Identity of the operation. This is expected to be unique @@ -122,24 +115,18 @@ class QuotaMode(proto.Enum): QUERY_ONLY = 4 ADJUST_ONLY = 5 - operation_id = proto.Field(proto.STRING, number=1) - - method_name = proto.Field(proto.STRING, number=2) - - consumer_id = proto.Field(proto.STRING, number=3) - - labels = proto.MapField(proto.STRING, proto.STRING, number=4) - + operation_id = proto.Field(proto.STRING, number=1,) + method_name = proto.Field(proto.STRING, number=2,) + consumer_id = proto.Field(proto.STRING, number=3,) + labels = proto.MapField(proto.STRING, proto.STRING, number=4,) quota_metrics = proto.RepeatedField( proto.MESSAGE, number=5, message=metric_value.MetricValueSet, ) - quota_mode = proto.Field(proto.ENUM, number=6, enum=QuotaMode,) class AllocateQuotaResponse(proto.Message): r"""Response message for the AllocateQuota method. - Attributes: operation_id (str): The same operation_id value used in the @@ -164,17 +151,14 @@ class AllocateQuotaResponse(proto.Message): request. """ - operation_id = proto.Field(proto.STRING, number=1) - + operation_id = proto.Field(proto.STRING, number=1,) allocate_errors = proto.RepeatedField( proto.MESSAGE, number=2, message="QuotaError", ) - quota_metrics = proto.RepeatedField( proto.MESSAGE, number=3, message=metric_value.MetricValueSet, ) - - service_config_id = proto.Field(proto.STRING, number=4) + service_config_id = proto.Field(proto.STRING, number=4,) class QuotaError(proto.Message): @@ -210,10 +194,8 @@ class Code(proto.Enum): API_KEY_EXPIRED = 112 code = proto.Field(proto.ENUM, number=1, enum=Code,) - - subject = proto.Field(proto.STRING, number=2) - - description = proto.Field(proto.STRING, number=3) + subject = proto.Field(proto.STRING, number=2,) + description = proto.Field(proto.STRING, number=3,) __all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/google/cloud/servicecontrol_v1/types/service_controller.py b/google/cloud/servicecontrol_v1/types/service_controller.py index 5f5b65b..0b2b93f 100644 --- a/google/cloud/servicecontrol_v1/types/service_controller.py +++ b/google/cloud/servicecontrol_v1/types/service_controller.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- - # Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,13 +13,11 @@ # See the License for the specific language governing permissions and # limitations under the License. # - import proto # type: ignore - from google.cloud.servicecontrol_v1.types import check_error from google.cloud.servicecontrol_v1.types import operation as gas_operation -from google.rpc import status_pb2 as gr_status # type: ignore +from google.rpc import status_pb2 # type: ignore __protobuf__ = proto.module( @@ -31,7 +28,6 @@ class CheckRequest(proto.Message): r"""Request message for the Check method. - Attributes: service_name (str): The service name as specified in its service configuration. @@ -50,16 +46,13 @@ class CheckRequest(proto.Message): found, the latest one will be used. """ - service_name = proto.Field(proto.STRING, number=1) - + service_name = proto.Field(proto.STRING, number=1,) operation = proto.Field(proto.MESSAGE, number=2, message=gas_operation.Operation,) - - service_config_id = proto.Field(proto.STRING, number=4) + service_config_id = proto.Field(proto.STRING, number=4,) class CheckResponse(proto.Message): r"""Response message for the Check method. - Attributes: operation_id (str): The same operation_id value used in the @@ -84,7 +77,6 @@ class CheckResponse(proto.Message): class CheckInfo(proto.Message): r"""Contains additional information about the check operation. - Attributes: unused_arguments (Sequence[str]): A list of fields and label keys that are @@ -95,15 +87,13 @@ class CheckInfo(proto.Message): Consumer info of this check. """ - unused_arguments = proto.RepeatedField(proto.STRING, number=1) - + unused_arguments = proto.RepeatedField(proto.STRING, number=1,) consumer_info = proto.Field( proto.MESSAGE, number=2, message="CheckResponse.ConsumerInfo", ) class ConsumerInfo(proto.Message): r"""``ConsumerInfo`` provides information about the consumer. - Attributes: project_number (int): The Google cloud project number, e.g. @@ -133,30 +123,23 @@ class ConsumerType(proto.Enum): ORGANIZATION = 3 SERVICE_SPECIFIC = 4 - project_number = proto.Field(proto.INT64, number=1) - + project_number = proto.Field(proto.INT64, number=1,) type_ = proto.Field( proto.ENUM, number=2, enum="CheckResponse.ConsumerInfo.ConsumerType", ) + consumer_number = proto.Field(proto.INT64, number=3,) - consumer_number = proto.Field(proto.INT64, number=3) - - operation_id = proto.Field(proto.STRING, number=1) - + operation_id = proto.Field(proto.STRING, number=1,) check_errors = proto.RepeatedField( proto.MESSAGE, number=2, message=check_error.CheckError, ) - - service_config_id = proto.Field(proto.STRING, number=5) - - service_rollout_id = proto.Field(proto.STRING, number=11) - + service_config_id = proto.Field(proto.STRING, number=5,) + service_rollout_id = proto.Field(proto.STRING, number=11,) check_info = proto.Field(proto.MESSAGE, number=6, message=CheckInfo,) class ReportRequest(proto.Message): r"""Request message for the Report method. - Attributes: service_name (str): The service name as specified in its service configuration. @@ -186,18 +169,15 @@ class ReportRequest(proto.Message): found, the latest one will be used. """ - service_name = proto.Field(proto.STRING, number=1) - + service_name = proto.Field(proto.STRING, number=1,) operations = proto.RepeatedField( proto.MESSAGE, number=2, message=gas_operation.Operation, ) - - service_config_id = proto.Field(proto.STRING, number=3) + service_config_id = proto.Field(proto.STRING, number=3,) class ReportResponse(proto.Message): r"""Response message for the Report method. - Attributes: report_errors (Sequence[google.cloud.servicecontrol_v1.types.ReportResponse.ReportError]): Partial failures, one for each ``Operation`` in the request @@ -238,15 +218,12 @@ class ReportError(proto.Message): [Operation][google.api.servicecontrol.v1.Operation]. """ - operation_id = proto.Field(proto.STRING, number=1) - - status = proto.Field(proto.MESSAGE, number=2, message=gr_status.Status,) + operation_id = proto.Field(proto.STRING, number=1,) + status = proto.Field(proto.MESSAGE, number=2, message=status_pb2.Status,) report_errors = proto.RepeatedField(proto.MESSAGE, number=1, message=ReportError,) - - service_config_id = proto.Field(proto.STRING, number=2) - - service_rollout_id = proto.Field(proto.STRING, number=4) + service_config_id = proto.Field(proto.STRING, number=2,) + service_rollout_id = proto.Field(proto.STRING, number=4,) __all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/scripts/fixup_servicecontrol_v1_keywords.py b/scripts/fixup_servicecontrol_v1_keywords.py index c755331..44f9056 100644 --- a/scripts/fixup_servicecontrol_v1_keywords.py +++ b/scripts/fixup_servicecontrol_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,10 +39,9 @@ def partition( class servicecontrolCallTransformer(cst.CSTTransformer): CTRL_PARAMS: Tuple[str] = ('retry', 'timeout', 'metadata') METHOD_TO_PARAMS: Dict[str, Tuple[str]] = { - 'allocate_quota': ('service_name', 'allocate_operation', 'service_config_id', ), - 'check': ('service_name', 'operation', 'service_config_id', ), - 'report': ('service_name', 'operations', 'service_config_id', ), - + 'allocate_quota': ('service_name', 'allocate_operation', 'service_config_id', ), + 'check': ('service_name', 'operation', 'service_config_id', ), + 'report': ('service_name', 'operations', 'service_config_id', ), } def leave_Call(self, original: cst.Call, updated: cst.Call) -> cst.CSTNode: @@ -75,7 +72,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 26614ee..7397e3e 100644 --- a/setup.py +++ b/setup.py @@ -28,6 +28,7 @@ "google-api-core[grpc] >= 1.22.2, < 2.0.0dev", "libcst >= 0.2.5", "proto-plus >= 1.15.0", + "packaging >= 14.3", ] package_root = os.path.abspath(os.path.dirname(__file__)) diff --git a/testing/constraints-3.6.txt b/testing/constraints-3.6.txt index 2cc407c..4947a88 100644 --- a/testing/constraints-3.6.txt +++ b/testing/constraints-3.6.txt @@ -8,3 +8,5 @@ google-api-core==1.22.2 libcst==0.2.5 proto-plus==1.15.0 +packaging==14.3 +google-auth==1.24.0 # TODO: remove when google-auth>=1.25.0 is transitively required through google-auth diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..4de6597 --- /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 0000000..4de6597 --- /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 0000000..4de6597 --- /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/servicecontrol_v1/__init__.py b/tests/unit/gapic/servicecontrol_v1/__init__.py index 42ffdf2..4de6597 100644 --- a/tests/unit/gapic/servicecontrol_v1/__init__.py +++ b/tests/unit/gapic/servicecontrol_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/servicecontrol_v1/test_quota_controller.py b/tests/unit/gapic/servicecontrol_v1/test_quota_controller.py index 0f2022f..5dbfc44 100644 --- a/tests/unit/gapic/servicecontrol_v1/test_quota_controller.py +++ b/tests/unit/gapic/servicecontrol_v1/test_quota_controller.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,13 +23,13 @@ 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.servicecontrol_v1.services.quota_controller import ( QuotaControllerAsyncClient, @@ -39,11 +38,41 @@ QuotaControllerClient, ) from google.cloud.servicecontrol_v1.services.quota_controller import transports +from google.cloud.servicecontrol_v1.services.quota_controller.transports.base import ( + _API_CORE_VERSION, +) +from google.cloud.servicecontrol_v1.services.quota_controller.transports.base import ( + _GOOGLE_AUTH_VERSION, +) from google.cloud.servicecontrol_v1.types import distribution from google.cloud.servicecontrol_v1.types import metric_value from google.cloud.servicecontrol_v1.types import quota_controller from google.oauth2 import service_account -from google.protobuf import timestamp_pb2 as timestamp # type: ignore +from google.protobuf import timestamp_pb2 # type: ignore +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(): @@ -94,7 +123,7 @@ def test__get_default_mtls_endpoint(): "client_class", [QuotaControllerClient, QuotaControllerAsyncClient,] ) def test_quota_controller_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: @@ -111,7 +140,7 @@ def test_quota_controller_client_from_service_account_info(client_class): "client_class", [QuotaControllerClient, QuotaControllerAsyncClient,] ) def test_quota_controller_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: @@ -164,7 +193,7 @@ def test_quota_controller_client_client_options( ): # Check that if channel is provided we won't create a new one. with mock.patch.object(QuotaControllerClient, "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() @@ -462,7 +491,7 @@ def test_allocate_quota( transport: str = "grpc", request_type=quota_controller.AllocateQuotaRequest ): client = QuotaControllerClient( - credentials=credentials.AnonymousCredentials(), transport=transport, + credentials=ga_credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, @@ -476,21 +505,16 @@ def test_allocate_quota( operation_id="operation_id_value", service_config_id="service_config_id_value", ) - response = client.allocate_quota(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0] == quota_controller.AllocateQuotaRequest() # Establish that the response is the type that we expect. - assert isinstance(response, quota_controller.AllocateQuotaResponse) - assert response.operation_id == "operation_id_value" - assert response.service_config_id == "service_config_id_value" @@ -502,7 +526,7 @@ def test_allocate_quota_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 = QuotaControllerClient( - credentials=credentials.AnonymousCredentials(), transport="grpc", + credentials=ga_credentials.AnonymousCredentials(), transport="grpc", ) # Mock the actual call within the gRPC stub, and fake the request. @@ -510,7 +534,6 @@ def test_allocate_quota_empty_call(): client.allocate_quota() call.assert_called() _, args, _ = call.mock_calls[0] - assert args[0] == quota_controller.AllocateQuotaRequest() @@ -519,7 +542,7 @@ async def test_allocate_quota_async( transport: str = "grpc_asyncio", request_type=quota_controller.AllocateQuotaRequest ): client = QuotaControllerAsyncClient( - credentials=credentials.AnonymousCredentials(), transport=transport, + credentials=ga_credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, @@ -535,20 +558,16 @@ async def test_allocate_quota_async( service_config_id="service_config_id_value", ) ) - response = await client.allocate_quota(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0] == quota_controller.AllocateQuotaRequest() # Establish that the response is the type that we expect. assert isinstance(response, quota_controller.AllocateQuotaResponse) - assert response.operation_id == "operation_id_value" - assert response.service_config_id == "service_config_id_value" @@ -560,16 +579,16 @@ async def test_allocate_quota_async_from_dict(): def test_credentials_transport_error(): # It is an error to provide credentials and a transport instance. transport = transports.QuotaControllerGrpcTransport( - credentials=credentials.AnonymousCredentials(), + credentials=ga_credentials.AnonymousCredentials(), ) with pytest.raises(ValueError): client = QuotaControllerClient( - 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.QuotaControllerGrpcTransport( - credentials=credentials.AnonymousCredentials(), + credentials=ga_credentials.AnonymousCredentials(), ) with pytest.raises(ValueError): client = QuotaControllerClient( @@ -579,7 +598,7 @@ def test_credentials_transport_error(): # It is an error to provide scopes and a transport instance. transport = transports.QuotaControllerGrpcTransport( - credentials=credentials.AnonymousCredentials(), + credentials=ga_credentials.AnonymousCredentials(), ) with pytest.raises(ValueError): client = QuotaControllerClient( @@ -590,7 +609,7 @@ def test_credentials_transport_error(): def test_transport_instance(): # A client may be instantiated with a custom transport instance. transport = transports.QuotaControllerGrpcTransport( - credentials=credentials.AnonymousCredentials(), + credentials=ga_credentials.AnonymousCredentials(), ) client = QuotaControllerClient(transport=transport) assert client.transport is transport @@ -599,13 +618,13 @@ def test_transport_instance(): def test_transport_get_channel(): # A client may be instantiated with a custom transport instance. transport = transports.QuotaControllerGrpcTransport( - credentials=credentials.AnonymousCredentials(), + credentials=ga_credentials.AnonymousCredentials(), ) channel = transport.grpc_channel assert channel transport = transports.QuotaControllerGrpcAsyncIOTransport( - credentials=credentials.AnonymousCredentials(), + credentials=ga_credentials.AnonymousCredentials(), ) channel = transport.grpc_channel assert channel @@ -620,23 +639,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 = QuotaControllerClient(credentials=credentials.AnonymousCredentials(),) + client = QuotaControllerClient(credentials=ga_credentials.AnonymousCredentials(),) assert isinstance(client.transport, transports.QuotaControllerGrpcTransport,) def test_quota_controller_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.QuotaControllerTransport( - credentials=credentials.AnonymousCredentials(), + credentials=ga_credentials.AnonymousCredentials(), credentials_file="credentials.json", ) @@ -648,7 +667,7 @@ def test_quota_controller_base_transport(): ) as Transport: Transport.return_value = None transport = transports.QuotaControllerTransport( - credentials=credentials.AnonymousCredentials(), + credentials=ga_credentials.AnonymousCredentials(), ) # Every method on the transport should just blindly @@ -659,15 +678,40 @@ def test_quota_controller_base_transport(): getattr(transport, method)(request=object()) +@requires_google_auth_gte_1_25_0 def test_quota_controller_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.servicecontrol_v1.services.quota_controller.transports.QuotaControllerTransport._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.QuotaControllerTransport( + 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", + "https://www.googleapis.com/auth/servicecontrol", + ), + quota_project_id="octopus", + ) + + +@requires_google_auth_lt_1_25_0 +def test_quota_controller_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.servicecontrol_v1.services.quota_controller.transports.QuotaControllerTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) transport = transports.QuotaControllerTransport( credentials_file="credentials.json", quota_project_id="octopus", ) @@ -683,19 +727,36 @@ def test_quota_controller_base_transport_with_credentials_file(): def test_quota_controller_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.servicecontrol_v1.services.quota_controller.transports.QuotaControllerTransport._prep_wrapped_messages" ) as Transport: Transport.return_value = None - adc.return_value = (credentials.AnonymousCredentials(), None) + adc.return_value = (ga_credentials.AnonymousCredentials(), None) transport = transports.QuotaControllerTransport() adc.assert_called_once() +@requires_google_auth_gte_1_25_0 def test_quota_controller_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) + QuotaControllerClient() + adc.assert_called_once_with( + scopes=None, + default_scopes=( + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/servicecontrol", + ), + quota_project_id=None, + ) + + +@requires_google_auth_lt_1_25_0 +def test_quota_controller_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) QuotaControllerClient() adc.assert_called_once_with( scopes=( @@ -706,14 +767,44 @@ def test_quota_controller_auth_adc(): ) -def test_quota_controller_transport_auth_adc(): +@pytest.mark.parametrize( + "transport_class", + [ + transports.QuotaControllerGrpcTransport, + transports.QuotaControllerGrpcAsyncIOTransport, + ], +) +@requires_google_auth_gte_1_25_0 +def test_quota_controller_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.QuotaControllerGrpcTransport( - 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", + "https://www.googleapis.com/auth/servicecontrol", + ), + quota_project_id="octopus", ) + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.QuotaControllerGrpcTransport, + transports.QuotaControllerGrpcAsyncIOTransport, + ], +) +@requires_google_auth_lt_1_25_0 +def test_quota_controller_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", @@ -723,6 +814,121 @@ def test_quota_controller_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class,grpc_helpers", + [ + (transports.QuotaControllerGrpcTransport, grpc_helpers), + (transports.QuotaControllerGrpcAsyncIOTransport, grpc_helpers_async), + ], +) +@requires_api_core_gte_1_26_0 +def test_quota_controller_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( + "servicecontrol.googleapis.com:443", + credentials=creds, + credentials_file=None, + quota_project_id="octopus", + default_scopes=( + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/servicecontrol", + ), + scopes=["1", "2"], + default_host="servicecontrol.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.QuotaControllerGrpcTransport, grpc_helpers), + (transports.QuotaControllerGrpcAsyncIOTransport, grpc_helpers_async), + ], +) +@requires_api_core_lt_1_26_0 +def test_quota_controller_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( + "servicecontrol.googleapis.com:443", + credentials=creds, + credentials_file=None, + quota_project_id="octopus", + scopes=( + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/servicecontrol", + ), + ssl_credentials=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + +@pytest.mark.parametrize( + "transport_class,grpc_helpers", + [ + (transports.QuotaControllerGrpcTransport, grpc_helpers), + (transports.QuotaControllerGrpcAsyncIOTransport, grpc_helpers_async), + ], +) +@requires_api_core_lt_1_26_0 +def test_quota_controller_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( + "servicecontrol.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", [ @@ -731,7 +937,7 @@ def test_quota_controller_transport_auth_adc(): ], ) def test_quota_controller_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: @@ -773,7 +979,7 @@ def test_quota_controller_grpc_transport_client_cert_source_for_mtls(transport_c def test_quota_controller_host_no_port(): client = QuotaControllerClient( - credentials=credentials.AnonymousCredentials(), + credentials=ga_credentials.AnonymousCredentials(), client_options=client_options.ClientOptions( api_endpoint="servicecontrol.googleapis.com" ), @@ -783,7 +989,7 @@ def test_quota_controller_host_no_port(): def test_quota_controller_host_with_port(): client = QuotaControllerClient( - credentials=credentials.AnonymousCredentials(), + credentials=ga_credentials.AnonymousCredentials(), client_options=client_options.ClientOptions( api_endpoint="servicecontrol.googleapis.com:8000" ), @@ -839,9 +1045,9 @@ def test_quota_controller_transport_channel_mtls_with_client_cert_source( 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", @@ -923,7 +1129,6 @@ def test_quota_controller_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, ) @@ -944,7 +1149,6 @@ def test_parse_common_billing_account_path(): def test_common_folder_path(): folder = "whelk" - expected = "folders/{folder}".format(folder=folder,) actual = QuotaControllerClient.common_folder_path(folder) assert expected == actual @@ -963,7 +1167,6 @@ def test_parse_common_folder_path(): def test_common_organization_path(): organization = "oyster" - expected = "organizations/{organization}".format(organization=organization,) actual = QuotaControllerClient.common_organization_path(organization) assert expected == actual @@ -982,7 +1185,6 @@ def test_parse_common_organization_path(): def test_common_project_path(): project = "cuttlefish" - expected = "projects/{project}".format(project=project,) actual = QuotaControllerClient.common_project_path(project) assert expected == actual @@ -1002,7 +1204,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, ) @@ -1029,7 +1230,7 @@ def test_client_withDEFAULT_CLIENT_INFO(): transports.QuotaControllerTransport, "_prep_wrapped_messages" ) as prep: client = QuotaControllerClient( - credentials=credentials.AnonymousCredentials(), client_info=client_info, + credentials=ga_credentials.AnonymousCredentials(), client_info=client_info, ) prep.assert_called_once_with(client_info) @@ -1038,6 +1239,6 @@ def test_client_withDEFAULT_CLIENT_INFO(): ) as prep: transport_class = QuotaControllerClient.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/servicecontrol_v1/test_service_controller.py b/tests/unit/gapic/servicecontrol_v1/test_service_controller.py index f79a829..66e6323 100644 --- a/tests/unit/gapic/servicecontrol_v1/test_service_controller.py +++ b/tests/unit/gapic/servicecontrol_v1/test_service_controller.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,13 +23,13 @@ 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.servicecontrol_v1.services.service_controller import ( ServiceControllerAsyncClient, @@ -39,6 +38,12 @@ ServiceControllerClient, ) from google.cloud.servicecontrol_v1.services.service_controller import transports +from google.cloud.servicecontrol_v1.services.service_controller.transports.base import ( + _API_CORE_VERSION, +) +from google.cloud.servicecontrol_v1.services.service_controller.transports.base import ( + _GOOGLE_AUTH_VERSION, +) from google.cloud.servicecontrol_v1.types import check_error from google.cloud.servicecontrol_v1.types import distribution from google.cloud.servicecontrol_v1.types import http_request @@ -46,12 +51,36 @@ from google.cloud.servicecontrol_v1.types import metric_value from google.cloud.servicecontrol_v1.types import operation from google.cloud.servicecontrol_v1.types import service_controller -from google.logging.type import log_severity_pb2 as log_severity # type: ignore +from google.logging.type import log_severity_pb2 # type: ignore from google.oauth2 import service_account -from google.protobuf import any_pb2 as gp_any # type: ignore -from google.protobuf import duration_pb2 as duration # type: ignore -from google.protobuf import struct_pb2 as struct # type: ignore -from google.protobuf import timestamp_pb2 as timestamp # type: ignore +from google.protobuf import any_pb2 # type: ignore +from google.protobuf import duration_pb2 # type: ignore +from google.protobuf import struct_pb2 # type: ignore +from google.protobuf import timestamp_pb2 # type: ignore +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(): @@ -103,7 +132,7 @@ def test__get_default_mtls_endpoint(): "client_class", [ServiceControllerClient, ServiceControllerAsyncClient,] ) def test_service_controller_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: @@ -120,7 +149,7 @@ def test_service_controller_client_from_service_account_info(client_class): "client_class", [ServiceControllerClient, ServiceControllerAsyncClient,] ) def test_service_controller_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: @@ -173,7 +202,7 @@ def test_service_controller_client_client_options( ): # Check that if channel is provided we won't create a new one. with mock.patch.object(ServiceControllerClient, "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() @@ -469,7 +498,7 @@ def test_service_controller_client_client_options_from_dict(): def test_check(transport: str = "grpc", request_type=service_controller.CheckRequest): client = ServiceControllerClient( - credentials=credentials.AnonymousCredentials(), transport=transport, + credentials=ga_credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, @@ -484,23 +513,17 @@ def test_check(transport: str = "grpc", request_type=service_controller.CheckReq service_config_id="service_config_id_value", service_rollout_id="service_rollout_id_value", ) - response = client.check(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0] == service_controller.CheckRequest() # Establish that the response is the type that we expect. - assert isinstance(response, service_controller.CheckResponse) - assert response.operation_id == "operation_id_value" - assert response.service_config_id == "service_config_id_value" - assert response.service_rollout_id == "service_rollout_id_value" @@ -512,7 +535,7 @@ def test_check_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 = ServiceControllerClient( - credentials=credentials.AnonymousCredentials(), transport="grpc", + credentials=ga_credentials.AnonymousCredentials(), transport="grpc", ) # Mock the actual call within the gRPC stub, and fake the request. @@ -520,7 +543,6 @@ def test_check_empty_call(): client.check() call.assert_called() _, args, _ = call.mock_calls[0] - assert args[0] == service_controller.CheckRequest() @@ -529,7 +551,7 @@ async def test_check_async( transport: str = "grpc_asyncio", request_type=service_controller.CheckRequest ): client = ServiceControllerAsyncClient( - credentials=credentials.AnonymousCredentials(), transport=transport, + credentials=ga_credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, @@ -546,22 +568,17 @@ async def test_check_async( service_rollout_id="service_rollout_id_value", ) ) - response = await client.check(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0] == service_controller.CheckRequest() # Establish that the response is the type that we expect. assert isinstance(response, service_controller.CheckResponse) - assert response.operation_id == "operation_id_value" - assert response.service_config_id == "service_config_id_value" - assert response.service_rollout_id == "service_rollout_id_value" @@ -572,7 +589,7 @@ async def test_check_async_from_dict(): def test_report(transport: str = "grpc", request_type=service_controller.ReportRequest): client = ServiceControllerClient( - credentials=credentials.AnonymousCredentials(), transport=transport, + credentials=ga_credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, @@ -586,21 +603,16 @@ def test_report(transport: str = "grpc", request_type=service_controller.ReportR service_config_id="service_config_id_value", service_rollout_id="service_rollout_id_value", ) - response = client.report(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - assert args[0] == service_controller.ReportRequest() # Establish that the response is the type that we expect. - assert isinstance(response, service_controller.ReportResponse) - assert response.service_config_id == "service_config_id_value" - assert response.service_rollout_id == "service_rollout_id_value" @@ -612,7 +624,7 @@ def test_report_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 = ServiceControllerClient( - credentials=credentials.AnonymousCredentials(), transport="grpc", + credentials=ga_credentials.AnonymousCredentials(), transport="grpc", ) # Mock the actual call within the gRPC stub, and fake the request. @@ -620,7 +632,6 @@ def test_report_empty_call(): client.report() call.assert_called() _, args, _ = call.mock_calls[0] - assert args[0] == service_controller.ReportRequest() @@ -629,7 +640,7 @@ async def test_report_async( transport: str = "grpc_asyncio", request_type=service_controller.ReportRequest ): client = ServiceControllerAsyncClient( - credentials=credentials.AnonymousCredentials(), transport=transport, + credentials=ga_credentials.AnonymousCredentials(), transport=transport, ) # Everything is optional in proto3 as far as the runtime is concerned, @@ -645,20 +656,16 @@ async def test_report_async( service_rollout_id="service_rollout_id_value", ) ) - response = await client.report(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - assert args[0] == service_controller.ReportRequest() # Establish that the response is the type that we expect. assert isinstance(response, service_controller.ReportResponse) - assert response.service_config_id == "service_config_id_value" - assert response.service_rollout_id == "service_rollout_id_value" @@ -670,16 +677,16 @@ async def test_report_async_from_dict(): def test_credentials_transport_error(): # It is an error to provide credentials and a transport instance. transport = transports.ServiceControllerGrpcTransport( - credentials=credentials.AnonymousCredentials(), + credentials=ga_credentials.AnonymousCredentials(), ) with pytest.raises(ValueError): client = ServiceControllerClient( - 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.ServiceControllerGrpcTransport( - credentials=credentials.AnonymousCredentials(), + credentials=ga_credentials.AnonymousCredentials(), ) with pytest.raises(ValueError): client = ServiceControllerClient( @@ -689,7 +696,7 @@ def test_credentials_transport_error(): # It is an error to provide scopes and a transport instance. transport = transports.ServiceControllerGrpcTransport( - credentials=credentials.AnonymousCredentials(), + credentials=ga_credentials.AnonymousCredentials(), ) with pytest.raises(ValueError): client = ServiceControllerClient( @@ -700,7 +707,7 @@ def test_credentials_transport_error(): def test_transport_instance(): # A client may be instantiated with a custom transport instance. transport = transports.ServiceControllerGrpcTransport( - credentials=credentials.AnonymousCredentials(), + credentials=ga_credentials.AnonymousCredentials(), ) client = ServiceControllerClient(transport=transport) assert client.transport is transport @@ -709,13 +716,13 @@ def test_transport_instance(): def test_transport_get_channel(): # A client may be instantiated with a custom transport instance. transport = transports.ServiceControllerGrpcTransport( - credentials=credentials.AnonymousCredentials(), + credentials=ga_credentials.AnonymousCredentials(), ) channel = transport.grpc_channel assert channel transport = transports.ServiceControllerGrpcAsyncIOTransport( - credentials=credentials.AnonymousCredentials(), + credentials=ga_credentials.AnonymousCredentials(), ) channel = transport.grpc_channel assert channel @@ -730,23 +737,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 = ServiceControllerClient(credentials=credentials.AnonymousCredentials(),) + client = ServiceControllerClient(credentials=ga_credentials.AnonymousCredentials(),) assert isinstance(client.transport, transports.ServiceControllerGrpcTransport,) def test_service_controller_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.ServiceControllerTransport( - credentials=credentials.AnonymousCredentials(), + credentials=ga_credentials.AnonymousCredentials(), credentials_file="credentials.json", ) @@ -758,7 +765,7 @@ def test_service_controller_base_transport(): ) as Transport: Transport.return_value = None transport = transports.ServiceControllerTransport( - credentials=credentials.AnonymousCredentials(), + credentials=ga_credentials.AnonymousCredentials(), ) # Every method on the transport should just blindly @@ -772,15 +779,40 @@ def test_service_controller_base_transport(): getattr(transport, method)(request=object()) +@requires_google_auth_gte_1_25_0 def test_service_controller_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.servicecontrol_v1.services.service_controller.transports.ServiceControllerTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + load_creds.return_value = (ga_credentials.AnonymousCredentials(), None) + transport = transports.ServiceControllerTransport( + 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", + "https://www.googleapis.com/auth/servicecontrol", + ), + quota_project_id="octopus", + ) + + +@requires_google_auth_lt_1_25_0 +def test_service_controller_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.servicecontrol_v1.services.service_controller.transports.ServiceControllerTransport._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.ServiceControllerTransport( credentials_file="credentials.json", quota_project_id="octopus", ) @@ -796,19 +828,36 @@ def test_service_controller_base_transport_with_credentials_file(): def test_service_controller_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.servicecontrol_v1.services.service_controller.transports.ServiceControllerTransport._prep_wrapped_messages" ) as Transport: Transport.return_value = None - adc.return_value = (credentials.AnonymousCredentials(), None) + adc.return_value = (ga_credentials.AnonymousCredentials(), None) transport = transports.ServiceControllerTransport() adc.assert_called_once() +@requires_google_auth_gte_1_25_0 def test_service_controller_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) + ServiceControllerClient() + adc.assert_called_once_with( + scopes=None, + default_scopes=( + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/servicecontrol", + ), + quota_project_id=None, + ) + + +@requires_google_auth_lt_1_25_0 +def test_service_controller_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) ServiceControllerClient() adc.assert_called_once_with( scopes=( @@ -819,14 +868,44 @@ def test_service_controller_auth_adc(): ) -def test_service_controller_transport_auth_adc(): +@pytest.mark.parametrize( + "transport_class", + [ + transports.ServiceControllerGrpcTransport, + transports.ServiceControllerGrpcAsyncIOTransport, + ], +) +@requires_google_auth_gte_1_25_0 +def test_service_controller_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.ServiceControllerGrpcTransport( - 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", + "https://www.googleapis.com/auth/servicecontrol", + ), + quota_project_id="octopus", ) + + +@pytest.mark.parametrize( + "transport_class", + [ + transports.ServiceControllerGrpcTransport, + transports.ServiceControllerGrpcAsyncIOTransport, + ], +) +@requires_google_auth_lt_1_25_0 +def test_service_controller_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", @@ -836,6 +915,121 @@ def test_service_controller_transport_auth_adc(): ) +@pytest.mark.parametrize( + "transport_class,grpc_helpers", + [ + (transports.ServiceControllerGrpcTransport, grpc_helpers), + (transports.ServiceControllerGrpcAsyncIOTransport, grpc_helpers_async), + ], +) +@requires_api_core_gte_1_26_0 +def test_service_controller_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( + "servicecontrol.googleapis.com:443", + credentials=creds, + credentials_file=None, + quota_project_id="octopus", + default_scopes=( + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/servicecontrol", + ), + scopes=["1", "2"], + default_host="servicecontrol.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.ServiceControllerGrpcTransport, grpc_helpers), + (transports.ServiceControllerGrpcAsyncIOTransport, grpc_helpers_async), + ], +) +@requires_api_core_lt_1_26_0 +def test_service_controller_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( + "servicecontrol.googleapis.com:443", + credentials=creds, + credentials_file=None, + quota_project_id="octopus", + scopes=( + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/servicecontrol", + ), + ssl_credentials=None, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + +@pytest.mark.parametrize( + "transport_class,grpc_helpers", + [ + (transports.ServiceControllerGrpcTransport, grpc_helpers), + (transports.ServiceControllerGrpcAsyncIOTransport, grpc_helpers_async), + ], +) +@requires_api_core_lt_1_26_0 +def test_service_controller_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( + "servicecontrol.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", [ @@ -844,7 +1038,7 @@ def test_service_controller_transport_auth_adc(): ], ) def test_service_controller_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: @@ -886,7 +1080,7 @@ def test_service_controller_grpc_transport_client_cert_source_for_mtls(transport def test_service_controller_host_no_port(): client = ServiceControllerClient( - credentials=credentials.AnonymousCredentials(), + credentials=ga_credentials.AnonymousCredentials(), client_options=client_options.ClientOptions( api_endpoint="servicecontrol.googleapis.com" ), @@ -896,7 +1090,7 @@ def test_service_controller_host_no_port(): def test_service_controller_host_with_port(): client = ServiceControllerClient( - credentials=credentials.AnonymousCredentials(), + credentials=ga_credentials.AnonymousCredentials(), client_options=client_options.ClientOptions( api_endpoint="servicecontrol.googleapis.com:8000" ), @@ -952,9 +1146,9 @@ def test_service_controller_transport_channel_mtls_with_client_cert_source( 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", @@ -1036,7 +1230,6 @@ def test_service_controller_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, ) @@ -1057,7 +1250,6 @@ def test_parse_common_billing_account_path(): def test_common_folder_path(): folder = "whelk" - expected = "folders/{folder}".format(folder=folder,) actual = ServiceControllerClient.common_folder_path(folder) assert expected == actual @@ -1076,7 +1268,6 @@ def test_parse_common_folder_path(): def test_common_organization_path(): organization = "oyster" - expected = "organizations/{organization}".format(organization=organization,) actual = ServiceControllerClient.common_organization_path(organization) assert expected == actual @@ -1095,7 +1286,6 @@ def test_parse_common_organization_path(): def test_common_project_path(): project = "cuttlefish" - expected = "projects/{project}".format(project=project,) actual = ServiceControllerClient.common_project_path(project) assert expected == actual @@ -1115,7 +1305,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, ) @@ -1142,7 +1331,7 @@ def test_client_withDEFAULT_CLIENT_INFO(): transports.ServiceControllerTransport, "_prep_wrapped_messages" ) as prep: client = ServiceControllerClient( - credentials=credentials.AnonymousCredentials(), client_info=client_info, + credentials=ga_credentials.AnonymousCredentials(), client_info=client_info, ) prep.assert_called_once_with(client_info) @@ -1151,6 +1340,6 @@ def test_client_withDEFAULT_CLIENT_INFO(): ) as prep: transport_class = ServiceControllerClient.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)