From 0233804885846295508a5fc98929dba598172244 Mon Sep 17 00:00:00 2001 From: Yoshi Automation Bot Date: Mon, 26 Oct 2020 18:43:34 -0700 Subject: [PATCH] feat: add text extraction health care option in create model (#86) v1beta1: Breaking changes to message attributes. `type` ->`type_`, `min` -> `min_`, `max` -> `max_` --- docs/automl_v1beta1/services.rst | 4 +- google/cloud/automl_v1/__init__.py | 4 +- .../services/auto_ml/async_client.py | 28 +- .../automl_v1/services/auto_ml/client.py | 92 +- .../services/auto_ml/transports/base.py | 2 +- .../services/auto_ml/transports/grpc.py | 46 +- .../auto_ml/transports/grpc_asyncio.py | 51 +- .../prediction_service/async_client.py | 23 +- .../services/prediction_service/client.py | 92 +- .../prediction_service/transports/base.py | 2 +- .../prediction_service/transports/grpc.py | 46 +- .../transports/grpc_asyncio.py | 51 +- .../proto/annotation_payload.proto | 77 ++ .../proto/annotation_spec.proto | 48 + .../automl_v1beta1/proto/classification.proto | 216 +++ .../automl_v1beta1/proto/column_spec.proto | 78 ++ .../automl_v1beta1/proto/data_items.proto | 221 ++++ .../automl_v1beta1/proto/data_stats.proto | 166 +++ .../automl_v1beta1/proto/data_types.proto | 105 ++ .../cloud/automl_v1beta1/proto/dataset.proto | 96 ++ .../automl_v1beta1/proto/detection.proto | 135 ++ .../cloud/automl_v1beta1/proto/geometry.proto | 46 + google/cloud/automl_v1beta1/proto/image.proto | 193 +++ google/cloud/automl_v1beta1/proto/io.proto | 1158 +++++++++++++++++ google/cloud/automl_v1beta1/proto/model.proto | 108 ++ .../proto/model_evaluation.proto | 116 ++ .../automl_v1beta1/proto/operations.proto | 189 +++ .../proto/prediction_service.proto | 268 ++++ .../cloud/automl_v1beta1/proto/ranges.proto | 35 + .../automl_v1beta1/proto/regression.proto | 44 + .../cloud/automl_v1beta1/proto/service.proto | 800 ++++++++++++ .../automl_v1beta1/proto/table_spec.proto | 78 ++ .../cloud/automl_v1beta1/proto/tables.proto | 292 +++++ .../cloud/automl_v1beta1/proto/temporal.proto | 37 + google/cloud/automl_v1beta1/proto/text.proto | 71 + .../proto/text_extraction.proto | 68 + .../automl_v1beta1/proto/text_segment.proto | 41 + .../automl_v1beta1/proto/text_sentiment.proto | 80 ++ .../automl_v1beta1/proto/translation.proto | 69 + google/cloud/automl_v1beta1/proto/video.proto | 48 + .../services/auto_ml/async_client.py | 32 +- .../automl_v1beta1/services/auto_ml/client.py | 92 +- .../services/auto_ml/transports/base.py | 2 +- .../services/auto_ml/transports/grpc.py | 46 +- .../auto_ml/transports/grpc_asyncio.py | 51 +- .../prediction_service/async_client.py | 23 +- .../services/prediction_service/client.py | 92 +- .../prediction_service/transports/base.py | 2 +- .../prediction_service/transports/grpc.py | 46 +- .../transports/grpc_asyncio.py | 51 +- .../automl_v1beta1/types/classification.py | 4 +- .../cloud/automl_v1beta1/types/data_stats.py | 8 +- google/cloud/automl_v1beta1/types/io.py | 29 +- google/cloud/automl_v1beta1/types/text.py | 15 +- noxfile.py | 34 - setup.py | 2 +- synth.metadata | 224 +++- synth.py | 13 +- tests/unit/gapic/automl_v1/test_auto_ml.py | 545 ++++---- .../automl_v1/test_prediction_service.py | 496 +++---- .../unit/gapic/automl_v1beta1/test_auto_ml.py | 603 ++++----- .../automl_v1beta1/test_prediction_service.py | 496 +++---- 62 files changed, 6864 insertions(+), 1366 deletions(-) create mode 100644 google/cloud/automl_v1beta1/proto/annotation_payload.proto create mode 100644 google/cloud/automl_v1beta1/proto/annotation_spec.proto create mode 100644 google/cloud/automl_v1beta1/proto/classification.proto create mode 100644 google/cloud/automl_v1beta1/proto/column_spec.proto create mode 100644 google/cloud/automl_v1beta1/proto/data_items.proto create mode 100644 google/cloud/automl_v1beta1/proto/data_stats.proto create mode 100644 google/cloud/automl_v1beta1/proto/data_types.proto create mode 100644 google/cloud/automl_v1beta1/proto/dataset.proto create mode 100644 google/cloud/automl_v1beta1/proto/detection.proto create mode 100644 google/cloud/automl_v1beta1/proto/geometry.proto create mode 100644 google/cloud/automl_v1beta1/proto/image.proto create mode 100644 google/cloud/automl_v1beta1/proto/io.proto create mode 100644 google/cloud/automl_v1beta1/proto/model.proto create mode 100644 google/cloud/automl_v1beta1/proto/model_evaluation.proto create mode 100644 google/cloud/automl_v1beta1/proto/operations.proto create mode 100644 google/cloud/automl_v1beta1/proto/prediction_service.proto create mode 100644 google/cloud/automl_v1beta1/proto/ranges.proto create mode 100644 google/cloud/automl_v1beta1/proto/regression.proto create mode 100644 google/cloud/automl_v1beta1/proto/service.proto create mode 100644 google/cloud/automl_v1beta1/proto/table_spec.proto create mode 100644 google/cloud/automl_v1beta1/proto/tables.proto create mode 100644 google/cloud/automl_v1beta1/proto/temporal.proto create mode 100644 google/cloud/automl_v1beta1/proto/text.proto create mode 100644 google/cloud/automl_v1beta1/proto/text_extraction.proto create mode 100644 google/cloud/automl_v1beta1/proto/text_segment.proto create mode 100644 google/cloud/automl_v1beta1/proto/text_sentiment.proto create mode 100644 google/cloud/automl_v1beta1/proto/translation.proto create mode 100644 google/cloud/automl_v1beta1/proto/video.proto diff --git a/docs/automl_v1beta1/services.rst b/docs/automl_v1beta1/services.rst index 787e8566..511f02ad 100644 --- a/docs/automl_v1beta1/services.rst +++ b/docs/automl_v1beta1/services.rst @@ -7,6 +7,6 @@ Services for Google Cloud Automl v1beta1 API .. automodule:: google.cloud.automl_v1beta1.services.prediction_service :members: :inherited-members: -.. automodule:: google.cloud.automl_v1beta1.services.tables - :members: +.. automodule:: google.cloud.automl_v1beta1.services.tables + :members: :inherited-members: diff --git a/google/cloud/automl_v1/__init__.py b/google/cloud/automl_v1/__init__.py index b5f76f81..6f22bb65 100644 --- a/google/cloud/automl_v1/__init__.py +++ b/google/cloud/automl_v1/__init__.py @@ -104,6 +104,7 @@ __all__ = ( "AnnotationPayload", "AnnotationSpec", + "AutoMlClient", "BatchPredictInputConfig", "BatchPredictOperationMetadata", "BatchPredictOutputConfig", @@ -164,7 +165,6 @@ "OutputConfig", "PredictRequest", "PredictResponse", - "PredictionServiceClient", "TextClassificationDatasetMetadata", "TextClassificationModelMetadata", "TextExtractionAnnotation", @@ -185,5 +185,5 @@ "UndeployModelRequest", "UpdateDatasetRequest", "UpdateModelRequest", - "AutoMlClient", + "PredictionServiceClient", ) diff --git a/google/cloud/automl_v1/services/auto_ml/async_client.py b/google/cloud/automl_v1/services/auto_ml/async_client.py index 2b7f9c5c..23d7b118 100644 --- a/google/cloud/automl_v1/services/auto_ml/async_client.py +++ b/google/cloud/automl_v1/services/auto_ml/async_client.py @@ -28,8 +28,8 @@ from google.auth import credentials # type: ignore from google.oauth2 import service_account # type: ignore -from google.api_core import operation -from google.api_core import operation_async +from google.api_core import operation # type: ignore +from google.api_core import operation_async # type: ignore from google.cloud.automl_v1.services.auto_ml import pagers from google.cloud.automl_v1.types import annotation_spec from google.cloud.automl_v1.types import classification @@ -79,9 +79,10 @@ class AutoMlAsyncClient: DEFAULT_ENDPOINT = AutoMlClient.DEFAULT_ENDPOINT DEFAULT_MTLS_ENDPOINT = AutoMlClient.DEFAULT_MTLS_ENDPOINT - model_path = staticmethod(AutoMlClient.model_path) - dataset_path = staticmethod(AutoMlClient.dataset_path) + parse_dataset_path = staticmethod(AutoMlClient.parse_dataset_path) + model_path = staticmethod(AutoMlClient.model_path) + parse_model_path = staticmethod(AutoMlClient.parse_model_path) from_service_account_file = AutoMlClient.from_service_account_file from_service_account_json = from_service_account_file @@ -112,16 +113,19 @@ def __init__( client_options (ClientOptions): Custom options for the client. It won't take effect if a ``transport`` instance is provided. (1) The ``api_endpoint`` property can be used to override the - default endpoint provided by the client. GOOGLE_API_USE_MTLS + default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT environment variable can also be used to override the endpoint: "always" (always use the default mTLS endpoint), "never" (always - use the default regular endpoint, this is the default value for - the environment variable) and "auto" (auto switch to the default - mTLS endpoint if client SSL credentials is present). However, - the ``api_endpoint`` property takes precedence if provided. - (2) The ``client_cert_source`` property is used to provide client - SSL credentials for mutual TLS transport. If not provided, the - default SSL credentials will be used if present. + use the default regular endpoint) and "auto" (auto switch to the + default mTLS endpoint if client certificate is present, this is + the default value). However, the ``api_endpoint`` property takes + precedence if provided. + (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable + is "true", then the ``client_cert_source`` property can be used + to provide client certificate for mutual TLS transport. If + not provided, the default SSL client certificate will be used if + present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not + set, no client certificate will be used. Raises: google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport diff --git a/google/cloud/automl_v1/services/auto_ml/client.py b/google/cloud/automl_v1/services/auto_ml/client.py index e615ce00..3765ac0b 100644 --- a/google/cloud/automl_v1/services/auto_ml/client.py +++ b/google/cloud/automl_v1/services/auto_ml/client.py @@ -16,22 +16,24 @@ # from collections import OrderedDict +from distutils import util import os import re -from typing import Callable, Dict, Sequence, Tuple, Type, Union +from typing import Callable, Dict, Optional, Sequence, Tuple, Type, Union import pkg_resources -import google.api_core.client_options as ClientOptions # type: ignore +from google.api_core import client_options as client_options_lib # type: ignore from google.api_core import exceptions # type: ignore from google.api_core import gapic_v1 # type: ignore from google.api_core import retry as retries # type: ignore from google.auth import credentials # type: ignore from google.auth.transport import mtls # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore from google.auth.exceptions import MutualTLSChannelError # type: ignore from google.oauth2 import service_account # type: ignore -from google.api_core import operation -from google.api_core import operation_async +from google.api_core import operation # type: ignore +from google.api_core import operation_async # type: ignore from google.cloud.automl_v1.services.auto_ml import pagers from google.cloud.automl_v1.types import annotation_spec from google.cloud.automl_v1.types import classification @@ -196,9 +198,9 @@ def parse_model_path(path: str) -> Dict[str, str]: def __init__( self, *, - credentials: credentials.Credentials = None, - transport: Union[str, AutoMlTransport] = None, - client_options: ClientOptions = None, + credentials: Optional[credentials.Credentials] = None, + transport: Union[str, AutoMlTransport, None] = None, + client_options: Optional[client_options_lib.ClientOptions] = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: """Instantiate the auto ml client. @@ -212,19 +214,22 @@ def __init__( transport (Union[str, ~.AutoMlTransport]): The transport to use. If set to None, a transport is chosen automatically. - client_options (ClientOptions): Custom options for the client. It - won't take effect if a ``transport`` instance is provided. + client_options (client_options_lib.ClientOptions): Custom options for the + client. It won't take effect if a ``transport`` instance is provided. (1) The ``api_endpoint`` property can be used to override the - default endpoint provided by the client. GOOGLE_API_USE_MTLS + default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT environment variable can also be used to override the endpoint: "always" (always use the default mTLS endpoint), "never" (always - use the default regular endpoint, this is the default value for - the environment variable) and "auto" (auto switch to the default - mTLS endpoint if client SSL credentials is present). However, - the ``api_endpoint`` property takes precedence if provided. - (2) The ``client_cert_source`` property is used to provide client - SSL credentials for mutual TLS transport. If not provided, the - default SSL credentials will be used if present. + use the default regular endpoint) and "auto" (auto switch to the + default mTLS endpoint if client certificate is present, this is + the default value). However, the ``api_endpoint`` property takes + precedence if provided. + (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable + is "true", then the ``client_cert_source`` property can be used + to provide client certificate for mutual TLS transport. If + not provided, the default SSL client certificate will be used if + present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not + set, no client certificate will be used. client_info (google.api_core.gapic_v1.client_info.ClientInfo): The client info used to send a user-agent string along with API requests. If ``None``, then default info will be used. @@ -236,29 +241,47 @@ def __init__( creation failed for any reason. """ if isinstance(client_options, dict): - client_options = ClientOptions.from_dict(client_options) + client_options = client_options_lib.from_dict(client_options) if client_options is None: - client_options = ClientOptions.ClientOptions() + client_options = client_options_lib.ClientOptions() - if client_options.api_endpoint is None: - use_mtls_env = os.getenv("GOOGLE_API_USE_MTLS", "never") + # Create SSL credentials for mutual TLS if needed. + use_client_cert = bool( + util.strtobool(os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false")) + ) + + ssl_credentials = None + is_mtls = False + if use_client_cert: + if client_options.client_cert_source: + import grpc # type: ignore + + cert, key = client_options.client_cert_source() + ssl_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + is_mtls = True + else: + creds = SslCredentials() + is_mtls = creds.is_mtls + ssl_credentials = creds.ssl_credentials if is_mtls else None + + # Figure out which api endpoint to use. + if client_options.api_endpoint is not None: + api_endpoint = client_options.api_endpoint + else: + use_mtls_env = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto") if use_mtls_env == "never": - client_options.api_endpoint = self.DEFAULT_ENDPOINT + api_endpoint = self.DEFAULT_ENDPOINT elif use_mtls_env == "always": - client_options.api_endpoint = self.DEFAULT_MTLS_ENDPOINT + api_endpoint = self.DEFAULT_MTLS_ENDPOINT elif use_mtls_env == "auto": - has_client_cert_source = ( - client_options.client_cert_source is not None - or mtls.has_default_client_cert_source() - ) - client_options.api_endpoint = ( - self.DEFAULT_MTLS_ENDPOINT - if has_client_cert_source - else self.DEFAULT_ENDPOINT + api_endpoint = ( + self.DEFAULT_MTLS_ENDPOINT if is_mtls else self.DEFAULT_ENDPOINT ) else: raise MutualTLSChannelError( - "Unsupported GOOGLE_API_USE_MTLS value. Accepted values: never, auto, always" + "Unsupported GOOGLE_API_USE_MTLS_ENDPOINT value. Accepted values: never, auto, always" ) # Save or instantiate the transport. @@ -282,10 +305,9 @@ def __init__( self._transport = Transport( credentials=credentials, credentials_file=client_options.credentials_file, - host=client_options.api_endpoint, + host=api_endpoint, scopes=client_options.scopes, - api_mtls_endpoint=client_options.api_endpoint, - client_cert_source=client_options.client_cert_source, + ssl_channel_credentials=ssl_credentials, quota_project_id=client_options.quota_project_id, client_info=client_info, ) diff --git a/google/cloud/automl_v1/services/auto_ml/transports/base.py b/google/cloud/automl_v1/services/auto_ml/transports/base.py index 5e230105..b1e12781 100644 --- a/google/cloud/automl_v1/services/auto_ml/transports/base.py +++ b/google/cloud/automl_v1/services/auto_ml/transports/base.py @@ -19,7 +19,7 @@ import typing import pkg_resources -from google import auth +from google import auth # type: ignore from google.api_core import exceptions # type: ignore from google.api_core import gapic_v1 # type: ignore from google.api_core import retry as retries # type: ignore diff --git a/google/cloud/automl_v1/services/auto_ml/transports/grpc.py b/google/cloud/automl_v1/services/auto_ml/transports/grpc.py index 100f50f6..b957e5cd 100644 --- a/google/cloud/automl_v1/services/auto_ml/transports/grpc.py +++ b/google/cloud/automl_v1/services/auto_ml/transports/grpc.py @@ -15,6 +15,7 @@ # limitations under the License. # +import warnings from typing import Callable, Dict, Optional, Sequence, Tuple from google.api_core import grpc_helpers # type: ignore @@ -24,7 +25,6 @@ from google.auth import credentials # type: ignore from google.auth.transport.grpc import SslCredentials # type: ignore - import grpc # type: ignore from google.cloud.automl_v1.types import annotation_spec @@ -78,6 +78,7 @@ def __init__( channel: grpc.Channel = None, api_mtls_endpoint: str = None, client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, + ssl_channel_credentials: grpc.ChannelCredentials = None, quota_project_id: Optional[str] = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: @@ -98,14 +99,16 @@ def __init__( ignored if ``channel`` is provided. channel (Optional[grpc.Channel]): A ``Channel`` instance through which to make calls. - api_mtls_endpoint (Optional[str]): The mutual TLS endpoint. If - provided, it overrides the ``host`` argument and tries to create + api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. + If provided, it overrides the ``host`` argument and tries to create a mutual TLS channel with client SSL credentials from ``client_cert_source`` or applicatin default SSL credentials. - client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): A - callback to provide client SSL certificate bytes and private key - bytes, both in PEM format. It is ignored if ``api_mtls_endpoint`` - is None. + client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): + Deprecated. A callback to provide client SSL certificate bytes and + private key bytes, both in PEM format. It is ignored if + ``api_mtls_endpoint`` is None. + ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials + for grpc channel. It is ignored if ``channel`` is provided. quota_project_id (Optional[str]): An optional project to use for billing and quota. client_info (google.api_core.gapic_v1.client_info.ClientInfo): @@ -128,6 +131,11 @@ def __init__( # If a channel was explicitly provided, set it. self._grpc_channel = channel elif api_mtls_endpoint: + warnings.warn( + "api_mtls_endpoint and client_cert_source are deprecated", + DeprecationWarning, + ) + host = ( api_mtls_endpoint if ":" in api_mtls_endpoint @@ -158,6 +166,23 @@ def __init__( scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, ) + else: + host = host if ":" in host else host + ":443" + + if credentials is None: + credentials, _ = auth.default( + scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id + ) + + # create a new channel. The provided one is ignored. + self._grpc_channel = type(self).create_channel( + host, + credentials=credentials, + credentials_file=credentials_file, + ssl_credentials=ssl_channel_credentials, + scopes=scopes or self.AUTH_SCOPES, + quota_project_id=quota_project_id, + ) self._stubs = {} # type: Dict[str, Callable] @@ -223,13 +248,6 @@ def grpc_channel(self) -> grpc.Channel: This property caches on the instance; repeated calls return the same channel. """ - # Sanity check: Only create a new channel if we do not already - # have one. - if not hasattr(self, "_grpc_channel"): - self._grpc_channel = self.create_channel( - self._host, credentials=self._credentials, - ) - # Return the channel from cache. return self._grpc_channel diff --git a/google/cloud/automl_v1/services/auto_ml/transports/grpc_asyncio.py b/google/cloud/automl_v1/services/auto_ml/transports/grpc_asyncio.py index 39e15a79..0778c063 100644 --- a/google/cloud/automl_v1/services/auto_ml/transports/grpc_asyncio.py +++ b/google/cloud/automl_v1/services/auto_ml/transports/grpc_asyncio.py @@ -15,11 +15,13 @@ # limitations under the License. # +import warnings from typing import Awaitable, Callable, Dict, Optional, Sequence, Tuple from google.api_core import gapic_v1 # type: ignore from google.api_core import grpc_helpers_async # type: ignore from google.api_core import operations_v1 # type: ignore +from google import auth # type: ignore from google.auth import credentials # type: ignore from google.auth.transport.grpc import SslCredentials # type: ignore @@ -120,6 +122,7 @@ def __init__( channel: aio.Channel = None, api_mtls_endpoint: str = None, client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, + ssl_channel_credentials: grpc.ChannelCredentials = None, quota_project_id=None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: @@ -141,14 +144,16 @@ def __init__( are passed to :func:`google.auth.default`. channel (Optional[aio.Channel]): A ``Channel`` instance through which to make calls. - api_mtls_endpoint (Optional[str]): The mutual TLS endpoint. If - provided, it overrides the ``host`` argument and tries to create + api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. + If provided, it overrides the ``host`` argument and tries to create a mutual TLS channel with client SSL credentials from ``client_cert_source`` or applicatin default SSL credentials. - client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): A - callback to provide client SSL certificate bytes and private key - bytes, both in PEM format. It is ignored if ``api_mtls_endpoint`` - is None. + client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): + Deprecated. A callback to provide client SSL certificate bytes and + private key bytes, both in PEM format. It is ignored if + ``api_mtls_endpoint`` is None. + ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials + for grpc channel. It is ignored if ``channel`` is provided. quota_project_id (Optional[str]): An optional project to use for billing and quota. client_info (google.api_core.gapic_v1.client_info.ClientInfo): @@ -171,12 +176,22 @@ def __init__( # If a channel was explicitly provided, set it. self._grpc_channel = channel elif api_mtls_endpoint: + warnings.warn( + "api_mtls_endpoint and client_cert_source are deprecated", + DeprecationWarning, + ) + host = ( api_mtls_endpoint if ":" in api_mtls_endpoint else api_mtls_endpoint + ":443" ) + if credentials is None: + credentials, _ = auth.default( + scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id + ) + # Create SSL credentials with client_cert_source or application # default SSL credentials. if client_cert_source: @@ -196,6 +211,23 @@ def __init__( scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, ) + else: + host = host if ":" in host else host + ":443" + + if credentials is None: + credentials, _ = auth.default( + scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id + ) + + # create a new channel. The provided one is ignored. + self._grpc_channel = type(self).create_channel( + host, + credentials=credentials, + credentials_file=credentials_file, + ssl_credentials=ssl_channel_credentials, + scopes=scopes or self.AUTH_SCOPES, + quota_project_id=quota_project_id, + ) # Run the base constructor. super().__init__( @@ -216,13 +248,6 @@ def grpc_channel(self) -> aio.Channel: This property caches on the instance; repeated calls return the same channel. """ - # Sanity check: Only create a new channel if we do not already - # have one. - if not hasattr(self, "_grpc_channel"): - self._grpc_channel = self.create_channel( - self._host, credentials=self._credentials, - ) - # Return the channel from cache. return self._grpc_channel diff --git a/google/cloud/automl_v1/services/prediction_service/async_client.py b/google/cloud/automl_v1/services/prediction_service/async_client.py index df141602..d77836a0 100644 --- a/google/cloud/automl_v1/services/prediction_service/async_client.py +++ b/google/cloud/automl_v1/services/prediction_service/async_client.py @@ -28,8 +28,8 @@ from google.auth import credentials # type: ignore from google.oauth2 import service_account # type: ignore -from google.api_core import operation -from google.api_core import operation_async +from google.api_core import operation # type: ignore +from google.api_core import operation_async # type: ignore from google.cloud.automl_v1.types import annotation_payload from google.cloud.automl_v1.types import data_items from google.cloud.automl_v1.types import io @@ -82,16 +82,19 @@ def __init__( client_options (ClientOptions): Custom options for the client. It won't take effect if a ``transport`` instance is provided. (1) The ``api_endpoint`` property can be used to override the - default endpoint provided by the client. GOOGLE_API_USE_MTLS + default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT environment variable can also be used to override the endpoint: "always" (always use the default mTLS endpoint), "never" (always - use the default regular endpoint, this is the default value for - the environment variable) and "auto" (auto switch to the default - mTLS endpoint if client SSL credentials is present). However, - the ``api_endpoint`` property takes precedence if provided. - (2) The ``client_cert_source`` property is used to provide client - SSL credentials for mutual TLS transport. If not provided, the - default SSL credentials will be used if present. + use the default regular endpoint) and "auto" (auto switch to the + default mTLS endpoint if client certificate is present, this is + the default value). However, the ``api_endpoint`` property takes + precedence if provided. + (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable + is "true", then the ``client_cert_source`` property can be used + to provide client certificate for mutual TLS transport. If + not provided, the default SSL client certificate will be used if + present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not + set, no client certificate will be used. Raises: google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport diff --git a/google/cloud/automl_v1/services/prediction_service/client.py b/google/cloud/automl_v1/services/prediction_service/client.py index 2ccfd9fc..d2c1971a 100644 --- a/google/cloud/automl_v1/services/prediction_service/client.py +++ b/google/cloud/automl_v1/services/prediction_service/client.py @@ -16,22 +16,24 @@ # from collections import OrderedDict +from distutils import util import os import re -from typing import Callable, Dict, Sequence, Tuple, Type, Union +from typing import Callable, Dict, Optional, Sequence, Tuple, Type, Union import pkg_resources -import google.api_core.client_options as ClientOptions # type: ignore +from google.api_core import client_options as client_options_lib # type: ignore from google.api_core import exceptions # type: ignore from google.api_core import gapic_v1 # type: ignore from google.api_core import retry as retries # type: ignore from google.auth import credentials # type: ignore from google.auth.transport import mtls # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore from google.auth.exceptions import MutualTLSChannelError # type: ignore from google.oauth2 import service_account # type: ignore -from google.api_core import operation -from google.api_core import operation_async +from google.api_core import operation # type: ignore +from google.api_core import operation_async # type: ignore from google.cloud.automl_v1.types import annotation_payload from google.cloud.automl_v1.types import data_items from google.cloud.automl_v1.types import io @@ -142,9 +144,9 @@ def from_service_account_file(cls, filename: str, *args, **kwargs): def __init__( self, *, - credentials: credentials.Credentials = None, - transport: Union[str, PredictionServiceTransport] = None, - client_options: ClientOptions = None, + credentials: Optional[credentials.Credentials] = None, + transport: Union[str, PredictionServiceTransport, None] = None, + client_options: Optional[client_options_lib.ClientOptions] = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: """Instantiate the prediction service client. @@ -158,19 +160,22 @@ def __init__( transport (Union[str, ~.PredictionServiceTransport]): The transport to use. If set to None, a transport is chosen automatically. - client_options (ClientOptions): Custom options for the client. It - won't take effect if a ``transport`` instance is provided. + client_options (client_options_lib.ClientOptions): Custom options for the + client. It won't take effect if a ``transport`` instance is provided. (1) The ``api_endpoint`` property can be used to override the - default endpoint provided by the client. GOOGLE_API_USE_MTLS + default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT environment variable can also be used to override the endpoint: "always" (always use the default mTLS endpoint), "never" (always - use the default regular endpoint, this is the default value for - the environment variable) and "auto" (auto switch to the default - mTLS endpoint if client SSL credentials is present). However, - the ``api_endpoint`` property takes precedence if provided. - (2) The ``client_cert_source`` property is used to provide client - SSL credentials for mutual TLS transport. If not provided, the - default SSL credentials will be used if present. + use the default regular endpoint) and "auto" (auto switch to the + default mTLS endpoint if client certificate is present, this is + the default value). However, the ``api_endpoint`` property takes + precedence if provided. + (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable + is "true", then the ``client_cert_source`` property can be used + to provide client certificate for mutual TLS transport. If + not provided, the default SSL client certificate will be used if + present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not + set, no client certificate will be used. client_info (google.api_core.gapic_v1.client_info.ClientInfo): The client info used to send a user-agent string along with API requests. If ``None``, then default info will be used. @@ -182,29 +187,47 @@ def __init__( creation failed for any reason. """ if isinstance(client_options, dict): - client_options = ClientOptions.from_dict(client_options) + client_options = client_options_lib.from_dict(client_options) if client_options is None: - client_options = ClientOptions.ClientOptions() + client_options = client_options_lib.ClientOptions() - if client_options.api_endpoint is None: - use_mtls_env = os.getenv("GOOGLE_API_USE_MTLS", "never") + # Create SSL credentials for mutual TLS if needed. + use_client_cert = bool( + util.strtobool(os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false")) + ) + + ssl_credentials = None + is_mtls = False + if use_client_cert: + if client_options.client_cert_source: + import grpc # type: ignore + + cert, key = client_options.client_cert_source() + ssl_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + is_mtls = True + else: + creds = SslCredentials() + is_mtls = creds.is_mtls + ssl_credentials = creds.ssl_credentials if is_mtls else None + + # Figure out which api endpoint to use. + if client_options.api_endpoint is not None: + api_endpoint = client_options.api_endpoint + else: + use_mtls_env = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto") if use_mtls_env == "never": - client_options.api_endpoint = self.DEFAULT_ENDPOINT + api_endpoint = self.DEFAULT_ENDPOINT elif use_mtls_env == "always": - client_options.api_endpoint = self.DEFAULT_MTLS_ENDPOINT + api_endpoint = self.DEFAULT_MTLS_ENDPOINT elif use_mtls_env == "auto": - has_client_cert_source = ( - client_options.client_cert_source is not None - or mtls.has_default_client_cert_source() - ) - client_options.api_endpoint = ( - self.DEFAULT_MTLS_ENDPOINT - if has_client_cert_source - else self.DEFAULT_ENDPOINT + api_endpoint = ( + self.DEFAULT_MTLS_ENDPOINT if is_mtls else self.DEFAULT_ENDPOINT ) else: raise MutualTLSChannelError( - "Unsupported GOOGLE_API_USE_MTLS value. Accepted values: never, auto, always" + "Unsupported GOOGLE_API_USE_MTLS_ENDPOINT value. Accepted values: never, auto, always" ) # Save or instantiate the transport. @@ -228,10 +251,9 @@ def __init__( self._transport = Transport( credentials=credentials, credentials_file=client_options.credentials_file, - host=client_options.api_endpoint, + host=api_endpoint, scopes=client_options.scopes, - api_mtls_endpoint=client_options.api_endpoint, - client_cert_source=client_options.client_cert_source, + ssl_channel_credentials=ssl_credentials, quota_project_id=client_options.quota_project_id, client_info=client_info, ) diff --git a/google/cloud/automl_v1/services/prediction_service/transports/base.py b/google/cloud/automl_v1/services/prediction_service/transports/base.py index 349d8793..f019a8dc 100644 --- a/google/cloud/automl_v1/services/prediction_service/transports/base.py +++ b/google/cloud/automl_v1/services/prediction_service/transports/base.py @@ -19,7 +19,7 @@ import typing import pkg_resources -from google import auth +from google import auth # type: ignore from google.api_core import exceptions # type: ignore from google.api_core import gapic_v1 # type: ignore from google.api_core import retry as retries # type: ignore diff --git a/google/cloud/automl_v1/services/prediction_service/transports/grpc.py b/google/cloud/automl_v1/services/prediction_service/transports/grpc.py index e4508add..9a2c8e9b 100644 --- a/google/cloud/automl_v1/services/prediction_service/transports/grpc.py +++ b/google/cloud/automl_v1/services/prediction_service/transports/grpc.py @@ -15,6 +15,7 @@ # limitations under the License. # +import warnings from typing import Callable, Dict, Optional, Sequence, Tuple from google.api_core import grpc_helpers # type: ignore @@ -24,7 +25,6 @@ from google.auth import credentials # type: ignore from google.auth.transport.grpc import SslCredentials # type: ignore - import grpc # type: ignore from google.cloud.automl_v1.types import prediction_service @@ -61,6 +61,7 @@ def __init__( channel: grpc.Channel = None, api_mtls_endpoint: str = None, client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, + ssl_channel_credentials: grpc.ChannelCredentials = None, quota_project_id: Optional[str] = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: @@ -81,14 +82,16 @@ def __init__( ignored if ``channel`` is provided. channel (Optional[grpc.Channel]): A ``Channel`` instance through which to make calls. - api_mtls_endpoint (Optional[str]): The mutual TLS endpoint. If - provided, it overrides the ``host`` argument and tries to create + api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. + If provided, it overrides the ``host`` argument and tries to create a mutual TLS channel with client SSL credentials from ``client_cert_source`` or applicatin default SSL credentials. - client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): A - callback to provide client SSL certificate bytes and private key - bytes, both in PEM format. It is ignored if ``api_mtls_endpoint`` - is None. + client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): + Deprecated. A callback to provide client SSL certificate bytes and + private key bytes, both in PEM format. It is ignored if + ``api_mtls_endpoint`` is None. + ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials + for grpc channel. It is ignored if ``channel`` is provided. quota_project_id (Optional[str]): An optional project to use for billing and quota. client_info (google.api_core.gapic_v1.client_info.ClientInfo): @@ -111,6 +114,11 @@ def __init__( # If a channel was explicitly provided, set it. self._grpc_channel = channel elif api_mtls_endpoint: + warnings.warn( + "api_mtls_endpoint and client_cert_source are deprecated", + DeprecationWarning, + ) + host = ( api_mtls_endpoint if ":" in api_mtls_endpoint @@ -141,6 +149,23 @@ def __init__( scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, ) + else: + host = host if ":" in host else host + ":443" + + if credentials is None: + credentials, _ = auth.default( + scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id + ) + + # create a new channel. The provided one is ignored. + self._grpc_channel = type(self).create_channel( + host, + credentials=credentials, + credentials_file=credentials_file, + ssl_credentials=ssl_channel_credentials, + scopes=scopes or self.AUTH_SCOPES, + quota_project_id=quota_project_id, + ) self._stubs = {} # type: Dict[str, Callable] @@ -206,13 +231,6 @@ def grpc_channel(self) -> grpc.Channel: This property caches on the instance; repeated calls return the same channel. """ - # Sanity check: Only create a new channel if we do not already - # have one. - if not hasattr(self, "_grpc_channel"): - self._grpc_channel = self.create_channel( - self._host, credentials=self._credentials, - ) - # Return the channel from cache. return self._grpc_channel diff --git a/google/cloud/automl_v1/services/prediction_service/transports/grpc_asyncio.py b/google/cloud/automl_v1/services/prediction_service/transports/grpc_asyncio.py index f92ad264..eddcb6ab 100644 --- a/google/cloud/automl_v1/services/prediction_service/transports/grpc_asyncio.py +++ b/google/cloud/automl_v1/services/prediction_service/transports/grpc_asyncio.py @@ -15,11 +15,13 @@ # limitations under the License. # +import warnings from typing import Awaitable, Callable, Dict, Optional, Sequence, Tuple from google.api_core import gapic_v1 # type: ignore from google.api_core import grpc_helpers_async # type: ignore from google.api_core import operations_v1 # type: ignore +from google import auth # type: ignore from google.auth import credentials # type: ignore from google.auth.transport.grpc import SslCredentials # type: ignore @@ -103,6 +105,7 @@ def __init__( channel: aio.Channel = None, api_mtls_endpoint: str = None, client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, + ssl_channel_credentials: grpc.ChannelCredentials = None, quota_project_id=None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: @@ -124,14 +127,16 @@ def __init__( are passed to :func:`google.auth.default`. channel (Optional[aio.Channel]): A ``Channel`` instance through which to make calls. - api_mtls_endpoint (Optional[str]): The mutual TLS endpoint. If - provided, it overrides the ``host`` argument and tries to create + api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. + If provided, it overrides the ``host`` argument and tries to create a mutual TLS channel with client SSL credentials from ``client_cert_source`` or applicatin default SSL credentials. - client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): A - callback to provide client SSL certificate bytes and private key - bytes, both in PEM format. It is ignored if ``api_mtls_endpoint`` - is None. + client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): + Deprecated. A callback to provide client SSL certificate bytes and + private key bytes, both in PEM format. It is ignored if + ``api_mtls_endpoint`` is None. + ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials + for grpc channel. It is ignored if ``channel`` is provided. quota_project_id (Optional[str]): An optional project to use for billing and quota. client_info (google.api_core.gapic_v1.client_info.ClientInfo): @@ -154,12 +159,22 @@ def __init__( # If a channel was explicitly provided, set it. self._grpc_channel = channel elif api_mtls_endpoint: + warnings.warn( + "api_mtls_endpoint and client_cert_source are deprecated", + DeprecationWarning, + ) + host = ( api_mtls_endpoint if ":" in api_mtls_endpoint else api_mtls_endpoint + ":443" ) + if credentials is None: + credentials, _ = auth.default( + scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id + ) + # Create SSL credentials with client_cert_source or application # default SSL credentials. if client_cert_source: @@ -179,6 +194,23 @@ def __init__( scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, ) + else: + host = host if ":" in host else host + ":443" + + if credentials is None: + credentials, _ = auth.default( + scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id + ) + + # create a new channel. The provided one is ignored. + self._grpc_channel = type(self).create_channel( + host, + credentials=credentials, + credentials_file=credentials_file, + ssl_credentials=ssl_channel_credentials, + scopes=scopes or self.AUTH_SCOPES, + quota_project_id=quota_project_id, + ) # Run the base constructor. super().__init__( @@ -199,13 +231,6 @@ def grpc_channel(self) -> aio.Channel: This property caches on the instance; repeated calls return the same channel. """ - # Sanity check: Only create a new channel if we do not already - # have one. - if not hasattr(self, "_grpc_channel"): - self._grpc_channel = self.create_channel( - self._host, credentials=self._credentials, - ) - # Return the channel from cache. return self._grpc_channel diff --git a/google/cloud/automl_v1beta1/proto/annotation_payload.proto b/google/cloud/automl_v1beta1/proto/annotation_payload.proto new file mode 100644 index 00000000..f62bb269 --- /dev/null +++ b/google/cloud/automl_v1beta1/proto/annotation_payload.proto @@ -0,0 +1,77 @@ +// 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. + +syntax = "proto3"; + +package google.cloud.automl.v1beta1; + +import "google/cloud/automl/v1beta1/classification.proto"; +import "google/cloud/automl/v1beta1/detection.proto"; +import "google/cloud/automl/v1beta1/tables.proto"; +import "google/cloud/automl/v1beta1/text_extraction.proto"; +import "google/cloud/automl/v1beta1/text_sentiment.proto"; +import "google/cloud/automl/v1beta1/translation.proto"; +import "google/protobuf/any.proto"; +import "google/api/annotations.proto"; + +option go_package = "google.golang.org/genproto/googleapis/cloud/automl/v1beta1;automl"; +option java_multiple_files = true; +option java_package = "com.google.cloud.automl.v1beta1"; +option php_namespace = "Google\\Cloud\\AutoMl\\V1beta1"; +option ruby_package = "Google::Cloud::AutoML::V1beta1"; + +// Contains annotation information that is relevant to AutoML. +message AnnotationPayload { + // Output only . Additional information about the annotation + // specific to the AutoML domain. + oneof detail { + // Annotation details for translation. + TranslationAnnotation translation = 2; + + // Annotation details for content or image classification. + ClassificationAnnotation classification = 3; + + // Annotation details for image object detection. + ImageObjectDetectionAnnotation image_object_detection = 4; + + // Annotation details for video classification. + // Returned for Video Classification predictions. + VideoClassificationAnnotation video_classification = 9; + + // Annotation details for video object tracking. + VideoObjectTrackingAnnotation video_object_tracking = 8; + + // Annotation details for text extraction. + TextExtractionAnnotation text_extraction = 6; + + // Annotation details for text sentiment. + TextSentimentAnnotation text_sentiment = 7; + + // Annotation details for Tables. + TablesAnnotation tables = 10; + } + + // Output only . The resource ID of the annotation spec that + // this annotation pertains to. The annotation spec comes from either an + // ancestor dataset, or the dataset that was used to train the model in use. + string annotation_spec_id = 1; + + // Output only. The value of + // [display_name][google.cloud.automl.v1beta1.AnnotationSpec.display_name] + // when the model was trained. Because this field returns a value at model + // training time, for different models trained using the same dataset, the + // returned value could be different as model owner could update the + // `display_name` between any two model training. + string display_name = 5; +} diff --git a/google/cloud/automl_v1beta1/proto/annotation_spec.proto b/google/cloud/automl_v1beta1/proto/annotation_spec.proto new file mode 100644 index 00000000..d9df07ee --- /dev/null +++ b/google/cloud/automl_v1beta1/proto/annotation_spec.proto @@ -0,0 +1,48 @@ +// 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. + +syntax = "proto3"; + +package google.cloud.automl.v1beta1; + +import "google/api/resource.proto"; +import "google/api/annotations.proto"; + +option go_package = "google.golang.org/genproto/googleapis/cloud/automl/v1beta1;automl"; +option java_multiple_files = true; +option java_package = "com.google.cloud.automl.v1beta1"; +option php_namespace = "Google\\Cloud\\AutoMl\\V1beta1"; +option ruby_package = "Google::Cloud::AutoML::V1beta1"; + +// A definition of an annotation spec. +message AnnotationSpec { + option (google.api.resource) = { + type: "automl.googleapis.com/AnnotationSpec" + pattern: "projects/{project}/locations/{location}/datasets/{dataset}/annotationSpecs/{annotation_spec}" + }; + + // Output only. Resource name of the annotation spec. + // Form: + // + // 'projects/{project_id}/locations/{location_id}/datasets/{dataset_id}/annotationSpecs/{annotation_spec_id}' + string name = 1; + + // Required. The name of the annotation spec to show in the interface. The name can be + // up to 32 characters long and must match the regexp `[a-zA-Z0-9_]+`. + string display_name = 2; + + // Output only. The number of examples in the parent dataset + // labeled by the annotation spec. + int32 example_count = 9; +} diff --git a/google/cloud/automl_v1beta1/proto/classification.proto b/google/cloud/automl_v1beta1/proto/classification.proto new file mode 100644 index 00000000..0594d01e --- /dev/null +++ b/google/cloud/automl_v1beta1/proto/classification.proto @@ -0,0 +1,216 @@ +// 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. + +syntax = "proto3"; + +package google.cloud.automl.v1beta1; + +import "google/cloud/automl/v1beta1/temporal.proto"; +import "google/api/annotations.proto"; + +option go_package = "google.golang.org/genproto/googleapis/cloud/automl/v1beta1;automl"; +option java_outer_classname = "ClassificationProto"; +option java_package = "com.google.cloud.automl.v1beta1"; +option php_namespace = "Google\\Cloud\\AutoMl\\V1beta1"; +option ruby_package = "Google::Cloud::AutoML::V1beta1"; + +// Type of the classification problem. +enum ClassificationType { + // An un-set value of this enum. + CLASSIFICATION_TYPE_UNSPECIFIED = 0; + + // At most one label is allowed per example. + MULTICLASS = 1; + + // Multiple labels are allowed for one example. + MULTILABEL = 2; +} + +// Contains annotation details specific to classification. +message ClassificationAnnotation { + // Output only. A confidence estimate between 0.0 and 1.0. A higher value + // means greater confidence that the annotation is positive. If a user + // approves an annotation as negative or positive, the score value remains + // unchanged. If a user creates an annotation, the score is 0 for negative or + // 1 for positive. + float score = 1; +} + +// Contains annotation details specific to video classification. +message VideoClassificationAnnotation { + // Output only. Expresses the type of video classification. Possible values: + // + // * `segment` - Classification done on a specified by user + // time segment of a video. AnnotationSpec is answered to be present + // in that time segment, if it is present in any part of it. The video + // ML model evaluations are done only for this type of classification. + // + // * `shot`- Shot-level classification. + // AutoML Video Intelligence determines the boundaries + // for each camera shot in the entire segment of the video that user + // specified in the request configuration. AutoML Video Intelligence + // then returns labels and their confidence scores for each detected + // shot, along with the start and end time of the shot. + // WARNING: Model evaluation is not done for this classification type, + // the quality of it depends on training data, but there are no + // metrics provided to describe that quality. + // + // * `1s_interval` - AutoML Video Intelligence returns labels and their + // confidence scores for each second of the entire segment of the video + // that user specified in the request configuration. + // WARNING: Model evaluation is not done for this classification type, + // the quality of it depends on training data, but there are no + // metrics provided to describe that quality. + string type = 1; + + // Output only . The classification details of this annotation. + ClassificationAnnotation classification_annotation = 2; + + // Output only . The time segment of the video to which the + // annotation applies. + TimeSegment time_segment = 3; +} + +// Model evaluation metrics for classification problems. +// Note: For Video Classification this metrics only describe quality of the +// Video Classification predictions of "segment_classification" type. +message ClassificationEvaluationMetrics { + // Metrics for a single confidence threshold. + message ConfidenceMetricsEntry { + // Output only. Metrics are computed with an assumption that the model + // never returns predictions with score lower than this value. + float confidence_threshold = 1; + + // Output only. Metrics are computed with an assumption that the model + // always returns at most this many predictions (ordered by their score, + // descendingly), but they all still need to meet the confidence_threshold. + int32 position_threshold = 14; + + // Output only. Recall (True Positive Rate) for the given confidence + // threshold. + float recall = 2; + + // Output only. Precision for the given confidence threshold. + float precision = 3; + + // Output only. False Positive Rate for the given confidence threshold. + float false_positive_rate = 8; + + // Output only. The harmonic mean of recall and precision. + float f1_score = 4; + + // Output only. The Recall (True Positive Rate) when only considering the + // label that has the highest prediction score and not below the confidence + // threshold for each example. + float recall_at1 = 5; + + // Output only. The precision when only considering the label that has the + // highest prediction score and not below the confidence threshold for each + // example. + float precision_at1 = 6; + + // Output only. The False Positive Rate when only considering the label that + // has the highest prediction score and not below the confidence threshold + // for each example. + float false_positive_rate_at1 = 9; + + // Output only. The harmonic mean of [recall_at1][google.cloud.automl.v1beta1.ClassificationEvaluationMetrics.ConfidenceMetricsEntry.recall_at1] and [precision_at1][google.cloud.automl.v1beta1.ClassificationEvaluationMetrics.ConfidenceMetricsEntry.precision_at1]. + float f1_score_at1 = 7; + + // Output only. The number of model created labels that match a ground truth + // label. + int64 true_positive_count = 10; + + // Output only. The number of model created labels that do not match a + // ground truth label. + int64 false_positive_count = 11; + + // Output only. The number of ground truth labels that are not matched + // by a model created label. + int64 false_negative_count = 12; + + // Output only. The number of labels that were not created by the model, + // but if they would, they would not match a ground truth label. + int64 true_negative_count = 13; + } + + // Confusion matrix of the model running the classification. + message ConfusionMatrix { + // Output only. A row in the confusion matrix. + message Row { + // Output only. Value of the specific cell in the confusion matrix. + // The number of values each row has (i.e. the length of the row) is equal + // to the length of the `annotation_spec_id` field or, if that one is not + // populated, length of the [display_name][google.cloud.automl.v1beta1.ClassificationEvaluationMetrics.ConfusionMatrix.display_name] field. + repeated int32 example_count = 1; + } + + // Output only. IDs of the annotation specs used in the confusion matrix. + // For Tables CLASSIFICATION + // + // [prediction_type][google.cloud.automl.v1beta1.TablesModelMetadata.prediction_type] + // only list of [annotation_spec_display_name-s][] is populated. + repeated string annotation_spec_id = 1; + + // Output only. Display name of the annotation specs used in the confusion + // matrix, as they were at the moment of the evaluation. For Tables + // CLASSIFICATION + // + // [prediction_type-s][google.cloud.automl.v1beta1.TablesModelMetadata.prediction_type], + // distinct values of the target column at the moment of the model + // evaluation are populated here. + repeated string display_name = 3; + + // Output only. Rows in the confusion matrix. The number of rows is equal to + // the size of `annotation_spec_id`. + // `row[i].example_count[j]` is the number of examples that have ground + // truth of the `annotation_spec_id[i]` and are predicted as + // `annotation_spec_id[j]` by the model being evaluated. + repeated Row row = 2; + } + + // Output only. The Area Under Precision-Recall Curve metric. Micro-averaged + // for the overall evaluation. + float au_prc = 1; + + // Output only. The Area Under Precision-Recall Curve metric based on priors. + // Micro-averaged for the overall evaluation. + // Deprecated. + float base_au_prc = 2 [deprecated = true]; + + // Output only. The Area Under Receiver Operating Characteristic curve metric. + // Micro-averaged for the overall evaluation. + float au_roc = 6; + + // Output only. The Log Loss metric. + float log_loss = 7; + + // Output only. Metrics for each confidence_threshold in + // 0.00,0.05,0.10,...,0.95,0.96,0.97,0.98,0.99 and + // position_threshold = INT32_MAX_VALUE. + // ROC and precision-recall curves, and other aggregated metrics are derived + // from them. The confidence metrics entries may also be supplied for + // additional values of position_threshold, but from these no aggregated + // metrics are computed. + repeated ConfidenceMetricsEntry confidence_metrics_entry = 3; + + // Output only. Confusion matrix of the evaluation. + // Only set for MULTICLASS classification problems where number + // of labels is no more than 10. + // Only set for model level evaluation, not for evaluation per label. + ConfusionMatrix confusion_matrix = 4; + + // Output only. The annotation spec ids used for this evaluation. + repeated string annotation_spec_id = 5; +} diff --git a/google/cloud/automl_v1beta1/proto/column_spec.proto b/google/cloud/automl_v1beta1/proto/column_spec.proto new file mode 100644 index 00000000..03389b8a --- /dev/null +++ b/google/cloud/automl_v1beta1/proto/column_spec.proto @@ -0,0 +1,78 @@ +// 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. + +syntax = "proto3"; + +package google.cloud.automl.v1beta1; + +import "google/api/resource.proto"; +import "google/cloud/automl/v1beta1/data_stats.proto"; +import "google/cloud/automl/v1beta1/data_types.proto"; +import "google/api/annotations.proto"; + +option go_package = "google.golang.org/genproto/googleapis/cloud/automl/v1beta1;automl"; +option java_multiple_files = true; +option java_package = "com.google.cloud.automl.v1beta1"; +option php_namespace = "Google\\Cloud\\AutoMl\\V1beta1"; +option ruby_package = "Google::Cloud::AutoML::V1beta1"; + +// A representation of a column in a relational table. When listing them, column specs are returned in the same order in which they were +// given on import . +// Used by: +// * Tables +message ColumnSpec { + option (google.api.resource) = { + type: "automl.googleapis.com/ColumnSpec" + pattern: "projects/{project}/locations/{location}/datasets/{dataset}/tableSpecs/{table_spec}/columnSpecs/{column_spec}" + }; + + // Identifies the table's column, and its correlation with the column this + // ColumnSpec describes. + message CorrelatedColumn { + // The column_spec_id of the correlated column, which belongs to the same + // table as the in-context column. + string column_spec_id = 1; + + // Correlation between this and the in-context column. + CorrelationStats correlation_stats = 2; + } + + // Output only. The resource name of the column specs. + // Form: + // + // `projects/{project_id}/locations/{location_id}/datasets/{dataset_id}/tableSpecs/{table_spec_id}/columnSpecs/{column_spec_id}` + string name = 1; + + // The data type of elements stored in the column. + DataType data_type = 2; + + // Output only. The name of the column to show in the interface. The name can + // be up to 100 characters long and can consist only of ASCII Latin letters + // A-Z and a-z, ASCII digits 0-9, underscores(_), and forward slashes(/), and + // must start with a letter or a digit. + string display_name = 3; + + // Output only. Stats of the series of values in the column. + // This field may be stale, see the ancestor's + // Dataset.tables_dataset_metadata.stats_update_time field + // for the timestamp at which these stats were last updated. + DataStats data_stats = 4; + + // Deprecated. + repeated CorrelatedColumn top_correlated_columns = 5; + + // Used to perform consistent read-modify-write updates. If not set, a blind + // "overwrite" update happens. + string etag = 6; +} diff --git a/google/cloud/automl_v1beta1/proto/data_items.proto b/google/cloud/automl_v1beta1/proto/data_items.proto new file mode 100644 index 00000000..9b9187ad --- /dev/null +++ b/google/cloud/automl_v1beta1/proto/data_items.proto @@ -0,0 +1,221 @@ +// 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. + +syntax = "proto3"; + +package google.cloud.automl.v1beta1; + +import "google/cloud/automl/v1beta1/geometry.proto"; +import "google/cloud/automl/v1beta1/io.proto"; +import "google/cloud/automl/v1beta1/temporal.proto"; +import "google/cloud/automl/v1beta1/text_segment.proto"; +import "google/protobuf/any.proto"; +import "google/protobuf/duration.proto"; +import "google/protobuf/struct.proto"; +import "google/api/annotations.proto"; + +option go_package = "google.golang.org/genproto/googleapis/cloud/automl/v1beta1;automl"; +option java_multiple_files = true; +option java_package = "com.google.cloud.automl.v1beta1"; +option php_namespace = "Google\\Cloud\\AutoMl\\V1beta1"; +option ruby_package = "Google::Cloud::AutoML::V1beta1"; + +// A representation of an image. +// Only images up to 30MB in size are supported. +message Image { + // Input only. The data representing the image. + // For Predict calls [image_bytes][google.cloud.automl.v1beta1.Image.image_bytes] must be set, as other options are not + // currently supported by prediction API. You can read the contents of an + // uploaded image by using the [content_uri][google.cloud.automl.v1beta1.Image.content_uri] field. + oneof data { + // Image content represented as a stream of bytes. + // Note: As with all `bytes` fields, protobuffers use a pure binary + // representation, whereas JSON representations use base64. + bytes image_bytes = 1; + + // An input config specifying the content of the image. + InputConfig input_config = 6; + } + + // Output only. HTTP URI to the thumbnail image. + string thumbnail_uri = 4; +} + +// A representation of a text snippet. +message TextSnippet { + // Required. The content of the text snippet as a string. Up to 250000 + // characters long. + string content = 1; + + // Optional. The format of [content][google.cloud.automl.v1beta1.TextSnippet.content]. Currently the only two allowed + // values are "text/html" and "text/plain". If left blank, the format is + // automatically determined from the type of the uploaded [content][google.cloud.automl.v1beta1.TextSnippet.content]. + string mime_type = 2; + + // Output only. HTTP URI where you can download the content. + string content_uri = 4; +} + +// Message that describes dimension of a document. +message DocumentDimensions { + // Unit of the document dimension. + enum DocumentDimensionUnit { + // Should not be used. + DOCUMENT_DIMENSION_UNIT_UNSPECIFIED = 0; + + // Document dimension is measured in inches. + INCH = 1; + + // Document dimension is measured in centimeters. + CENTIMETER = 2; + + // Document dimension is measured in points. 72 points = 1 inch. + POINT = 3; + } + + // Unit of the dimension. + DocumentDimensionUnit unit = 1; + + // Width value of the document, works together with the unit. + float width = 2; + + // Height value of the document, works together with the unit. + float height = 3; +} + +// A structured text document e.g. a PDF. +message Document { + // Describes the layout information of a [text_segment][google.cloud.automl.v1beta1.Document.Layout.text_segment] in the document. + message Layout { + // The type of TextSegment in the context of the original document. + enum TextSegmentType { + // Should not be used. + TEXT_SEGMENT_TYPE_UNSPECIFIED = 0; + + // The text segment is a token. e.g. word. + TOKEN = 1; + + // The text segment is a paragraph. + PARAGRAPH = 2; + + // The text segment is a form field. + FORM_FIELD = 3; + + // The text segment is the name part of a form field. It will be treated + // as child of another FORM_FIELD TextSegment if its span is subspan of + // another TextSegment with type FORM_FIELD. + FORM_FIELD_NAME = 4; + + // The text segment is the text content part of a form field. It will be + // treated as child of another FORM_FIELD TextSegment if its span is + // subspan of another TextSegment with type FORM_FIELD. + FORM_FIELD_CONTENTS = 5; + + // The text segment is a whole table, including headers, and all rows. + TABLE = 6; + + // The text segment is a table's headers. It will be treated as child of + // another TABLE TextSegment if its span is subspan of another TextSegment + // with type TABLE. + TABLE_HEADER = 7; + + // The text segment is a row in table. It will be treated as child of + // another TABLE TextSegment if its span is subspan of another TextSegment + // with type TABLE. + TABLE_ROW = 8; + + // The text segment is a cell in table. It will be treated as child of + // another TABLE_ROW TextSegment if its span is subspan of another + // TextSegment with type TABLE_ROW. + TABLE_CELL = 9; + } + + // Text Segment that represents a segment in + // [document_text][google.cloud.automl.v1beta1.Document.document_text]. + TextSegment text_segment = 1; + + // Page number of the [text_segment][google.cloud.automl.v1beta1.Document.Layout.text_segment] in the original document, starts + // from 1. + int32 page_number = 2; + + // The position of the [text_segment][google.cloud.automl.v1beta1.Document.Layout.text_segment] in the page. + // Contains exactly 4 + // + // [normalized_vertices][google.cloud.automl.v1beta1.BoundingPoly.normalized_vertices] + // and they are connected by edges in the order provided, which will + // represent a rectangle parallel to the frame. The + // [NormalizedVertex-s][google.cloud.automl.v1beta1.NormalizedVertex] are + // relative to the page. + // Coordinates are based on top-left as point (0,0). + BoundingPoly bounding_poly = 3; + + // The type of the [text_segment][google.cloud.automl.v1beta1.Document.Layout.text_segment] in document. + TextSegmentType text_segment_type = 4; + } + + // An input config specifying the content of the document. + DocumentInputConfig input_config = 1; + + // The plain text version of this document. + TextSnippet document_text = 2; + + // Describes the layout of the document. + // Sorted by [page_number][]. + repeated Layout layout = 3; + + // The dimensions of the page in the document. + DocumentDimensions document_dimensions = 4; + + // Number of pages in the document. + int32 page_count = 5; +} + +// A representation of a row in a relational table. +message Row { + // The resource IDs of the column specs describing the columns of the row. + // If set must contain, but possibly in a different order, all input + // feature + // + // [column_spec_ids][google.cloud.automl.v1beta1.TablesModelMetadata.input_feature_column_specs] + // of the Model this row is being passed to. + // Note: The below `values` field must match order of this field, if this + // field is set. + repeated string column_spec_ids = 2; + + // Required. The values of the row cells, given in the same order as the + // column_spec_ids, or, if not set, then in the same order as input + // feature + // + // [column_specs][google.cloud.automl.v1beta1.TablesModelMetadata.input_feature_column_specs] + // of the Model this row is being passed to. + repeated google.protobuf.Value values = 3; +} + +// Example data used for training or prediction. +message ExamplePayload { + // Required. Input only. The example data. + oneof payload { + // Example image. + Image image = 1; + + // Example text. + TextSnippet text_snippet = 2; + + // Example document. + Document document = 4; + + // Example relational table row. + Row row = 3; + } +} diff --git a/google/cloud/automl_v1beta1/proto/data_stats.proto b/google/cloud/automl_v1beta1/proto/data_stats.proto new file mode 100644 index 00000000..c13a5d45 --- /dev/null +++ b/google/cloud/automl_v1beta1/proto/data_stats.proto @@ -0,0 +1,166 @@ +// 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. + +syntax = "proto3"; + +package google.cloud.automl.v1beta1; + +import "google/api/annotations.proto"; + +option go_package = "google.golang.org/genproto/googleapis/cloud/automl/v1beta1;automl"; +option java_multiple_files = true; +option java_package = "com.google.cloud.automl.v1beta1"; +option php_namespace = "Google\\Cloud\\AutoMl\\V1beta1"; +option ruby_package = "Google::Cloud::AutoML::V1beta1"; + +// The data statistics of a series of values that share the same DataType. +message DataStats { + // The data statistics specific to a DataType. + oneof stats { + // The statistics for FLOAT64 DataType. + Float64Stats float64_stats = 3; + + // The statistics for STRING DataType. + StringStats string_stats = 4; + + // The statistics for TIMESTAMP DataType. + TimestampStats timestamp_stats = 5; + + // The statistics for ARRAY DataType. + ArrayStats array_stats = 6; + + // The statistics for STRUCT DataType. + StructStats struct_stats = 7; + + // The statistics for CATEGORY DataType. + CategoryStats category_stats = 8; + } + + // The number of distinct values. + int64 distinct_value_count = 1; + + // The number of values that are null. + int64 null_value_count = 2; + + // The number of values that are valid. + int64 valid_value_count = 9; +} + +// The data statistics of a series of FLOAT64 values. +message Float64Stats { + // A bucket of a histogram. + message HistogramBucket { + // The minimum value of the bucket, inclusive. + double min = 1; + + // The maximum value of the bucket, exclusive unless max = `"Infinity"`, in + // which case it's inclusive. + double max = 2; + + // The number of data values that are in the bucket, i.e. are between + // min and max values. + int64 count = 3; + } + + // The mean of the series. + double mean = 1; + + // The standard deviation of the series. + double standard_deviation = 2; + + // Ordered from 0 to k k-quantile values of the data series of n values. + // The value at index i is, approximately, the i*n/k-th smallest value in the + // series; for i = 0 and i = k these are, respectively, the min and max + // values. + repeated double quantiles = 3; + + // Histogram buckets of the data series. Sorted by the min value of the + // bucket, ascendingly, and the number of the buckets is dynamically + // generated. The buckets are non-overlapping and completely cover whole + // FLOAT64 range with min of first bucket being `"-Infinity"`, and max of + // the last one being `"Infinity"`. + repeated HistogramBucket histogram_buckets = 4; +} + +// The data statistics of a series of STRING values. +message StringStats { + // The statistics of a unigram. + message UnigramStats { + // The unigram. + string value = 1; + + // The number of occurrences of this unigram in the series. + int64 count = 2; + } + + // The statistics of the top 20 unigrams, ordered by + // [count][google.cloud.automl.v1beta1.StringStats.UnigramStats.count]. + repeated UnigramStats top_unigram_stats = 1; +} + +// The data statistics of a series of TIMESTAMP values. +message TimestampStats { + // Stats split by a defined in context granularity. + message GranularStats { + // A map from granularity key to example count for that key. + // E.g. for hour_of_day `13` means 1pm, or for month_of_year `5` means May). + map buckets = 1; + } + + // The string key is the pre-defined granularity. Currently supported: + // hour_of_day, day_of_week, month_of_year. + // Granularities finer that the granularity of timestamp data are not + // populated (e.g. if timestamps are at day granularity, then hour_of_day + // is not populated). + map granular_stats = 1; +} + +// The data statistics of a series of ARRAY values. +message ArrayStats { + // Stats of all the values of all arrays, as if they were a single long + // series of data. The type depends on the element type of the array. + DataStats member_stats = 2; +} + +// The data statistics of a series of STRUCT values. +message StructStats { + // Map from a field name of the struct to data stats aggregated over series + // of all data in that field across all the structs. + map field_stats = 1; +} + +// The data statistics of a series of CATEGORY values. +message CategoryStats { + // The statistics of a single CATEGORY value. + message SingleCategoryStats { + // The CATEGORY value. + string value = 1; + + // The number of occurrences of this value in the series. + int64 count = 2; + } + + // The statistics of the top 20 CATEGORY values, ordered by + // + // [count][google.cloud.automl.v1beta1.CategoryStats.SingleCategoryStats.count]. + repeated SingleCategoryStats top_category_stats = 1; +} + +// A correlation statistics between two series of DataType values. The series +// may have differing DataType-s, but within a single series the DataType must +// be the same. +message CorrelationStats { + // The correlation value using the Cramer's V measure. + double cramers_v = 1; +} diff --git a/google/cloud/automl_v1beta1/proto/data_types.proto b/google/cloud/automl_v1beta1/proto/data_types.proto new file mode 100644 index 00000000..6f77f56b --- /dev/null +++ b/google/cloud/automl_v1beta1/proto/data_types.proto @@ -0,0 +1,105 @@ +// 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. + +syntax = "proto3"; + +package google.cloud.automl.v1beta1; + +import "google/api/annotations.proto"; + +option go_package = "google.golang.org/genproto/googleapis/cloud/automl/v1beta1;automl"; +option java_multiple_files = true; +option java_package = "com.google.cloud.automl.v1beta1"; +option php_namespace = "Google\\Cloud\\AutoMl\\V1beta1"; +option ruby_package = "Google::Cloud::AutoML::V1beta1"; + +// `TypeCode` is used as a part of +// [DataType][google.cloud.automl.v1beta1.DataType]. +enum TypeCode { + // Not specified. Should not be used. + TYPE_CODE_UNSPECIFIED = 0; + + // Encoded as `number`, or the strings `"NaN"`, `"Infinity"`, or + // `"-Infinity"`. + FLOAT64 = 3; + + // Must be between 0AD and 9999AD. Encoded as `string` according to + // [time_format][google.cloud.automl.v1beta1.DataType.time_format], or, if + // that format is not set, then in RFC 3339 `date-time` format, where + // `time-offset` = `"Z"` (e.g. 1985-04-12T23:20:50.52Z). + TIMESTAMP = 4; + + // Encoded as `string`. + STRING = 6; + + // Encoded as `list`, where the list elements are represented according to + // + // [list_element_type][google.cloud.automl.v1beta1.DataType.list_element_type]. + ARRAY = 8; + + // Encoded as `struct`, where field values are represented according to + // [struct_type][google.cloud.automl.v1beta1.DataType.struct_type]. + STRUCT = 9; + + // Values of this type are not further understood by AutoML, + // e.g. AutoML is unable to tell the order of values (as it could with + // FLOAT64), or is unable to say if one value contains another (as it + // could with STRING). + // Encoded as `string` (bytes should be base64-encoded, as described in RFC + // 4648, section 4). + CATEGORY = 10; +} + +// Indicated the type of data that can be stored in a structured data entity +// (e.g. a table). +message DataType { + // Details of DataType-s that need additional specification. + oneof details { + // If [type_code][google.cloud.automl.v1beta1.DataType.type_code] == [ARRAY][google.cloud.automl.v1beta1.TypeCode.ARRAY], + // then `list_element_type` is the type of the elements. + DataType list_element_type = 2; + + // If [type_code][google.cloud.automl.v1beta1.DataType.type_code] == [STRUCT][google.cloud.automl.v1beta1.TypeCode.STRUCT], then `struct_type` + // provides type information for the struct's fields. + StructType struct_type = 3; + + // If [type_code][google.cloud.automl.v1beta1.DataType.type_code] == [TIMESTAMP][google.cloud.automl.v1beta1.TypeCode.TIMESTAMP] + // then `time_format` provides the format in which that time field is + // expressed. The time_format must either be one of: + // * `UNIX_SECONDS` + // * `UNIX_MILLISECONDS` + // * `UNIX_MICROSECONDS` + // * `UNIX_NANOSECONDS` + // (for respectively number of seconds, milliseconds, microseconds and + // nanoseconds since start of the Unix epoch); + // or be written in `strftime` syntax. If time_format is not set, then the + // default format as described on the type_code is used. + string time_format = 5; + } + + // Required. The [TypeCode][google.cloud.automl.v1beta1.TypeCode] for this type. + TypeCode type_code = 1; + + // If true, this DataType can also be `NULL`. In .CSV files `NULL` value is + // expressed as an empty string. + bool nullable = 4; +} + +// `StructType` defines the DataType-s of a [STRUCT][google.cloud.automl.v1beta1.TypeCode.STRUCT] type. +message StructType { + // Unordered map of struct field names to their data types. + // Fields cannot be added or removed via Update. Their names and + // data types are still mutable. + map fields = 1; +} diff --git a/google/cloud/automl_v1beta1/proto/dataset.proto b/google/cloud/automl_v1beta1/proto/dataset.proto new file mode 100644 index 00000000..8d1b8d93 --- /dev/null +++ b/google/cloud/automl_v1beta1/proto/dataset.proto @@ -0,0 +1,96 @@ +// 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. + +syntax = "proto3"; + +package google.cloud.automl.v1beta1; + +import "google/api/resource.proto"; +import "google/cloud/automl/v1beta1/image.proto"; +import "google/cloud/automl/v1beta1/tables.proto"; +import "google/cloud/automl/v1beta1/text.proto"; +import "google/cloud/automl/v1beta1/translation.proto"; +import "google/cloud/automl/v1beta1/video.proto"; +import "google/protobuf/timestamp.proto"; +import "google/api/annotations.proto"; + +option go_package = "google.golang.org/genproto/googleapis/cloud/automl/v1beta1;automl"; +option java_multiple_files = true; +option java_package = "com.google.cloud.automl.v1beta1"; +option php_namespace = "Google\\Cloud\\AutoMl\\V1beta1"; +option ruby_package = "Google::Cloud::AutoML::V1beta1"; + +// A workspace for solving a single, particular machine learning (ML) problem. +// A workspace contains examples that may be annotated. +message Dataset { + option (google.api.resource) = { + type: "automl.googleapis.com/Dataset" + pattern: "projects/{project}/locations/{location}/datasets/{dataset}" + }; + + // Required. + // The dataset metadata that is specific to the problem type. + oneof dataset_metadata { + // Metadata for a dataset used for translation. + TranslationDatasetMetadata translation_dataset_metadata = 23; + + // Metadata for a dataset used for image classification. + ImageClassificationDatasetMetadata image_classification_dataset_metadata = 24; + + // Metadata for a dataset used for text classification. + TextClassificationDatasetMetadata text_classification_dataset_metadata = 25; + + // Metadata for a dataset used for image object detection. + ImageObjectDetectionDatasetMetadata image_object_detection_dataset_metadata = 26; + + // Metadata for a dataset used for video classification. + VideoClassificationDatasetMetadata video_classification_dataset_metadata = 31; + + // Metadata for a dataset used for video object tracking. + VideoObjectTrackingDatasetMetadata video_object_tracking_dataset_metadata = 29; + + // Metadata for a dataset used for text extraction. + TextExtractionDatasetMetadata text_extraction_dataset_metadata = 28; + + // Metadata for a dataset used for text sentiment. + TextSentimentDatasetMetadata text_sentiment_dataset_metadata = 30; + + // Metadata for a dataset used for Tables. + TablesDatasetMetadata tables_dataset_metadata = 33; + } + + // Output only. The resource name of the dataset. + // Form: `projects/{project_id}/locations/{location_id}/datasets/{dataset_id}` + string name = 1; + + // Required. The name of the dataset to show in the interface. The name can be + // up to 32 characters long and can consist only of ASCII Latin letters A-Z + // and a-z, underscores + // (_), and ASCII digits 0-9. + string display_name = 2; + + // User-provided description of the dataset. The description can be up to + // 25000 characters long. + string description = 3; + + // Output only. The number of examples in the dataset. + int32 example_count = 21; + + // Output only. Timestamp when this dataset was created. + google.protobuf.Timestamp create_time = 14; + + // Used to perform consistent read-modify-write updates. If not set, a blind + // "overwrite" update happens. + string etag = 17; +} diff --git a/google/cloud/automl_v1beta1/proto/detection.proto b/google/cloud/automl_v1beta1/proto/detection.proto new file mode 100644 index 00000000..c5864e20 --- /dev/null +++ b/google/cloud/automl_v1beta1/proto/detection.proto @@ -0,0 +1,135 @@ +// 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. + +syntax = "proto3"; + +package google.cloud.automl.v1beta1; + +import "google/cloud/automl/v1beta1/geometry.proto"; +import "google/protobuf/duration.proto"; +import "google/api/annotations.proto"; + +option go_package = "google.golang.org/genproto/googleapis/cloud/automl/v1beta1;automl"; +option java_multiple_files = true; +option java_package = "com.google.cloud.automl.v1beta1"; +option php_namespace = "Google\\Cloud\\AutoMl\\V1beta1"; +option ruby_package = "Google::Cloud::AutoML::V1beta1"; + +// Annotation details for image object detection. +message ImageObjectDetectionAnnotation { + // Output only. The rectangle representing the object location. + BoundingPoly bounding_box = 1; + + // Output only. The confidence that this annotation is positive for the parent example, + // value in [0, 1], higher means higher positivity confidence. + float score = 2; +} + +// Annotation details for video object tracking. +message VideoObjectTrackingAnnotation { + // Optional. The instance of the object, expressed as a positive integer. Used to tell + // apart objects of the same type (i.e. AnnotationSpec) when multiple are + // present on a single example. + // NOTE: Instance ID prediction quality is not a part of model evaluation and + // is done as best effort. Especially in cases when an entity goes + // off-screen for a longer time (minutes), when it comes back it may be given + // a new instance ID. + string instance_id = 1; + + // Required. A time (frame) of a video to which this annotation pertains. + // Represented as the duration since the video's start. + google.protobuf.Duration time_offset = 2; + + // Required. The rectangle representing the object location on the frame (i.e. + // at the time_offset of the video). + BoundingPoly bounding_box = 3; + + // Output only. The confidence that this annotation is positive for the video at + // the time_offset, value in [0, 1], higher means higher positivity + // confidence. For annotations created by the user the score is 1. When + // user approves an annotation, the original float score is kept (and not + // changed to 1). + float score = 4; +} + +// Bounding box matching model metrics for a single intersection-over-union +// threshold and multiple label match confidence thresholds. +message BoundingBoxMetricsEntry { + // Metrics for a single confidence threshold. + message ConfidenceMetricsEntry { + // Output only. The confidence threshold value used to compute the metrics. + float confidence_threshold = 1; + + // Output only. Recall under the given confidence threshold. + float recall = 2; + + // Output only. Precision under the given confidence threshold. + float precision = 3; + + // Output only. The harmonic mean of recall and precision. + float f1_score = 4; + } + + // Output only. The intersection-over-union threshold value used to compute + // this metrics entry. + float iou_threshold = 1; + + // Output only. The mean average precision, most often close to au_prc. + float mean_average_precision = 2; + + // Output only. Metrics for each label-match confidence_threshold from + // 0.05,0.10,...,0.95,0.96,0.97,0.98,0.99. Precision-recall curve is + // derived from them. + repeated ConfidenceMetricsEntry confidence_metrics_entries = 3; +} + +// Model evaluation metrics for image object detection problems. +// Evaluates prediction quality of labeled bounding boxes. +message ImageObjectDetectionEvaluationMetrics { + // Output only. The total number of bounding boxes (i.e. summed over all + // images) the ground truth used to create this evaluation had. + int32 evaluated_bounding_box_count = 1; + + // Output only. The bounding boxes match metrics for each + // Intersection-over-union threshold 0.05,0.10,...,0.95,0.96,0.97,0.98,0.99 + // and each label confidence threshold 0.05,0.10,...,0.95,0.96,0.97,0.98,0.99 + // pair. + repeated BoundingBoxMetricsEntry bounding_box_metrics_entries = 2; + + // Output only. The single metric for bounding boxes evaluation: + // the mean_average_precision averaged over all bounding_box_metrics_entries. + float bounding_box_mean_average_precision = 3; +} + +// Model evaluation metrics for video object tracking problems. +// Evaluates prediction quality of both labeled bounding boxes and labeled +// tracks (i.e. series of bounding boxes sharing same label and instance ID). +message VideoObjectTrackingEvaluationMetrics { + // Output only. The number of video frames used to create this evaluation. + int32 evaluated_frame_count = 1; + + // Output only. The total number of bounding boxes (i.e. summed over all + // frames) the ground truth used to create this evaluation had. + int32 evaluated_bounding_box_count = 2; + + // Output only. The bounding boxes match metrics for each + // Intersection-over-union threshold 0.05,0.10,...,0.95,0.96,0.97,0.98,0.99 + // and each label confidence threshold 0.05,0.10,...,0.95,0.96,0.97,0.98,0.99 + // pair. + repeated BoundingBoxMetricsEntry bounding_box_metrics_entries = 4; + + // Output only. The single metric for bounding boxes evaluation: + // the mean_average_precision averaged over all bounding_box_metrics_entries. + float bounding_box_mean_average_precision = 6; +} diff --git a/google/cloud/automl_v1beta1/proto/geometry.proto b/google/cloud/automl_v1beta1/proto/geometry.proto new file mode 100644 index 00000000..d5654aac --- /dev/null +++ b/google/cloud/automl_v1beta1/proto/geometry.proto @@ -0,0 +1,46 @@ +// 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. + +syntax = "proto3"; + +package google.cloud.automl.v1beta1; + +import "google/api/annotations.proto"; + +option go_package = "google.golang.org/genproto/googleapis/cloud/automl/v1beta1;automl"; +option java_multiple_files = true; +option java_package = "com.google.cloud.automl.v1beta1"; +option php_namespace = "Google\\Cloud\\AutoMl\\V1beta1"; +option ruby_package = "Google::Cloud::AutoML::V1beta1"; + +// A vertex represents a 2D point in the image. +// The normalized vertex coordinates are between 0 to 1 fractions relative to +// the original plane (image, video). E.g. if the plane (e.g. whole image) would +// have size 10 x 20 then a point with normalized coordinates (0.1, 0.3) would +// be at the position (1, 6) on that plane. +message NormalizedVertex { + // Required. Horizontal coordinate. + float x = 1; + + // Required. Vertical coordinate. + float y = 2; +} + +// A bounding polygon of a detected object on a plane. +// On output both vertices and normalized_vertices are provided. +// The polygon is formed by connecting vertices in the order they are listed. +message BoundingPoly { + // Output only . The bounding polygon normalized vertices. + repeated NormalizedVertex normalized_vertices = 2; +} diff --git a/google/cloud/automl_v1beta1/proto/image.proto b/google/cloud/automl_v1beta1/proto/image.proto new file mode 100644 index 00000000..960eaeb0 --- /dev/null +++ b/google/cloud/automl_v1beta1/proto/image.proto @@ -0,0 +1,193 @@ +// 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. + +syntax = "proto3"; + +package google.cloud.automl.v1beta1; + +import "google/api/resource.proto"; +import "google/cloud/automl/v1beta1/annotation_spec.proto"; +import "google/cloud/automl/v1beta1/classification.proto"; +import "google/protobuf/timestamp.proto"; +import "google/api/annotations.proto"; + +option go_package = "google.golang.org/genproto/googleapis/cloud/automl/v1beta1;automl"; +option java_multiple_files = true; +option java_outer_classname = "ImageProto"; +option java_package = "com.google.cloud.automl.v1beta1"; +option php_namespace = "Google\\Cloud\\AutoMl\\V1beta1"; +option ruby_package = "Google::Cloud::AutoML::V1beta1"; + +// Dataset metadata that is specific to image classification. +message ImageClassificationDatasetMetadata { + // Required. Type of the classification problem. + ClassificationType classification_type = 1; +} + +// Dataset metadata specific to image object detection. +message ImageObjectDetectionDatasetMetadata { + +} + +// Model metadata for image classification. +message ImageClassificationModelMetadata { + // Optional. The ID of the `base` model. If it is specified, the new model + // will be created based on the `base` model. Otherwise, the new model will be + // created from scratch. The `base` model must be in the same + // `project` and `location` as the new model to create, and have the same + // `model_type`. + string base_model_id = 1; + + // Required. The train budget of creating this model, expressed in hours. The + // actual `train_cost` will be equal or less than this value. + int64 train_budget = 2; + + // Output only. The actual train cost of creating this model, expressed in + // hours. If this model is created from a `base` model, the train cost used + // to create the `base` model are not included. + int64 train_cost = 3; + + // Output only. The reason that this create model operation stopped, + // e.g. `BUDGET_REACHED`, `MODEL_CONVERGED`. + string stop_reason = 5; + + // Optional. Type of the model. The available values are: + // * `cloud` - Model to be used via prediction calls to AutoML API. + // This is the default value. + // * `mobile-low-latency-1` - A model that, in addition to providing + // prediction via AutoML API, can also be exported (see + // [AutoMl.ExportModel][google.cloud.automl.v1beta1.AutoMl.ExportModel]) and used on a mobile or edge device + // with TensorFlow afterwards. Expected to have low latency, but + // may have lower prediction quality than other models. + // * `mobile-versatile-1` - A model that, in addition to providing + // prediction via AutoML API, can also be exported (see + // [AutoMl.ExportModel][google.cloud.automl.v1beta1.AutoMl.ExportModel]) and used on a mobile or edge device + // with TensorFlow afterwards. + // * `mobile-high-accuracy-1` - A model that, in addition to providing + // prediction via AutoML API, can also be exported (see + // [AutoMl.ExportModel][google.cloud.automl.v1beta1.AutoMl.ExportModel]) and used on a mobile or edge device + // with TensorFlow afterwards. Expected to have a higher + // latency, but should also have a higher prediction quality + // than other models. + // * `mobile-core-ml-low-latency-1` - A model that, in addition to providing + // prediction via AutoML API, can also be exported (see + // [AutoMl.ExportModel][google.cloud.automl.v1beta1.AutoMl.ExportModel]) and used on a mobile device with Core + // ML afterwards. Expected to have low latency, but may have + // lower prediction quality than other models. + // * `mobile-core-ml-versatile-1` - A model that, in addition to providing + // prediction via AutoML API, can also be exported (see + // [AutoMl.ExportModel][google.cloud.automl.v1beta1.AutoMl.ExportModel]) and used on a mobile device with Core + // ML afterwards. + // * `mobile-core-ml-high-accuracy-1` - A model that, in addition to + // providing prediction via AutoML API, can also be exported + // (see [AutoMl.ExportModel][google.cloud.automl.v1beta1.AutoMl.ExportModel]) and used on a mobile device with + // Core ML afterwards. Expected to have a higher latency, but + // should also have a higher prediction quality than other + // models. + string model_type = 7; + + // Output only. An approximate number of online prediction QPS that can + // be supported by this model per each node on which it is deployed. + double node_qps = 13; + + // Output only. The number of nodes this model is deployed on. A node is an + // abstraction of a machine resource, which can handle online prediction QPS + // as given in the node_qps field. + int64 node_count = 14; +} + +// Model metadata specific to image object detection. +message ImageObjectDetectionModelMetadata { + // Optional. Type of the model. The available values are: + // * `cloud-high-accuracy-1` - (default) A model to be used via prediction + // calls to AutoML API. Expected to have a higher latency, but + // should also have a higher prediction quality than other + // models. + // * `cloud-low-latency-1` - A model to be used via prediction + // calls to AutoML API. Expected to have low latency, but may + // have lower prediction quality than other models. + // * `mobile-low-latency-1` - A model that, in addition to providing + // prediction via AutoML API, can also be exported (see + // [AutoMl.ExportModel][google.cloud.automl.v1beta1.AutoMl.ExportModel]) and used on a mobile or edge device + // with TensorFlow afterwards. Expected to have low latency, but + // may have lower prediction quality than other models. + // * `mobile-versatile-1` - A model that, in addition to providing + // prediction via AutoML API, can also be exported (see + // [AutoMl.ExportModel][google.cloud.automl.v1beta1.AutoMl.ExportModel]) and used on a mobile or edge device + // with TensorFlow afterwards. + // * `mobile-high-accuracy-1` - A model that, in addition to providing + // prediction via AutoML API, can also be exported (see + // [AutoMl.ExportModel][google.cloud.automl.v1beta1.AutoMl.ExportModel]) and used on a mobile or edge device + // with TensorFlow afterwards. Expected to have a higher + // latency, but should also have a higher prediction quality + // than other models. + string model_type = 1; + + // Output only. The number of nodes this model is deployed on. A node is an + // abstraction of a machine resource, which can handle online prediction QPS + // as given in the qps_per_node field. + int64 node_count = 3; + + // Output only. An approximate number of online prediction QPS that can + // be supported by this model per each node on which it is deployed. + double node_qps = 4; + + // Output only. The reason that this create model operation stopped, + // e.g. `BUDGET_REACHED`, `MODEL_CONVERGED`. + string stop_reason = 5; + + // The train budget of creating this model, expressed in milli node + // hours i.e. 1,000 value in this field means 1 node hour. The actual + // `train_cost` will be equal or less than this value. If further model + // training ceases to provide any improvements, it will stop without using + // full budget and the stop_reason will be `MODEL_CONVERGED`. + // Note, node_hour = actual_hour * number_of_nodes_invovled. + // For model type `cloud-high-accuracy-1`(default) and `cloud-low-latency-1`, + // the train budget must be between 20,000 and 900,000 milli node hours, + // inclusive. The default value is 216, 000 which represents one day in + // wall time. + // For model type `mobile-low-latency-1`, `mobile-versatile-1`, + // `mobile-high-accuracy-1`, `mobile-core-ml-low-latency-1`, + // `mobile-core-ml-versatile-1`, `mobile-core-ml-high-accuracy-1`, the train + // budget must be between 1,000 and 100,000 milli node hours, inclusive. + // The default value is 24, 000 which represents one day in wall time. + int64 train_budget_milli_node_hours = 6; + + // Output only. The actual train cost of creating this model, expressed in + // milli node hours, i.e. 1,000 value in this field means 1 node hour. + // Guaranteed to not exceed the train budget. + int64 train_cost_milli_node_hours = 7; +} + +// Model deployment metadata specific to Image Classification. +message ImageClassificationModelDeploymentMetadata { + // Input only. The number of nodes to deploy the model on. A node is an + // abstraction of a machine resource, which can handle online prediction QPS + // as given in the model's + // + // [node_qps][google.cloud.automl.v1beta1.ImageClassificationModelMetadata.node_qps]. + // Must be between 1 and 100, inclusive on both ends. + int64 node_count = 1; +} + +// Model deployment metadata specific to Image Object Detection. +message ImageObjectDetectionModelDeploymentMetadata { + // Input only. The number of nodes to deploy the model on. A node is an + // abstraction of a machine resource, which can handle online prediction QPS + // as given in the model's + // + // [qps_per_node][google.cloud.automl.v1beta1.ImageObjectDetectionModelMetadata.qps_per_node]. + // Must be between 1 and 100, inclusive on both ends. + int64 node_count = 1; +} diff --git a/google/cloud/automl_v1beta1/proto/io.proto b/google/cloud/automl_v1beta1/proto/io.proto new file mode 100644 index 00000000..3d8ab45f --- /dev/null +++ b/google/cloud/automl_v1beta1/proto/io.proto @@ -0,0 +1,1158 @@ +// 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. + +syntax = "proto3"; + +package google.cloud.automl.v1beta1; + +import "google/api/annotations.proto"; + +option go_package = "google.golang.org/genproto/googleapis/cloud/automl/v1beta1;automl"; +option java_multiple_files = true; +option java_package = "com.google.cloud.automl.v1beta1"; +option php_namespace = "Google\\Cloud\\AutoMl\\V1beta1"; +option ruby_package = "Google::Cloud::AutoML::V1beta1"; + +// Input configuration for ImportData Action. +// +// The format of input depends on dataset_metadata the Dataset into which +// the import is happening has. As input source the +// [gcs_source][google.cloud.automl.v1beta1.InputConfig.gcs_source] +// is expected, unless specified otherwise. Additionally any input .CSV file +// by itself must be 100MB or smaller, unless specified otherwise. +// If an "example" file (that is, image, video etc.) with identical content +// (even if it had different GCS_FILE_PATH) is mentioned multiple times, then +// its label, bounding boxes etc. are appended. The same file should be always +// provided with the same ML_USE and GCS_FILE_PATH, if it is not, then +// these values are nondeterministically selected from the given ones. +// +// The formats are represented in EBNF with commas being literal and with +// non-terminal symbols defined near the end of this comment. The formats are: +// +// * For Image Classification: +// CSV file(s) with each line in format: +// ML_USE,GCS_FILE_PATH,LABEL,LABEL,... +// GCS_FILE_PATH leads to image of up to 30MB in size. Supported +// extensions: .JPEG, .GIF, .PNG, .WEBP, .BMP, .TIFF, .ICO +// For MULTICLASS classification type, at most one LABEL is allowed +// per image. If an image has not yet been labeled, then it should be +// mentioned just once with no LABEL. +// Some sample rows: +// TRAIN,gs://folder/image1.jpg,daisy +// TEST,gs://folder/image2.jpg,dandelion,tulip,rose +// UNASSIGNED,gs://folder/image3.jpg,daisy +// UNASSIGNED,gs://folder/image4.jpg +// +// * For Image Object Detection: +// CSV file(s) with each line in format: +// ML_USE,GCS_FILE_PATH,(LABEL,BOUNDING_BOX | ,,,,,,,) +// GCS_FILE_PATH leads to image of up to 30MB in size. Supported +// extensions: .JPEG, .GIF, .PNG. +// Each image is assumed to be exhaustively labeled. The minimum +// allowed BOUNDING_BOX edge length is 0.01, and no more than 500 +// BOUNDING_BOX-es per image are allowed (one BOUNDING_BOX is defined +// per line). If an image has not yet been labeled, then it should be +// mentioned just once with no LABEL and the ",,,,,,," in place of the +// BOUNDING_BOX. For images which are known to not contain any +// bounding boxes, they should be labelled explictly as +// "NEGATIVE_IMAGE", followed by ",,,,,,," in place of the +// BOUNDING_BOX. +// Sample rows: +// TRAIN,gs://folder/image1.png,car,0.1,0.1,,,0.3,0.3,, +// TRAIN,gs://folder/image1.png,bike,.7,.6,,,.8,.9,, +// UNASSIGNED,gs://folder/im2.png,car,0.1,0.1,0.2,0.1,0.2,0.3,0.1,0.3 +// TEST,gs://folder/im3.png,,,,,,,,, +// TRAIN,gs://folder/im4.png,NEGATIVE_IMAGE,,,,,,,,, +// +// * For Video Classification: +// CSV file(s) with each line in format: +// ML_USE,GCS_FILE_PATH +// where ML_USE VALIDATE value should not be used. The GCS_FILE_PATH +// should lead to another .csv file which describes examples that have +// given ML_USE, using the following row format: +// GCS_FILE_PATH,(LABEL,TIME_SEGMENT_START,TIME_SEGMENT_END | ,,) +// Here GCS_FILE_PATH leads to a video of up to 50GB in size and up +// to 3h duration. Supported extensions: .MOV, .MPEG4, .MP4, .AVI. +// TIME_SEGMENT_START and TIME_SEGMENT_END must be within the +// length of the video, and end has to be after the start. Any segment +// of a video which has one or more labels on it, is considered a +// hard negative for all other labels. Any segment with no labels on +// it is considered to be unknown. If a whole video is unknown, then +// it shuold be mentioned just once with ",," in place of LABEL, +// TIME_SEGMENT_START,TIME_SEGMENT_END. +// Sample top level CSV file: +// TRAIN,gs://folder/train_videos.csv +// TEST,gs://folder/test_videos.csv +// UNASSIGNED,gs://folder/other_videos.csv +// Sample rows of a CSV file for a particular ML_USE: +// gs://folder/video1.avi,car,120,180.000021 +// gs://folder/video1.avi,bike,150,180.000021 +// gs://folder/vid2.avi,car,0,60.5 +// gs://folder/vid3.avi,,, +// +// * For Video Object Tracking: +// CSV file(s) with each line in format: +// ML_USE,GCS_FILE_PATH +// where ML_USE VALIDATE value should not be used. The GCS_FILE_PATH +// should lead to another .csv file which describes examples that have +// given ML_USE, using one of the following row format: +// GCS_FILE_PATH,LABEL,[INSTANCE_ID],TIMESTAMP,BOUNDING_BOX +// or +// GCS_FILE_PATH,,,,,,,,,, +// Here GCS_FILE_PATH leads to a video of up to 50GB in size and up +// to 3h duration. Supported extensions: .MOV, .MPEG4, .MP4, .AVI. +// Providing INSTANCE_IDs can help to obtain a better model. When +// a specific labeled entity leaves the video frame, and shows up +// afterwards it is not required, albeit preferable, that the same +// INSTANCE_ID is given to it. +// TIMESTAMP must be within the length of the video, the +// BOUNDING_BOX is assumed to be drawn on the closest video's frame +// to the TIMESTAMP. Any mentioned by the TIMESTAMP frame is expected +// to be exhaustively labeled and no more than 500 BOUNDING_BOX-es per +// frame are allowed. If a whole video is unknown, then it should be +// mentioned just once with ",,,,,,,,,," in place of LABEL, +// [INSTANCE_ID],TIMESTAMP,BOUNDING_BOX. +// Sample top level CSV file: +// TRAIN,gs://folder/train_videos.csv +// TEST,gs://folder/test_videos.csv +// UNASSIGNED,gs://folder/other_videos.csv +// Seven sample rows of a CSV file for a particular ML_USE: +// gs://folder/video1.avi,car,1,12.10,0.8,0.8,0.9,0.8,0.9,0.9,0.8,0.9 +// gs://folder/video1.avi,car,1,12.90,0.4,0.8,0.5,0.8,0.5,0.9,0.4,0.9 +// gs://folder/video1.avi,car,2,12.10,.4,.2,.5,.2,.5,.3,.4,.3 +// gs://folder/video1.avi,car,2,12.90,.8,.2,,,.9,.3,, +// gs://folder/video1.avi,bike,,12.50,.45,.45,,,.55,.55,, +// gs://folder/video2.avi,car,1,0,.1,.9,,,.9,.1,, +// gs://folder/video2.avi,,,,,,,,,,, +// * For Text Extraction: +// CSV file(s) with each line in format: +// ML_USE,GCS_FILE_PATH +// GCS_FILE_PATH leads to a .JSONL (that is, JSON Lines) file which +// either imports text in-line or as documents. Any given +// .JSONL file must be 100MB or smaller. +// The in-line .JSONL file contains, per line, a proto that wraps a +// TextSnippet proto (in json representation) followed by one or more +// AnnotationPayload protos (called annotations), which have +// display_name and text_extraction detail populated. The given text +// is expected to be annotated exhaustively, for example, if you look +// for animals and text contains "dolphin" that is not labeled, then +// "dolphin" is assumed to not be an animal. Any given text snippet +// content must be 10KB or smaller, and also be UTF-8 NFC encoded +// (ASCII already is). +// The document .JSONL file contains, per line, a proto that wraps a +// Document proto. The Document proto must have either document_text +// or input_config set. In document_text case, the Document proto may +// also contain the spatial information of the document, including +// layout, document dimension and page number. In input_config case, +// only PDF documents are supported now, and each document may be up +// to 2MB large. Currently, annotations on documents cannot be +// specified at import. +// Three sample CSV rows: +// TRAIN,gs://folder/file1.jsonl +// VALIDATE,gs://folder/file2.jsonl +// TEST,gs://folder/file3.jsonl +// Sample in-line JSON Lines file for entity extraction (presented here +// with artificial line breaks, but the only actual line break is +// denoted by \n).: +// { +// "document": { +// "document_text": {"content": "dog cat"} +// "layout": [ +// { +// "text_segment": { +// "start_offset": 0, +// "end_offset": 3, +// }, +// "page_number": 1, +// "bounding_poly": { +// "normalized_vertices": [ +// {"x": 0.1, "y": 0.1}, +// {"x": 0.1, "y": 0.3}, +// {"x": 0.3, "y": 0.3}, +// {"x": 0.3, "y": 0.1}, +// ], +// }, +// "text_segment_type": TOKEN, +// }, +// { +// "text_segment": { +// "start_offset": 4, +// "end_offset": 7, +// }, +// "page_number": 1, +// "bounding_poly": { +// "normalized_vertices": [ +// {"x": 0.4, "y": 0.1}, +// {"x": 0.4, "y": 0.3}, +// {"x": 0.8, "y": 0.3}, +// {"x": 0.8, "y": 0.1}, +// ], +// }, +// "text_segment_type": TOKEN, +// } +// +// ], +// "document_dimensions": { +// "width": 8.27, +// "height": 11.69, +// "unit": INCH, +// } +// "page_count": 1, +// }, +// "annotations": [ +// { +// "display_name": "animal", +// "text_extraction": {"text_segment": {"start_offset": 0, +// "end_offset": 3}} +// }, +// { +// "display_name": "animal", +// "text_extraction": {"text_segment": {"start_offset": 4, +// "end_offset": 7}} +// } +// ], +// }\n +// { +// "text_snippet": { +// "content": "This dog is good." +// }, +// "annotations": [ +// { +// "display_name": "animal", +// "text_extraction": { +// "text_segment": {"start_offset": 5, "end_offset": 8} +// } +// } +// ] +// } +// Sample document JSON Lines file (presented here with artificial line +// breaks, but the only actual line break is denoted by \n).: +// { +// "document": { +// "input_config": { +// "gcs_source": { "input_uris": [ "gs://folder/document1.pdf" ] +// } +// } +// } +// }\n +// { +// "document": { +// "input_config": { +// "gcs_source": { "input_uris": [ "gs://folder/document2.pdf" ] +// } +// } +// } +// } +// +// * For Text Classification: +// CSV file(s) with each line in format: +// ML_USE,(TEXT_SNIPPET | GCS_FILE_PATH),LABEL,LABEL,... +// TEXT_SNIPPET and GCS_FILE_PATH are distinguished by a pattern. If +// the column content is a valid gcs file path, i.e. prefixed by +// "gs://", it will be treated as a GCS_FILE_PATH, else if the content +// is enclosed within double quotes (""), it is +// treated as a TEXT_SNIPPET. In the GCS_FILE_PATH case, the path +// must lead to a .txt file with UTF-8 encoding, for example, +// "gs://folder/content.txt", and the content in it is extracted +// as a text snippet. In TEXT_SNIPPET case, the column content +// excluding quotes is treated as to be imported text snippet. In +// both cases, the text snippet/file size must be within 128kB. +// Maximum 100 unique labels are allowed per CSV row. +// Sample rows: +// TRAIN,"They have bad food and very rude",RudeService,BadFood +// TRAIN,gs://folder/content.txt,SlowService +// TEST,"Typically always bad service there.",RudeService +// VALIDATE,"Stomach ache to go.",BadFood +// +// * For Text Sentiment: +// CSV file(s) with each line in format: +// ML_USE,(TEXT_SNIPPET | GCS_FILE_PATH),SENTIMENT +// TEXT_SNIPPET and GCS_FILE_PATH are distinguished by a pattern. If +// the column content is a valid gcs file path, that is, prefixed by +// "gs://", it is treated as a GCS_FILE_PATH, otherwise it is treated +// as a TEXT_SNIPPET. In the GCS_FILE_PATH case, the path +// must lead to a .txt file with UTF-8 encoding, for example, +// "gs://folder/content.txt", and the content in it is extracted +// as a text snippet. In TEXT_SNIPPET case, the column content itself +// is treated as to be imported text snippet. In both cases, the +// text snippet must be up to 500 characters long. +// Sample rows: +// TRAIN,"@freewrytin this is way too good for your product",2 +// TRAIN,"I need this product so bad",3 +// TEST,"Thank you for this product.",4 +// VALIDATE,gs://folder/content.txt,2 +// +// * For Tables: +// Either +// [gcs_source][google.cloud.automl.v1beta1.InputConfig.gcs_source] or +// +// [bigquery_source][google.cloud.automl.v1beta1.InputConfig.bigquery_source] +// can be used. All inputs is concatenated into a single +// +// [primary_table][google.cloud.automl.v1beta1.TablesDatasetMetadata.primary_table_name] +// For gcs_source: +// CSV file(s), where the first row of the first file is the header, +// containing unique column names. If the first row of a subsequent +// file is the same as the header, then it is also treated as a +// header. All other rows contain values for the corresponding +// columns. +// Each .CSV file by itself must be 10GB or smaller, and their total +// size must be 100GB or smaller. +// First three sample rows of a CSV file: +// "Id","First Name","Last Name","Dob","Addresses" +// +// "1","John","Doe","1968-01-22","[{"status":"current","address":"123_First_Avenue","city":"Seattle","state":"WA","zip":"11111","numberOfYears":"1"},{"status":"previous","address":"456_Main_Street","city":"Portland","state":"OR","zip":"22222","numberOfYears":"5"}]" +// +// "2","Jane","Doe","1980-10-16","[{"status":"current","address":"789_Any_Avenue","city":"Albany","state":"NY","zip":"33333","numberOfYears":"2"},{"status":"previous","address":"321_Main_Street","city":"Hoboken","state":"NJ","zip":"44444","numberOfYears":"3"}]} +// For bigquery_source: +// An URI of a BigQuery table. The user data size of the BigQuery +// table must be 100GB or smaller. +// An imported table must have between 2 and 1,000 columns, inclusive, +// and between 1000 and 100,000,000 rows, inclusive. There are at most 5 +// import data running in parallel. +// Definitions: +// ML_USE = "TRAIN" | "VALIDATE" | "TEST" | "UNASSIGNED" +// Describes how the given example (file) should be used for model +// training. "UNASSIGNED" can be used when user has no preference. +// GCS_FILE_PATH = A path to file on GCS, e.g. "gs://folder/image1.png". +// LABEL = A display name of an object on an image, video etc., e.g. "dog". +// Must be up to 32 characters long and can consist only of ASCII +// Latin letters A-Z and a-z, underscores(_), and ASCII digits 0-9. +// For each label an AnnotationSpec is created which display_name +// becomes the label; AnnotationSpecs are given back in predictions. +// INSTANCE_ID = A positive integer that identifies a specific instance of a +// labeled entity on an example. Used e.g. to track two cars on +// a video while being able to tell apart which one is which. +// BOUNDING_BOX = VERTEX,VERTEX,VERTEX,VERTEX | VERTEX,,,VERTEX,, +// A rectangle parallel to the frame of the example (image, +// video). If 4 vertices are given they are connected by edges +// in the order provided, if 2 are given they are recognized +// as diagonally opposite vertices of the rectangle. +// VERTEX = COORDINATE,COORDINATE +// First coordinate is horizontal (x), the second is vertical (y). +// COORDINATE = A float in 0 to 1 range, relative to total length of +// image or video in given dimension. For fractions the +// leading non-decimal 0 can be omitted (i.e. 0.3 = .3). +// Point 0,0 is in top left. +// TIME_SEGMENT_START = TIME_OFFSET +// Expresses a beginning, inclusive, of a time segment +// within an example that has a time dimension +// (e.g. video). +// TIME_SEGMENT_END = TIME_OFFSET +// Expresses an end, exclusive, of a time segment within +// an example that has a time dimension (e.g. video). +// TIME_OFFSET = A number of seconds as measured from the start of an +// example (e.g. video). Fractions are allowed, up to a +// microsecond precision. "inf" is allowed, and it means the end +// of the example. +// TEXT_SNIPPET = A content of a text snippet, UTF-8 encoded, enclosed within +// double quotes (""). +// SENTIMENT = An integer between 0 and +// Dataset.text_sentiment_dataset_metadata.sentiment_max +// (inclusive). Describes the ordinal of the sentiment - higher +// value means a more positive sentiment. All the values are +// completely relative, i.e. neither 0 needs to mean a negative or +// neutral sentiment nor sentiment_max needs to mean a positive one +// - it is just required that 0 is the least positive sentiment +// in the data, and sentiment_max is the most positive one. +// The SENTIMENT shouldn't be confused with "score" or "magnitude" +// from the previous Natural Language Sentiment Analysis API. +// All SENTIMENT values between 0 and sentiment_max must be +// represented in the imported data. On prediction the same 0 to +// sentiment_max range will be used. The difference between +// neighboring sentiment values needs not to be uniform, e.g. 1 and +// 2 may be similar whereas the difference between 2 and 3 may be +// huge. +// +// Errors: +// If any of the provided CSV files can't be parsed or if more than certain +// percent of CSV rows cannot be processed then the operation fails and +// nothing is imported. Regardless of overall success or failure the per-row +// failures, up to a certain count cap, is listed in +// Operation.metadata.partial_failures. +// +message InputConfig { + // The source of the input. + oneof source { + // The Google Cloud Storage location for the input content. + // In ImportData, the gcs_source points to a csv with structure described in + // the comment. + GcsSource gcs_source = 1; + + // The BigQuery location for the input content. + BigQuerySource bigquery_source = 3; + } + + // Additional domain-specific parameters describing the semantic of the + // imported data, any string must be up to 25000 + // characters long. + // + // * For Tables: + // `schema_inference_version` - (integer) Required. The version of the + // algorithm that should be used for the initial inference of the + // schema (columns' DataTypes) of the table the data is being imported + // into. Allowed values: "1". + map params = 2; +} + +// Input configuration for BatchPredict Action. +// +// The format of input depends on the ML problem of the model used for +// prediction. As input source the +// [gcs_source][google.cloud.automl.v1beta1.InputConfig.gcs_source] +// is expected, unless specified otherwise. +// +// The formats are represented in EBNF with commas being literal and with +// non-terminal symbols defined near the end of this comment. The formats +// are: +// +// * For Image Classification: +// CSV file(s) with each line having just a single column: +// GCS_FILE_PATH +// which leads to image of up to 30MB in size. Supported +// extensions: .JPEG, .GIF, .PNG. This path is treated as the ID in +// the Batch predict output. +// Three sample rows: +// gs://folder/image1.jpeg +// gs://folder/image2.gif +// gs://folder/image3.png +// +// * For Image Object Detection: +// CSV file(s) with each line having just a single column: +// GCS_FILE_PATH +// which leads to image of up to 30MB in size. Supported +// extensions: .JPEG, .GIF, .PNG. This path is treated as the ID in +// the Batch predict output. +// Three sample rows: +// gs://folder/image1.jpeg +// gs://folder/image2.gif +// gs://folder/image3.png +// * For Video Classification: +// CSV file(s) with each line in format: +// GCS_FILE_PATH,TIME_SEGMENT_START,TIME_SEGMENT_END +// GCS_FILE_PATH leads to video of up to 50GB in size and up to 3h +// duration. Supported extensions: .MOV, .MPEG4, .MP4, .AVI. +// TIME_SEGMENT_START and TIME_SEGMENT_END must be within the +// length of the video, and end has to be after the start. +// Three sample rows: +// gs://folder/video1.mp4,10,40 +// gs://folder/video1.mp4,20,60 +// gs://folder/vid2.mov,0,inf +// +// * For Video Object Tracking: +// CSV file(s) with each line in format: +// GCS_FILE_PATH,TIME_SEGMENT_START,TIME_SEGMENT_END +// GCS_FILE_PATH leads to video of up to 50GB in size and up to 3h +// duration. Supported extensions: .MOV, .MPEG4, .MP4, .AVI. +// TIME_SEGMENT_START and TIME_SEGMENT_END must be within the +// length of the video, and end has to be after the start. +// Three sample rows: +// gs://folder/video1.mp4,10,240 +// gs://folder/video1.mp4,300,360 +// gs://folder/vid2.mov,0,inf +// * For Text Classification: +// CSV file(s) with each line having just a single column: +// GCS_FILE_PATH | TEXT_SNIPPET +// Any given text file can have size upto 128kB. +// Any given text snippet content must have 60,000 characters or less. +// Three sample rows: +// gs://folder/text1.txt +// "Some text content to predict" +// gs://folder/text3.pdf +// Supported file extensions: .txt, .pdf +// +// * For Text Sentiment: +// CSV file(s) with each line having just a single column: +// GCS_FILE_PATH | TEXT_SNIPPET +// Any given text file can have size upto 128kB. +// Any given text snippet content must have 500 characters or less. +// Three sample rows: +// gs://folder/text1.txt +// "Some text content to predict" +// gs://folder/text3.pdf +// Supported file extensions: .txt, .pdf +// +// * For Text Extraction +// .JSONL (i.e. JSON Lines) file(s) which either provide text in-line or +// as documents (for a single BatchPredict call only one of the these +// formats may be used). +// The in-line .JSONL file(s) contain per line a proto that +// wraps a temporary user-assigned TextSnippet ID (string up to 2000 +// characters long) called "id", a TextSnippet proto (in +// json representation) and zero or more TextFeature protos. Any given +// text snippet content must have 30,000 characters or less, and also +// be UTF-8 NFC encoded (ASCII already is). The IDs provided should be +// unique. +// The document .JSONL file(s) contain, per line, a proto that wraps a +// Document proto with input_config set. Only PDF documents are +// supported now, and each document must be up to 2MB large. +// Any given .JSONL file must be 100MB or smaller, and no more than 20 +// files may be given. +// Sample in-line JSON Lines file (presented here with artificial line +// breaks, but the only actual line break is denoted by \n): +// { +// "id": "my_first_id", +// "text_snippet": { "content": "dog car cat"}, +// "text_features": [ +// { +// "text_segment": {"start_offset": 4, "end_offset": 6}, +// "structural_type": PARAGRAPH, +// "bounding_poly": { +// "normalized_vertices": [ +// {"x": 0.1, "y": 0.1}, +// {"x": 0.1, "y": 0.3}, +// {"x": 0.3, "y": 0.3}, +// {"x": 0.3, "y": 0.1}, +// ] +// }, +// } +// ], +// }\n +// { +// "id": "2", +// "text_snippet": { +// "content": "An elaborate content", +// "mime_type": "text/plain" +// } +// } +// Sample document JSON Lines file (presented here with artificial line +// breaks, but the only actual line break is denoted by \n).: +// { +// "document": { +// "input_config": { +// "gcs_source": { "input_uris": [ "gs://folder/document1.pdf" ] +// } +// } +// } +// }\n +// { +// "document": { +// "input_config": { +// "gcs_source": { "input_uris": [ "gs://folder/document2.pdf" ] +// } +// } +// } +// } +// +// * For Tables: +// Either +// [gcs_source][google.cloud.automl.v1beta1.InputConfig.gcs_source] or +// +// [bigquery_source][google.cloud.automl.v1beta1.InputConfig.bigquery_source]. +// GCS case: +// CSV file(s), each by itself 10GB or smaller and total size must be +// 100GB or smaller, where first file must have a header containing +// column names. If the first row of a subsequent file is the same as +// the header, then it is also treated as a header. All other rows +// contain values for the corresponding columns. +// The column names must contain the model's +// +// [input_feature_column_specs'][google.cloud.automl.v1beta1.TablesModelMetadata.input_feature_column_specs] +// +// [display_name-s][google.cloud.automl.v1beta1.ColumnSpec.display_name] +// (order doesn't matter). The columns corresponding to the model's +// input feature column specs must contain values compatible with the +// column spec's data types. Prediction on all the rows, i.e. the CSV +// lines, will be attempted. For FORECASTING +// +// [prediction_type][google.cloud.automl.v1beta1.TablesModelMetadata.prediction_type]: +// all columns having +// +// [TIME_SERIES_AVAILABLE_PAST_ONLY][google.cloud.automl.v1beta1.ColumnSpec.ForecastingMetadata.ColumnType] +// type will be ignored. +// First three sample rows of a CSV file: +// "First Name","Last Name","Dob","Addresses" +// +// "John","Doe","1968-01-22","[{"status":"current","address":"123_First_Avenue","city":"Seattle","state":"WA","zip":"11111","numberOfYears":"1"},{"status":"previous","address":"456_Main_Street","city":"Portland","state":"OR","zip":"22222","numberOfYears":"5"}]" +// +// "Jane","Doe","1980-10-16","[{"status":"current","address":"789_Any_Avenue","city":"Albany","state":"NY","zip":"33333","numberOfYears":"2"},{"status":"previous","address":"321_Main_Street","city":"Hoboken","state":"NJ","zip":"44444","numberOfYears":"3"}]} +// BigQuery case: +// An URI of a BigQuery table. The user data size of the BigQuery +// table must be 100GB or smaller. +// The column names must contain the model's +// +// [input_feature_column_specs'][google.cloud.automl.v1beta1.TablesModelMetadata.input_feature_column_specs] +// +// [display_name-s][google.cloud.automl.v1beta1.ColumnSpec.display_name] +// (order doesn't matter). The columns corresponding to the model's +// input feature column specs must contain values compatible with the +// column spec's data types. Prediction on all the rows of the table +// will be attempted. For FORECASTING +// +// [prediction_type][google.cloud.automl.v1beta1.TablesModelMetadata.prediction_type]: +// all columns having +// +// [TIME_SERIES_AVAILABLE_PAST_ONLY][google.cloud.automl.v1beta1.ColumnSpec.ForecastingMetadata.ColumnType] +// type will be ignored. +// +// Definitions: +// GCS_FILE_PATH = A path to file on GCS, e.g. "gs://folder/video.avi". +// TEXT_SNIPPET = A content of a text snippet, UTF-8 encoded, enclosed within +// double quotes ("") +// TIME_SEGMENT_START = TIME_OFFSET +// Expresses a beginning, inclusive, of a time segment +// within an +// example that has a time dimension (e.g. video). +// TIME_SEGMENT_END = TIME_OFFSET +// Expresses an end, exclusive, of a time segment within +// an example that has a time dimension (e.g. video). +// TIME_OFFSET = A number of seconds as measured from the start of an +// example (e.g. video). Fractions are allowed, up to a +// microsecond precision. "inf" is allowed and it means the end +// of the example. +// +// Errors: +// If any of the provided CSV files can't be parsed or if more than certain +// percent of CSV rows cannot be processed then the operation fails and +// prediction does not happen. Regardless of overall success or failure the +// per-row failures, up to a certain count cap, will be listed in +// Operation.metadata.partial_failures. +message BatchPredictInputConfig { + // Required. The source of the input. + oneof source { + // The Google Cloud Storage location for the input content. + GcsSource gcs_source = 1; + + // The BigQuery location for the input content. + BigQuerySource bigquery_source = 2; + } +} + +// Input configuration of a [Document][google.cloud.automl.v1beta1.Document]. +message DocumentInputConfig { + // The Google Cloud Storage location of the document file. Only a single path + // should be given. + // Max supported size: 512MB. + // Supported extensions: .PDF. + GcsSource gcs_source = 1; +} + +// * For Translation: +// CSV file `translation.csv`, with each line in format: +// ML_USE,GCS_FILE_PATH +// GCS_FILE_PATH leads to a .TSV file which describes examples that have +// given ML_USE, using the following row format per line: +// TEXT_SNIPPET (in source language) \t TEXT_SNIPPET (in target +// language) +// +// * For Tables: +// Output depends on whether the dataset was imported from GCS or +// BigQuery. +// GCS case: +// +// [gcs_destination][google.cloud.automl.v1beta1.OutputConfig.gcs_destination] +// must be set. Exported are CSV file(s) `tables_1.csv`, +// `tables_2.csv`,...,`tables_N.csv` with each having as header line +// the table's column names, and all other lines contain values for +// the header columns. +// BigQuery case: +// +// [bigquery_destination][google.cloud.automl.v1beta1.OutputConfig.bigquery_destination] +// pointing to a BigQuery project must be set. In the given project a +// new dataset will be created with name +// +// `export_data__` +// where will be made +// BigQuery-dataset-name compatible (e.g. most special characters will +// become underscores), and timestamp will be in +// YYYY_MM_DDThh_mm_ss_sssZ "based on ISO-8601" format. In that +// dataset a new table called `primary_table` will be created, and +// filled with precisely the same data as this obtained on import. +message OutputConfig { + // Required. The destination of the output. + oneof destination { + // The Google Cloud Storage location where the output is to be written to. + // For Image Object Detection, Text Extraction, Video Classification and + // Tables, in the given directory a new directory will be created with name: + // export_data-- where + // timestamp is in YYYY-MM-DDThh:mm:ss.sssZ ISO-8601 format. All export + // output will be written into that directory. + GcsDestination gcs_destination = 1; + + // The BigQuery location where the output is to be written to. + BigQueryDestination bigquery_destination = 2; + } +} + +// Output configuration for BatchPredict Action. +// +// As destination the +// +// [gcs_destination][google.cloud.automl.v1beta1.BatchPredictOutputConfig.gcs_destination] +// must be set unless specified otherwise for a domain. If gcs_destination is +// set then in the given directory a new directory is created. Its name +// will be +// "prediction--", +// where timestamp is in YYYY-MM-DDThh:mm:ss.sssZ ISO-8601 format. The contents +// of it depends on the ML problem the predictions are made for. +// +// * For Image Classification: +// In the created directory files `image_classification_1.jsonl`, +// `image_classification_2.jsonl`,...,`image_classification_N.jsonl` +// will be created, where N may be 1, and depends on the +// total number of the successfully predicted images and annotations. +// A single image will be listed only once with all its annotations, +// and its annotations will never be split across files. +// Each .JSONL file will contain, per line, a JSON representation of a +// proto that wraps image's "ID" : "" followed by a list of +// zero or more AnnotationPayload protos (called annotations), which +// have classification detail populated. +// If prediction for any image failed (partially or completely), then an +// additional `errors_1.jsonl`, `errors_2.jsonl`,..., `errors_N.jsonl` +// files will be created (N depends on total number of failed +// predictions). These files will have a JSON representation of a proto +// that wraps the same "ID" : "" but here followed by +// exactly one +// +// [`google.rpc.Status`](https: +// //github.com/googleapis/googleapis/blob/master/google/rpc/status.proto) +// containing only `code` and `message`fields. +// +// * For Image Object Detection: +// In the created directory files `image_object_detection_1.jsonl`, +// `image_object_detection_2.jsonl`,...,`image_object_detection_N.jsonl` +// will be created, where N may be 1, and depends on the +// total number of the successfully predicted images and annotations. +// Each .JSONL file will contain, per line, a JSON representation of a +// proto that wraps image's "ID" : "" followed by a list of +// zero or more AnnotationPayload protos (called annotations), which +// have image_object_detection detail populated. A single image will +// be listed only once with all its annotations, and its annotations +// will never be split across files. +// If prediction for any image failed (partially or completely), then +// additional `errors_1.jsonl`, `errors_2.jsonl`,..., `errors_N.jsonl` +// files will be created (N depends on total number of failed +// predictions). These files will have a JSON representation of a proto +// that wraps the same "ID" : "" but here followed by +// exactly one +// +// [`google.rpc.Status`](https: +// //github.com/googleapis/googleapis/blob/master/google/rpc/status.proto) +// containing only `code` and `message`fields. +// * For Video Classification: +// In the created directory a video_classification.csv file, and a .JSON +// file per each video classification requested in the input (i.e. each +// line in given CSV(s)), will be created. +// +// The format of video_classification.csv is: +// +// GCS_FILE_PATH,TIME_SEGMENT_START,TIME_SEGMENT_END,JSON_FILE_NAME,STATUS +// where: +// GCS_FILE_PATH,TIME_SEGMENT_START,TIME_SEGMENT_END = matches 1 to 1 +// the prediction input lines (i.e. video_classification.csv has +// precisely the same number of lines as the prediction input had.) +// JSON_FILE_NAME = Name of .JSON file in the output directory, which +// contains prediction responses for the video time segment. +// STATUS = "OK" if prediction completed successfully, or an error code +// with message otherwise. If STATUS is not "OK" then the .JSON file +// for that line may not exist or be empty. +// +// Each .JSON file, assuming STATUS is "OK", will contain a list of +// AnnotationPayload protos in JSON format, which are the predictions +// for the video time segment the file is assigned to in the +// video_classification.csv. All AnnotationPayload protos will have +// video_classification field set, and will be sorted by +// video_classification.type field (note that the returned types are +// governed by `classifaction_types` parameter in +// [PredictService.BatchPredictRequest.params][]). +// +// * For Video Object Tracking: +// In the created directory a video_object_tracking.csv file will be +// created, and multiple files video_object_trackinng_1.json, +// video_object_trackinng_2.json,..., video_object_trackinng_N.json, +// where N is the number of requests in the input (i.e. the number of +// lines in given CSV(s)). +// +// The format of video_object_tracking.csv is: +// +// GCS_FILE_PATH,TIME_SEGMENT_START,TIME_SEGMENT_END,JSON_FILE_NAME,STATUS +// where: +// GCS_FILE_PATH,TIME_SEGMENT_START,TIME_SEGMENT_END = matches 1 to 1 +// the prediction input lines (i.e. video_object_tracking.csv has +// precisely the same number of lines as the prediction input had.) +// JSON_FILE_NAME = Name of .JSON file in the output directory, which +// contains prediction responses for the video time segment. +// STATUS = "OK" if prediction completed successfully, or an error +// code with message otherwise. If STATUS is not "OK" then the .JSON +// file for that line may not exist or be empty. +// +// Each .JSON file, assuming STATUS is "OK", will contain a list of +// AnnotationPayload protos in JSON format, which are the predictions +// for each frame of the video time segment the file is assigned to in +// video_object_tracking.csv. All AnnotationPayload protos will have +// video_object_tracking field set. +// * For Text Classification: +// In the created directory files `text_classification_1.jsonl`, +// `text_classification_2.jsonl`,...,`text_classification_N.jsonl` +// will be created, where N may be 1, and depends on the +// total number of inputs and annotations found. +// +// Each .JSONL file will contain, per line, a JSON representation of a +// proto that wraps input text snippet or input text file and a list of +// zero or more AnnotationPayload protos (called annotations), which +// have classification detail populated. A single text snippet or file +// will be listed only once with all its annotations, and its +// annotations will never be split across files. +// +// If prediction for any text snippet or file failed (partially or +// completely), then additional `errors_1.jsonl`, `errors_2.jsonl`,..., +// `errors_N.jsonl` files will be created (N depends on total number of +// failed predictions). These files will have a JSON representation of a +// proto that wraps input text snippet or input text file followed by +// exactly one +// +// [`google.rpc.Status`](https: +// //github.com/googleapis/googleapis/blob/master/google/rpc/status.proto) +// containing only `code` and `message`. +// +// * For Text Sentiment: +// In the created directory files `text_sentiment_1.jsonl`, +// `text_sentiment_2.jsonl`,...,`text_sentiment_N.jsonl` +// will be created, where N may be 1, and depends on the +// total number of inputs and annotations found. +// +// Each .JSONL file will contain, per line, a JSON representation of a +// proto that wraps input text snippet or input text file and a list of +// zero or more AnnotationPayload protos (called annotations), which +// have text_sentiment detail populated. A single text snippet or file +// will be listed only once with all its annotations, and its +// annotations will never be split across files. +// +// If prediction for any text snippet or file failed (partially or +// completely), then additional `errors_1.jsonl`, `errors_2.jsonl`,..., +// `errors_N.jsonl` files will be created (N depends on total number of +// failed predictions). These files will have a JSON representation of a +// proto that wraps input text snippet or input text file followed by +// exactly one +// +// [`google.rpc.Status`](https: +// //github.com/googleapis/googleapis/blob/master/google/rpc/status.proto) +// containing only `code` and `message`. +// +// * For Text Extraction: +// In the created directory files `text_extraction_1.jsonl`, +// `text_extraction_2.jsonl`,...,`text_extraction_N.jsonl` +// will be created, where N may be 1, and depends on the +// total number of inputs and annotations found. +// The contents of these .JSONL file(s) depend on whether the input +// used inline text, or documents. +// If input was inline, then each .JSONL file will contain, per line, +// a JSON representation of a proto that wraps given in request text +// snippet's "id" (if specified), followed by input text snippet, +// and a list of zero or more +// AnnotationPayload protos (called annotations), which have +// text_extraction detail populated. A single text snippet will be +// listed only once with all its annotations, and its annotations will +// never be split across files. +// If input used documents, then each .JSONL file will contain, per +// line, a JSON representation of a proto that wraps given in request +// document proto, followed by its OCR-ed representation in the form +// of a text snippet, finally followed by a list of zero or more +// AnnotationPayload protos (called annotations), which have +// text_extraction detail populated and refer, via their indices, to +// the OCR-ed text snippet. A single document (and its text snippet) +// will be listed only once with all its annotations, and its +// annotations will never be split across files. +// If prediction for any text snippet failed (partially or completely), +// then additional `errors_1.jsonl`, `errors_2.jsonl`,..., +// `errors_N.jsonl` files will be created (N depends on total number of +// failed predictions). These files will have a JSON representation of a +// proto that wraps either the "id" : "" (in case of inline) +// or the document proto (in case of document) but here followed by +// exactly one +// +// [`google.rpc.Status`](https: +// //github.com/googleapis/googleapis/blob/master/google/rpc/status.proto) +// containing only `code` and `message`. +// +// * For Tables: +// Output depends on whether +// +// [gcs_destination][google.cloud.automl.v1beta1.BatchPredictOutputConfig.gcs_destination] +// or +// +// [bigquery_destination][google.cloud.automl.v1beta1.BatchPredictOutputConfig.bigquery_destination] +// is set (either is allowed). +// GCS case: +// In the created directory files `tables_1.csv`, `tables_2.csv`,..., +// `tables_N.csv` will be created, where N may be 1, and depends on +// the total number of the successfully predicted rows. +// For all CLASSIFICATION +// +// [prediction_type-s][google.cloud.automl.v1beta1.TablesModelMetadata.prediction_type]: +// Each .csv file will contain a header, listing all columns' +// +// [display_name-s][google.cloud.automl.v1beta1.ColumnSpec.display_name] +// given on input followed by M target column names in the format of +// +// "<[target_column_specs][google.cloud.automl.v1beta1.TablesModelMetadata.target_column_spec] +// +// [display_name][google.cloud.automl.v1beta1.ColumnSpec.display_name]>__score" where M is the number of distinct target values, +// i.e. number of distinct values in the target column of the table +// used to train the model. Subsequent lines will contain the +// respective values of successfully predicted rows, with the last, +// i.e. the target, columns having the corresponding prediction +// [scores][google.cloud.automl.v1beta1.TablesAnnotation.score]. +// For REGRESSION and FORECASTING +// +// [prediction_type-s][google.cloud.automl.v1beta1.TablesModelMetadata.prediction_type]: +// Each .csv file will contain a header, listing all columns' +// [display_name-s][google.cloud.automl.v1beta1.display_name] given +// on input followed by the predicted target column with name in the +// format of +// +// "predicted_<[target_column_specs][google.cloud.automl.v1beta1.TablesModelMetadata.target_column_spec] +// +// [display_name][google.cloud.automl.v1beta1.ColumnSpec.display_name]>" +// Subsequent lines will contain the respective values of +// successfully predicted rows, with the last, i.e. the target, +// column having the predicted target value. +// If prediction for any rows failed, then an additional +// `errors_1.csv`, `errors_2.csv`,..., `errors_N.csv` will be +// created (N depends on total number of failed rows). These files +// will have analogous format as `tables_*.csv`, but always with a +// single target column having +// +// [`google.rpc.Status`](https: +// //github.com/googleapis/googleapis/blob/master/google/rpc/status.proto) +// represented as a JSON string, and containing only `code` and +// `message`. +// BigQuery case: +// +// [bigquery_destination][google.cloud.automl.v1beta1.OutputConfig.bigquery_destination] +// pointing to a BigQuery project must be set. In the given project a +// new dataset will be created with name +// `prediction__` +// where will be made +// BigQuery-dataset-name compatible (e.g. most special characters will +// become underscores), and timestamp will be in +// YYYY_MM_DDThh_mm_ss_sssZ "based on ISO-8601" format. In the dataset +// two tables will be created, `predictions`, and `errors`. +// The `predictions` table's column names will be the input columns' +// +// [display_name-s][google.cloud.automl.v1beta1.ColumnSpec.display_name] +// followed by the target column with name in the format of +// +// "predicted_<[target_column_specs][google.cloud.automl.v1beta1.TablesModelMetadata.target_column_spec] +// +// [display_name][google.cloud.automl.v1beta1.ColumnSpec.display_name]>" +// The input feature columns will contain the respective values of +// successfully predicted rows, with the target column having an +// ARRAY of +// +// [AnnotationPayloads][google.cloud.automl.v1beta1.AnnotationPayload], +// represented as STRUCT-s, containing +// [TablesAnnotation][google.cloud.automl.v1beta1.TablesAnnotation]. +// The `errors` table contains rows for which the prediction has +// failed, it has analogous input columns while the target column name +// is in the format of +// +// "errors_<[target_column_specs][google.cloud.automl.v1beta1.TablesModelMetadata.target_column_spec] +// +// [display_name][google.cloud.automl.v1beta1.ColumnSpec.display_name]>", +// and as a value has +// +// [`google.rpc.Status`](https: +// //github.com/googleapis/googleapis/blob/master/google/rpc/status.proto) +// represented as a STRUCT, and containing only `code` and `message`. +message BatchPredictOutputConfig { + // Required. The destination of the output. + oneof destination { + // The Google Cloud Storage location of the directory where the output is to + // be written to. + GcsDestination gcs_destination = 1; + + // The BigQuery location where the output is to be written to. + BigQueryDestination bigquery_destination = 2; + } +} + +// Output configuration for ModelExport Action. +message ModelExportOutputConfig { + // Required. The destination of the output. + oneof destination { + // The Google Cloud Storage location where the model is to be written to. + // This location may only be set for the following model formats: + // "tflite", "edgetpu_tflite", "tf_saved_model", "tf_js", "core_ml". + // + // Under the directory given as the destination a new one with name + // "model-export--", + // where timestamp is in YYYY-MM-DDThh:mm:ss.sssZ ISO-8601 format, + // will be created. Inside the model and any of its supporting files + // will be written. + GcsDestination gcs_destination = 1; + + // The GCR location where model image is to be pushed to. This location + // may only be set for the following model formats: + // "docker". + // + // The model image will be created under the given URI. + GcrDestination gcr_destination = 3; + } + + // The format in which the model must be exported. The available, and default, + // formats depend on the problem and model type (if given problem and type + // combination doesn't have a format listed, it means its models are not + // exportable): + // + // * For Image Classification mobile-low-latency-1, mobile-versatile-1, + // mobile-high-accuracy-1: + // "tflite" (default), "edgetpu_tflite", "tf_saved_model", "tf_js", + // "docker". + // + // * For Image Classification mobile-core-ml-low-latency-1, + // mobile-core-ml-versatile-1, mobile-core-ml-high-accuracy-1: + // "core_ml" (default). + // + // * For Image Object Detection mobile-low-latency-1, mobile-versatile-1, + // mobile-high-accuracy-1: + // "tflite", "tf_saved_model", "tf_js". + // + // * For Video Classification cloud, + // "tf_saved_model". + // + // * For Video Object Tracking cloud, + // "tf_saved_model". + // + // * For Video Object Tracking mobile-versatile-1: + // "tflite", "edgetpu_tflite", "tf_saved_model", "docker". + // + // * For Video Object Tracking mobile-coral-versatile-1: + // "tflite", "edgetpu_tflite", "docker". + // + // * For Video Object Tracking mobile-coral-low-latency-1: + // "tflite", "edgetpu_tflite", "docker". + // + // * For Video Object Tracking mobile-jetson-versatile-1: + // "tf_saved_model", "docker". + // + // * For Tables: + // "docker". + // + // Formats description: + // + // * tflite - Used for Android mobile devices. + // * edgetpu_tflite - Used for [Edge TPU](https://cloud.google.com/edge-tpu/) + // devices. + // * tf_saved_model - A tensorflow model in SavedModel format. + // * tf_js - A [TensorFlow.js](https://www.tensorflow.org/js) model that can + // be used in the browser and in Node.js using JavaScript. + // * docker - Used for Docker containers. Use the params field to customize + // the container. The container is verified to work correctly on + // ubuntu 16.04 operating system. See more at + // [containers + // + // quickstart](https: + // //cloud.google.com/vision/automl/docs/containers-gcs-quickstart) + // * core_ml - Used for iOS mobile devices. + string model_format = 4; + + // Additional model-type and format specific parameters describing the + // requirements for the to be exported model files, any string must be up to + // 25000 characters long. + // + // * For `docker` format: + // `cpu_architecture` - (string) "x86_64" (default). + // `gpu_architecture` - (string) "none" (default), "nvidia". + map params = 2; +} + +// Output configuration for ExportEvaluatedExamples Action. Note that this call +// is available only for 30 days since the moment the model was evaluated. +// The output depends on the domain, as follows (note that only examples from +// the TEST set are exported): +// +// * For Tables: +// +// [bigquery_destination][google.cloud.automl.v1beta1.OutputConfig.bigquery_destination] +// pointing to a BigQuery project must be set. In the given project a +// new dataset will be created with name +// +// `export_evaluated_examples__` +// where will be made BigQuery-dataset-name +// compatible (e.g. most special characters will become underscores), +// and timestamp will be in YYYY_MM_DDThh_mm_ss_sssZ "based on ISO-8601" +// format. In the dataset an `evaluated_examples` table will be +// created. It will have all the same columns as the +// +// [primary_table][google.cloud.automl.v1beta1.TablesDatasetMetadata.primary_table_spec_id] +// of the +// [dataset][google.cloud.automl.v1beta1.Model.dataset_id] from which +// the model was created, as they were at the moment of model's +// evaluation (this includes the target column with its ground +// truth), followed by a column called "predicted_". That +// last column will contain the model's prediction result for each +// respective row, given as ARRAY of +// [AnnotationPayloads][google.cloud.automl.v1beta1.AnnotationPayload], +// represented as STRUCT-s, containing +// [TablesAnnotation][google.cloud.automl.v1beta1.TablesAnnotation]. +message ExportEvaluatedExamplesOutputConfig { + // Required. The destination of the output. + oneof destination { + // The BigQuery location where the output is to be written to. + BigQueryDestination bigquery_destination = 2; + } +} + +// The Google Cloud Storage location for the input content. +message GcsSource { + // Required. Google Cloud Storage URIs to input files, up to 2000 characters + // long. Accepted forms: + // * Full object path, e.g. gs://bucket/directory/object.csv + repeated string input_uris = 1; +} + +// The BigQuery location for the input content. +message BigQuerySource { + // Required. BigQuery URI to a table, up to 2000 characters long. + // Accepted forms: + // * BigQuery path e.g. bq://projectId.bqDatasetId.bqTableId + string input_uri = 1; +} + +// The Google Cloud Storage location where the output is to be written to. +message GcsDestination { + // Required. Google Cloud Storage URI to output directory, up to 2000 + // characters long. + // Accepted forms: + // * Prefix path: gs://bucket/directory + // The requesting user must have write permission to the bucket. + // The directory is created if it doesn't exist. + string output_uri_prefix = 1; +} + +// The BigQuery location for the output content. +message BigQueryDestination { + // Required. BigQuery URI to a project, up to 2000 characters long. + // Accepted forms: + // * BigQuery path e.g. bq://projectId + string output_uri = 1; +} + +// The GCR location where the image must be pushed to. +message GcrDestination { + // Required. Google Contained Registry URI of the new image, up to 2000 + // characters long. See + // + // https: + // //cloud.google.com/container-registry/do + // // cs/pushing-and-pulling#pushing_an_image_to_a_registry + // Accepted forms: + // * [HOSTNAME]/[PROJECT-ID]/[IMAGE] + // * [HOSTNAME]/[PROJECT-ID]/[IMAGE]:[TAG] + // + // The requesting user must have permission to push images the project. + string output_uri = 1; +} diff --git a/google/cloud/automl_v1beta1/proto/model.proto b/google/cloud/automl_v1beta1/proto/model.proto new file mode 100644 index 00000000..2b2e8d73 --- /dev/null +++ b/google/cloud/automl_v1beta1/proto/model.proto @@ -0,0 +1,108 @@ +// 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. + +syntax = "proto3"; + +package google.cloud.automl.v1beta1; + +import "google/api/resource.proto"; +import "google/cloud/automl/v1beta1/image.proto"; +import "google/cloud/automl/v1beta1/tables.proto"; +import "google/cloud/automl/v1beta1/text.proto"; +import "google/cloud/automl/v1beta1/translation.proto"; +import "google/cloud/automl/v1beta1/video.proto"; +import "google/protobuf/timestamp.proto"; +import "google/api/annotations.proto"; + +option go_package = "google.golang.org/genproto/googleapis/cloud/automl/v1beta1;automl"; +option java_multiple_files = true; +option java_package = "com.google.cloud.automl.v1beta1"; +option php_namespace = "Google\\Cloud\\AutoMl\\V1beta1"; +option ruby_package = "Google::Cloud::AutoML::V1beta1"; + +// API proto representing a trained machine learning model. +message Model { + option (google.api.resource) = { + type: "automl.googleapis.com/Model" + pattern: "projects/{project}/locations/{location}/models/{model}" + }; + + // Deployment state of the model. + enum DeploymentState { + // Should not be used, an un-set enum has this value by default. + DEPLOYMENT_STATE_UNSPECIFIED = 0; + + // Model is deployed. + DEPLOYED = 1; + + // Model is not deployed. + UNDEPLOYED = 2; + } + + // Required. + // The model metadata that is specific to the problem type. + // Must match the metadata type of the dataset used to train the model. + oneof model_metadata { + // Metadata for translation models. + TranslationModelMetadata translation_model_metadata = 15; + + // Metadata for image classification models. + ImageClassificationModelMetadata image_classification_model_metadata = 13; + + // Metadata for text classification models. + TextClassificationModelMetadata text_classification_model_metadata = 14; + + // Metadata for image object detection models. + ImageObjectDetectionModelMetadata image_object_detection_model_metadata = 20; + + // Metadata for video classification models. + VideoClassificationModelMetadata video_classification_model_metadata = 23; + + // Metadata for video object tracking models. + VideoObjectTrackingModelMetadata video_object_tracking_model_metadata = 21; + + // Metadata for text extraction models. + TextExtractionModelMetadata text_extraction_model_metadata = 19; + + // Metadata for Tables models. + TablesModelMetadata tables_model_metadata = 24; + + // Metadata for text sentiment models. + TextSentimentModelMetadata text_sentiment_model_metadata = 22; + } + + // Output only. Resource name of the model. + // Format: `projects/{project_id}/locations/{location_id}/models/{model_id}` + string name = 1; + + // Required. The name of the model to show in the interface. The name can be + // up to 32 characters long and can consist only of ASCII Latin letters A-Z + // and a-z, underscores + // (_), and ASCII digits 0-9. It must start with a letter. + string display_name = 2; + + // Required. The resource ID of the dataset used to create the model. The dataset must + // come from the same ancestor project and location. + string dataset_id = 3; + + // Output only. Timestamp when the model training finished and can be used for prediction. + google.protobuf.Timestamp create_time = 7; + + // Output only. Timestamp when this model was last updated. + google.protobuf.Timestamp update_time = 11; + + // Output only. Deployment state of the model. A model can only serve + // prediction requests after it gets deployed. + DeploymentState deployment_state = 8; +} diff --git a/google/cloud/automl_v1beta1/proto/model_evaluation.proto b/google/cloud/automl_v1beta1/proto/model_evaluation.proto new file mode 100644 index 00000000..d5633fcd --- /dev/null +++ b/google/cloud/automl_v1beta1/proto/model_evaluation.proto @@ -0,0 +1,116 @@ +// 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. + +syntax = "proto3"; + +package google.cloud.automl.v1beta1; + +import "google/api/resource.proto"; +import "google/cloud/automl/v1beta1/classification.proto"; +import "google/cloud/automl/v1beta1/detection.proto"; +import "google/cloud/automl/v1beta1/regression.proto"; +import "google/cloud/automl/v1beta1/tables.proto"; +import "google/cloud/automl/v1beta1/text_extraction.proto"; +import "google/cloud/automl/v1beta1/text_sentiment.proto"; +import "google/cloud/automl/v1beta1/translation.proto"; +import "google/protobuf/timestamp.proto"; +import "google/api/annotations.proto"; + +option go_package = "google.golang.org/genproto/googleapis/cloud/automl/v1beta1;automl"; +option java_multiple_files = true; +option java_package = "com.google.cloud.automl.v1beta1"; +option php_namespace = "Google\\Cloud\\AutoMl\\V1beta1"; +option ruby_package = "Google::Cloud::AutoML::V1beta1"; + +// Evaluation results of a model. +message ModelEvaluation { + option (google.api.resource) = { + type: "automl.googleapis.com/ModelEvaluation" + pattern: "projects/{project}/locations/{location}/models/{model}/modelEvaluations/{model_evaluation}" + }; + + // Output only. Problem type specific evaluation metrics. + oneof metrics { + // Model evaluation metrics for image, text, video and tables + // classification. + // Tables problem is considered a classification when the target column + // is CATEGORY DataType. + ClassificationEvaluationMetrics classification_evaluation_metrics = 8; + + // Model evaluation metrics for Tables regression. + // Tables problem is considered a regression when the target column + // has FLOAT64 DataType. + RegressionEvaluationMetrics regression_evaluation_metrics = 24; + + // Model evaluation metrics for translation. + TranslationEvaluationMetrics translation_evaluation_metrics = 9; + + // Model evaluation metrics for image object detection. + ImageObjectDetectionEvaluationMetrics image_object_detection_evaluation_metrics = 12; + + // Model evaluation metrics for video object tracking. + VideoObjectTrackingEvaluationMetrics video_object_tracking_evaluation_metrics = 14; + + // Evaluation metrics for text sentiment models. + TextSentimentEvaluationMetrics text_sentiment_evaluation_metrics = 11; + + // Evaluation metrics for text extraction models. + TextExtractionEvaluationMetrics text_extraction_evaluation_metrics = 13; + } + + // Output only. Resource name of the model evaluation. + // Format: + // + // `projects/{project_id}/locations/{location_id}/models/{model_id}/modelEvaluations/{model_evaluation_id}` + string name = 1; + + // Output only. The ID of the annotation spec that the model evaluation applies to. The + // The ID is empty for the overall model evaluation. + // For Tables annotation specs in the dataset do not exist and this ID is + // always not set, but for CLASSIFICATION + // + // [prediction_type-s][google.cloud.automl.v1beta1.TablesModelMetadata.prediction_type] + // the + // [display_name][google.cloud.automl.v1beta1.ModelEvaluation.display_name] + // field is used. + string annotation_spec_id = 2; + + // Output only. The value of + // [display_name][google.cloud.automl.v1beta1.AnnotationSpec.display_name] at + // the moment when the model was trained. Because this field returns a value + // at model training time, for different models trained from the same dataset, + // the values may differ, since display names could had been changed between + // the two model's trainings. + // For Tables CLASSIFICATION + // + // [prediction_type-s][google.cloud.automl.v1beta1.TablesModelMetadata.prediction_type] + // distinct values of the target column at the moment of the model evaluation + // are populated here. + // The display_name is empty for the overall model evaluation. + string display_name = 15; + + // Output only. Timestamp when this model evaluation was created. + google.protobuf.Timestamp create_time = 5; + + // Output only. The number of examples used for model evaluation, i.e. for + // which ground truth from time of model creation is compared against the + // predicted annotations created by the model. + // For overall ModelEvaluation (i.e. with annotation_spec_id not set) this is + // the total number of all examples used for evaluation. + // Otherwise, this is the count of examples that according to the ground + // truth were annotated by the + // + // [annotation_spec_id][google.cloud.automl.v1beta1.ModelEvaluation.annotation_spec_id]. + int32 evaluated_example_count = 6; +} diff --git a/google/cloud/automl_v1beta1/proto/operations.proto b/google/cloud/automl_v1beta1/proto/operations.proto new file mode 100644 index 00000000..cce3fedc --- /dev/null +++ b/google/cloud/automl_v1beta1/proto/operations.proto @@ -0,0 +1,189 @@ +// 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. + +syntax = "proto3"; + +package google.cloud.automl.v1beta1; + +import "google/cloud/automl/v1beta1/io.proto"; +import "google/cloud/automl/v1beta1/model.proto"; +import "google/cloud/automl/v1beta1/model_evaluation.proto"; +import "google/protobuf/empty.proto"; +import "google/protobuf/timestamp.proto"; +import "google/rpc/status.proto"; +import "google/api/annotations.proto"; + +option go_package = "google.golang.org/genproto/googleapis/cloud/automl/v1beta1;automl"; +option java_multiple_files = true; +option java_package = "com.google.cloud.automl.v1beta1"; +option php_namespace = "Google\\Cloud\\AutoMl\\V1beta1"; +option ruby_package = "Google::Cloud::AutoML::V1beta1"; + +// Metadata used across all long running operations returned by AutoML API. +message OperationMetadata { + // Ouptut only. Details of specific operation. Even if this field is empty, + // the presence allows to distinguish different types of operations. + oneof details { + // Details of a Delete operation. + DeleteOperationMetadata delete_details = 8; + + // Details of a DeployModel operation. + DeployModelOperationMetadata deploy_model_details = 24; + + // Details of an UndeployModel operation. + UndeployModelOperationMetadata undeploy_model_details = 25; + + // Details of CreateModel operation. + CreateModelOperationMetadata create_model_details = 10; + + // Details of ImportData operation. + ImportDataOperationMetadata import_data_details = 15; + + // Details of BatchPredict operation. + BatchPredictOperationMetadata batch_predict_details = 16; + + // Details of ExportData operation. + ExportDataOperationMetadata export_data_details = 21; + + // Details of ExportModel operation. + ExportModelOperationMetadata export_model_details = 22; + + // Details of ExportEvaluatedExamples operation. + ExportEvaluatedExamplesOperationMetadata export_evaluated_examples_details = 26; + } + + // Output only. Progress of operation. Range: [0, 100]. + // Not used currently. + int32 progress_percent = 13; + + // Output only. Partial failures encountered. + // E.g. single files that couldn't be read. + // This field should never exceed 20 entries. + // Status details field will contain standard GCP error details. + repeated google.rpc.Status partial_failures = 2; + + // Output only. Time when the operation was created. + google.protobuf.Timestamp create_time = 3; + + // Output only. Time when the operation was updated for the last time. + google.protobuf.Timestamp update_time = 4; +} + +// Details of operations that perform deletes of any entities. +message DeleteOperationMetadata { + +} + +// Details of DeployModel operation. +message DeployModelOperationMetadata { + +} + +// Details of UndeployModel operation. +message UndeployModelOperationMetadata { + +} + +// Details of CreateModel operation. +message CreateModelOperationMetadata { + +} + +// Details of ImportData operation. +message ImportDataOperationMetadata { + +} + +// Details of ExportData operation. +message ExportDataOperationMetadata { + // Further describes this export data's output. + // Supplements + // [OutputConfig][google.cloud.automl.v1beta1.OutputConfig]. + message ExportDataOutputInfo { + // The output location to which the exported data is written. + oneof output_location { + // The full path of the Google Cloud Storage directory created, into which + // the exported data is written. + string gcs_output_directory = 1; + + // The path of the BigQuery dataset created, in bq://projectId.bqDatasetId + // format, into which the exported data is written. + string bigquery_output_dataset = 2; + } + } + + // Output only. Information further describing this export data's output. + ExportDataOutputInfo output_info = 1; +} + +// Details of BatchPredict operation. +message BatchPredictOperationMetadata { + // Further describes this batch predict's output. + // Supplements + // + // [BatchPredictOutputConfig][google.cloud.automl.v1beta1.BatchPredictOutputConfig]. + message BatchPredictOutputInfo { + // The output location into which prediction output is written. + oneof output_location { + // The full path of the Google Cloud Storage directory created, into which + // the prediction output is written. + string gcs_output_directory = 1; + + // The path of the BigQuery dataset created, in bq://projectId.bqDatasetId + // format, into which the prediction output is written. + string bigquery_output_dataset = 2; + } + } + + // Output only. The input config that was given upon starting this + // batch predict operation. + BatchPredictInputConfig input_config = 1; + + // Output only. Information further describing this batch predict's output. + BatchPredictOutputInfo output_info = 2; +} + +// Details of ExportModel operation. +message ExportModelOperationMetadata { + // Further describes the output of model export. + // Supplements + // + // [ModelExportOutputConfig][google.cloud.automl.v1beta1.ModelExportOutputConfig]. + message ExportModelOutputInfo { + // The full path of the Google Cloud Storage directory created, into which + // the model will be exported. + string gcs_output_directory = 1; + } + + // Output only. Information further describing the output of this model + // export. + ExportModelOutputInfo output_info = 2; +} + +// Details of EvaluatedExamples operation. +message ExportEvaluatedExamplesOperationMetadata { + // Further describes the output of the evaluated examples export. + // Supplements + // + // [ExportEvaluatedExamplesOutputConfig][google.cloud.automl.v1beta1.ExportEvaluatedExamplesOutputConfig]. + message ExportEvaluatedExamplesOutputInfo { + // The path of the BigQuery dataset created, in bq://projectId.bqDatasetId + // format, into which the output of export evaluated examples is written. + string bigquery_output_dataset = 2; + } + + // Output only. Information further describing the output of this evaluated + // examples export. + ExportEvaluatedExamplesOutputInfo output_info = 2; +} diff --git a/google/cloud/automl_v1beta1/proto/prediction_service.proto b/google/cloud/automl_v1beta1/proto/prediction_service.proto new file mode 100644 index 00000000..0bcf685e --- /dev/null +++ b/google/cloud/automl_v1beta1/proto/prediction_service.proto @@ -0,0 +1,268 @@ +// 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. + +syntax = "proto3"; + +package google.cloud.automl.v1beta1; + +import "google/api/annotations.proto"; +import "google/api/client.proto"; +import "google/api/field_behavior.proto"; +import "google/api/resource.proto"; +import "google/cloud/automl/v1beta1/annotation_payload.proto"; +import "google/cloud/automl/v1beta1/data_items.proto"; +import "google/cloud/automl/v1beta1/io.proto"; +import "google/cloud/automl/v1beta1/operations.proto"; +import "google/longrunning/operations.proto"; + +option go_package = "google.golang.org/genproto/googleapis/cloud/automl/v1beta1;automl"; +option java_multiple_files = true; +option java_outer_classname = "PredictionServiceProto"; +option java_package = "com.google.cloud.automl.v1beta1"; +option php_namespace = "Google\\Cloud\\AutoMl\\V1beta1"; +option ruby_package = "Google::Cloud::AutoML::V1beta1"; + +// AutoML Prediction API. +// +// On any input that is documented to expect a string parameter in +// snake_case or kebab-case, either of those cases is accepted. +service PredictionService { + option (google.api.default_host) = "automl.googleapis.com"; + option (google.api.oauth_scopes) = "https://www.googleapis.com/auth/cloud-platform"; + + // Perform an online prediction. The prediction result will be directly + // returned in the response. + // Available for following ML problems, and their expected request payloads: + // * Image Classification - Image in .JPEG, .GIF or .PNG format, image_bytes + // up to 30MB. + // * Image Object Detection - Image in .JPEG, .GIF or .PNG format, image_bytes + // up to 30MB. + // * Text Classification - TextSnippet, content up to 60,000 characters, + // UTF-8 encoded. + // * Text Extraction - TextSnippet, content up to 30,000 characters, + // UTF-8 NFC encoded. + // * Translation - TextSnippet, content up to 25,000 characters, UTF-8 + // encoded. + // * Tables - Row, with column values matching the columns of the model, + // up to 5MB. Not available for FORECASTING + // + // [prediction_type][google.cloud.automl.v1beta1.TablesModelMetadata.prediction_type]. + // * Text Sentiment - TextSnippet, content up 500 characters, UTF-8 + // encoded. + rpc Predict(PredictRequest) returns (PredictResponse) { + option (google.api.http) = { + post: "/v1beta1/{name=projects/*/locations/*/models/*}:predict" + body: "*" + }; + option (google.api.method_signature) = "name,payload,params"; + } + + // Perform a batch prediction. Unlike the online [Predict][google.cloud.automl.v1beta1.PredictionService.Predict], batch + // prediction result won't be immediately available in the response. Instead, + // a long running operation object is returned. User can poll the operation + // result via [GetOperation][google.longrunning.Operations.GetOperation] + // method. Once the operation is done, [BatchPredictResult][google.cloud.automl.v1beta1.BatchPredictResult] is returned in + // the [response][google.longrunning.Operation.response] field. + // Available for following ML problems: + // * Image Classification + // * Image Object Detection + // * Video Classification + // * Video Object Tracking * Text Extraction + // * Tables + rpc BatchPredict(BatchPredictRequest) returns (google.longrunning.Operation) { + option (google.api.http) = { + post: "/v1beta1/{name=projects/*/locations/*/models/*}:batchPredict" + body: "*" + }; + option (google.api.method_signature) = "name,input_config,output_config,params"; + option (google.longrunning.operation_info) = { + response_type: "BatchPredictResult" + metadata_type: "OperationMetadata" + }; + } +} + +// Request message for [PredictionService.Predict][google.cloud.automl.v1beta1.PredictionService.Predict]. +message PredictRequest { + // Required. Name of the model requested to serve the prediction. + string name = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { + type: "automl.googleapis.com/Model" + } + ]; + + // Required. Payload to perform a prediction on. The payload must match the + // problem type that the model was trained to solve. + ExamplePayload payload = 2 [(google.api.field_behavior) = REQUIRED]; + + // Additional domain-specific parameters, any string must be up to 25000 + // characters long. + // + // * For Image Classification: + // + // `score_threshold` - (float) A value from 0.0 to 1.0. When the model + // makes predictions for an image, it will only produce results that have + // at least this confidence score. The default is 0.5. + // + // * For Image Object Detection: + // `score_threshold` - (float) When Model detects objects on the image, + // it will only produce bounding boxes which have at least this + // confidence score. Value in 0 to 1 range, default is 0.5. + // `max_bounding_box_count` - (int64) No more than this number of bounding + // boxes will be returned in the response. Default is 100, the + // requested value may be limited by server. + // * For Tables: + // feature_importance - (boolean) Whether feature importance + // should be populated in the returned TablesAnnotation. + // The default is false. + map params = 3; +} + +// Response message for [PredictionService.Predict][google.cloud.automl.v1beta1.PredictionService.Predict]. +message PredictResponse { + // Prediction result. + // Translation and Text Sentiment will return precisely one payload. + repeated AnnotationPayload payload = 1; + + // The preprocessed example that AutoML actually makes prediction on. + // Empty if AutoML does not preprocess the input example. + // * For Text Extraction: + // If the input is a .pdf file, the OCR'ed text will be provided in + // [document_text][google.cloud.automl.v1beta1.Document.document_text]. + ExamplePayload preprocessed_input = 3; + + // Additional domain-specific prediction response metadata. + // + // * For Image Object Detection: + // `max_bounding_box_count` - (int64) At most that many bounding boxes per + // image could have been returned. + // + // * For Text Sentiment: + // `sentiment_score` - (float, deprecated) A value between -1 and 1, + // -1 maps to least positive sentiment, while 1 maps to the most positive + // one and the higher the score, the more positive the sentiment in the + // document is. Yet these values are relative to the training data, so + // e.g. if all data was positive then -1 will be also positive (though + // the least). + // The sentiment_score shouldn't be confused with "score" or "magnitude" + // from the previous Natural Language Sentiment Analysis API. + map metadata = 2; +} + +// Request message for [PredictionService.BatchPredict][google.cloud.automl.v1beta1.PredictionService.BatchPredict]. +message BatchPredictRequest { + // Required. Name of the model requested to serve the batch prediction. + string name = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { + type: "automl.googleapis.com/Model" + } + ]; + + // Required. The input configuration for batch prediction. + BatchPredictInputConfig input_config = 3 [(google.api.field_behavior) = REQUIRED]; + + // Required. The Configuration specifying where output predictions should + // be written. + BatchPredictOutputConfig output_config = 4 [(google.api.field_behavior) = REQUIRED]; + + // Required. Additional domain-specific parameters for the predictions, any string must + // be up to 25000 characters long. + // + // * For Text Classification: + // + // `score_threshold` - (float) A value from 0.0 to 1.0. When the model + // makes predictions for a text snippet, it will only produce results + // that have at least this confidence score. The default is 0.5. + // + // * For Image Classification: + // + // `score_threshold` - (float) A value from 0.0 to 1.0. When the model + // makes predictions for an image, it will only produce results that + // have at least this confidence score. The default is 0.5. + // + // * For Image Object Detection: + // + // `score_threshold` - (float) When Model detects objects on the image, + // it will only produce bounding boxes which have at least this + // confidence score. Value in 0 to 1 range, default is 0.5. + // `max_bounding_box_count` - (int64) No more than this number of bounding + // boxes will be produced per image. Default is 100, the + // requested value may be limited by server. + // + // * For Video Classification : + // + // `score_threshold` - (float) A value from 0.0 to 1.0. When the model + // makes predictions for a video, it will only produce results that + // have at least this confidence score. The default is 0.5. + // `segment_classification` - (boolean) Set to true to request + // segment-level classification. AutoML Video Intelligence returns + // labels and their confidence scores for the entire segment of the + // video that user specified in the request configuration. + // The default is "true". + // `shot_classification` - (boolean) Set to true to request shot-level + // classification. AutoML Video Intelligence determines the boundaries + // for each camera shot in the entire segment of the video that user + // specified in the request configuration. AutoML Video Intelligence + // then returns labels and their confidence scores for each detected + // shot, along with the start and end time of the shot. + // WARNING: Model evaluation is not done for this classification type, + // the quality of it depends on training data, but there are no metrics + // provided to describe that quality. The default is "false". + // `1s_interval_classification` - (boolean) Set to true to request + // classification for a video at one-second intervals. AutoML Video + // Intelligence returns labels and their confidence scores for each + // second of the entire segment of the video that user specified in the + // request configuration. + // WARNING: Model evaluation is not done for this classification + // type, the quality of it depends on training data, but there are no + // metrics provided to describe that quality. The default is + // "false". + // + // * For Tables: + // + // feature_importance - (boolean) Whether feature importance + // should be populated in the returned TablesAnnotations. The + // default is false. + // + // * For Video Object Tracking: + // + // `score_threshold` - (float) When Model detects objects on video frames, + // it will only produce bounding boxes which have at least this + // confidence score. Value in 0 to 1 range, default is 0.5. + // `max_bounding_box_count` - (int64) No more than this number of bounding + // boxes will be returned per frame. Default is 100, the requested + // value may be limited by server. + // `min_bounding_box_size` - (float) Only bounding boxes with shortest edge + // at least that long as a relative value of video frame size will be + // returned. Value in 0 to 1 range. Default is 0. + map params = 5 [(google.api.field_behavior) = REQUIRED]; +} + +// Result of the Batch Predict. This message is returned in +// [response][google.longrunning.Operation.response] of the operation returned +// by the [PredictionService.BatchPredict][google.cloud.automl.v1beta1.PredictionService.BatchPredict]. +message BatchPredictResult { + // Additional domain-specific prediction response metadata. + // + // * For Image Object Detection: + // `max_bounding_box_count` - (int64) At most that many bounding boxes per + // image could have been returned. + // + // * For Video Object Tracking: + // `max_bounding_box_count` - (int64) At most that many bounding boxes per + // frame could have been returned. + map metadata = 1; +} diff --git a/google/cloud/automl_v1beta1/proto/ranges.proto b/google/cloud/automl_v1beta1/proto/ranges.proto new file mode 100644 index 00000000..89572bb0 --- /dev/null +++ b/google/cloud/automl_v1beta1/proto/ranges.proto @@ -0,0 +1,35 @@ +// 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. + +syntax = "proto3"; + +package google.cloud.automl.v1beta1; + +import "google/api/annotations.proto"; + +option go_package = "google.golang.org/genproto/googleapis/cloud/automl/v1beta1;automl"; +option java_multiple_files = true; +option java_outer_classname = "RangesProto"; +option java_package = "com.google.cloud.automl.v1beta1"; +option php_namespace = "Google\\Cloud\\AutoMl\\V1beta1"; +option ruby_package = "Google::Cloud::AutoML::V1beta1"; + +// A range between two double numbers. +message DoubleRange { + // Start of the range, inclusive. + double start = 1; + + // End of the range, exclusive. + double end = 2; +} diff --git a/google/cloud/automl_v1beta1/proto/regression.proto b/google/cloud/automl_v1beta1/proto/regression.proto new file mode 100644 index 00000000..1286d3d8 --- /dev/null +++ b/google/cloud/automl_v1beta1/proto/regression.proto @@ -0,0 +1,44 @@ +// 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. + +syntax = "proto3"; + +package google.cloud.automl.v1beta1; + +import "google/api/annotations.proto"; + +option go_package = "google.golang.org/genproto/googleapis/cloud/automl/v1beta1;automl"; +option java_outer_classname = "RegressionProto"; +option java_package = "com.google.cloud.automl.v1beta1"; +option php_namespace = "Google\\Cloud\\AutoMl\\V1beta1"; +option ruby_package = "Google::Cloud::AutoML::V1beta1"; + +// Metrics for regression problems. +message RegressionEvaluationMetrics { + // Output only. Root Mean Squared Error (RMSE). + float root_mean_squared_error = 1; + + // Output only. Mean Absolute Error (MAE). + float mean_absolute_error = 2; + + // Output only. Mean absolute percentage error. Only set if all ground truth + // values are are positive. + float mean_absolute_percentage_error = 3; + + // Output only. R squared. + float r_squared = 4; + + // Output only. Root mean squared log error. + float root_mean_squared_log_error = 5; +} diff --git a/google/cloud/automl_v1beta1/proto/service.proto b/google/cloud/automl_v1beta1/proto/service.proto new file mode 100644 index 00000000..a421ece1 --- /dev/null +++ b/google/cloud/automl_v1beta1/proto/service.proto @@ -0,0 +1,800 @@ +// 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. + +syntax = "proto3"; + +package google.cloud.automl.v1beta1; + +import "google/api/annotations.proto"; +import "google/api/client.proto"; +import "google/api/field_behavior.proto"; +import "google/api/resource.proto"; +import "google/cloud/automl/v1beta1/annotation_payload.proto"; +import "google/cloud/automl/v1beta1/annotation_spec.proto"; +import "google/cloud/automl/v1beta1/column_spec.proto"; +import "google/cloud/automl/v1beta1/dataset.proto"; +import "google/cloud/automl/v1beta1/image.proto"; +import "google/cloud/automl/v1beta1/io.proto"; +import "google/cloud/automl/v1beta1/model.proto"; +import "google/cloud/automl/v1beta1/model_evaluation.proto"; +import "google/cloud/automl/v1beta1/operations.proto"; +import "google/cloud/automl/v1beta1/table_spec.proto"; +import "google/longrunning/operations.proto"; +import "google/protobuf/field_mask.proto"; + +option go_package = "google.golang.org/genproto/googleapis/cloud/automl/v1beta1;automl"; +option java_multiple_files = true; +option java_outer_classname = "AutoMlProto"; +option java_package = "com.google.cloud.automl.v1beta1"; +option php_namespace = "Google\\Cloud\\AutoMl\\V1beta1"; +option ruby_package = "Google::Cloud::AutoML::V1beta1"; + +// AutoML Server API. +// +// The resource names are assigned by the server. +// The server never reuses names that it has created after the resources with +// those names are deleted. +// +// An ID of a resource is the last element of the item's resource name. For +// `projects/{project_id}/locations/{location_id}/datasets/{dataset_id}`, then +// the id for the item is `{dataset_id}`. +// +// Currently the only supported `location_id` is "us-central1". +// +// On any input that is documented to expect a string parameter in +// snake_case or kebab-case, either of those cases is accepted. +service AutoMl { + option (google.api.default_host) = "automl.googleapis.com"; + option (google.api.oauth_scopes) = "https://www.googleapis.com/auth/cloud-platform"; + + // Creates a dataset. + rpc CreateDataset(CreateDatasetRequest) returns (Dataset) { + option (google.api.http) = { + post: "/v1beta1/{parent=projects/*/locations/*}/datasets" + body: "dataset" + }; + option (google.api.method_signature) = "parent,dataset"; + } + + // Gets a dataset. + rpc GetDataset(GetDatasetRequest) returns (Dataset) { + option (google.api.http) = { + get: "/v1beta1/{name=projects/*/locations/*/datasets/*}" + }; + option (google.api.method_signature) = "name"; + } + + // Lists datasets in a project. + rpc ListDatasets(ListDatasetsRequest) returns (ListDatasetsResponse) { + option (google.api.http) = { + get: "/v1beta1/{parent=projects/*/locations/*}/datasets" + }; + option (google.api.method_signature) = "parent"; + } + + // Updates a dataset. + rpc UpdateDataset(UpdateDatasetRequest) returns (Dataset) { + option (google.api.http) = { + patch: "/v1beta1/{dataset.name=projects/*/locations/*/datasets/*}" + body: "dataset" + }; + option (google.api.method_signature) = "dataset"; + } + + // Deletes a dataset and all of its contents. + // Returns empty response in the + // [response][google.longrunning.Operation.response] field when it completes, + // and `delete_details` in the + // [metadata][google.longrunning.Operation.metadata] field. + rpc DeleteDataset(DeleteDatasetRequest) returns (google.longrunning.Operation) { + option (google.api.http) = { + delete: "/v1beta1/{name=projects/*/locations/*/datasets/*}" + }; + option (google.api.method_signature) = "name"; + option (google.longrunning.operation_info) = { + response_type: "google.protobuf.Empty" + metadata_type: "OperationMetadata" + }; + } + + // Imports data into a dataset. + // For Tables this method can only be called on an empty Dataset. + // + // For Tables: + // * A + // [schema_inference_version][google.cloud.automl.v1beta1.InputConfig.params] + // parameter must be explicitly set. + // Returns an empty response in the + // [response][google.longrunning.Operation.response] field when it completes. + rpc ImportData(ImportDataRequest) returns (google.longrunning.Operation) { + option (google.api.http) = { + post: "/v1beta1/{name=projects/*/locations/*/datasets/*}:importData" + body: "*" + }; + option (google.api.method_signature) = "name,input_config"; + option (google.longrunning.operation_info) = { + response_type: "google.protobuf.Empty" + metadata_type: "OperationMetadata" + }; + } + + // Exports dataset's data to the provided output location. + // Returns an empty response in the + // [response][google.longrunning.Operation.response] field when it completes. + rpc ExportData(ExportDataRequest) returns (google.longrunning.Operation) { + option (google.api.http) = { + post: "/v1beta1/{name=projects/*/locations/*/datasets/*}:exportData" + body: "*" + }; + option (google.api.method_signature) = "name,output_config"; + option (google.longrunning.operation_info) = { + response_type: "google.protobuf.Empty" + metadata_type: "OperationMetadata" + }; + } + + // Gets an annotation spec. + rpc GetAnnotationSpec(GetAnnotationSpecRequest) returns (AnnotationSpec) { + option (google.api.http) = { + get: "/v1beta1/{name=projects/*/locations/*/datasets/*/annotationSpecs/*}" + }; + option (google.api.method_signature) = "name"; + } + + // Gets a table spec. + rpc GetTableSpec(GetTableSpecRequest) returns (TableSpec) { + option (google.api.http) = { + get: "/v1beta1/{name=projects/*/locations/*/datasets/*/tableSpecs/*}" + }; + option (google.api.method_signature) = "name"; + } + + // Lists table specs in a dataset. + rpc ListTableSpecs(ListTableSpecsRequest) returns (ListTableSpecsResponse) { + option (google.api.http) = { + get: "/v1beta1/{parent=projects/*/locations/*/datasets/*}/tableSpecs" + }; + option (google.api.method_signature) = "parent"; + } + + // Updates a table spec. + rpc UpdateTableSpec(UpdateTableSpecRequest) returns (TableSpec) { + option (google.api.http) = { + patch: "/v1beta1/{table_spec.name=projects/*/locations/*/datasets/*/tableSpecs/*}" + body: "table_spec" + }; + option (google.api.method_signature) = "table_spec"; + } + + // Gets a column spec. + rpc GetColumnSpec(GetColumnSpecRequest) returns (ColumnSpec) { + option (google.api.http) = { + get: "/v1beta1/{name=projects/*/locations/*/datasets/*/tableSpecs/*/columnSpecs/*}" + }; + option (google.api.method_signature) = "name"; + } + + // Lists column specs in a table spec. + rpc ListColumnSpecs(ListColumnSpecsRequest) returns (ListColumnSpecsResponse) { + option (google.api.http) = { + get: "/v1beta1/{parent=projects/*/locations/*/datasets/*/tableSpecs/*}/columnSpecs" + }; + option (google.api.method_signature) = "parent"; + } + + // Updates a column spec. + rpc UpdateColumnSpec(UpdateColumnSpecRequest) returns (ColumnSpec) { + option (google.api.http) = { + patch: "/v1beta1/{column_spec.name=projects/*/locations/*/datasets/*/tableSpecs/*/columnSpecs/*}" + body: "column_spec" + }; + option (google.api.method_signature) = "column_spec"; + } + + // Creates a model. + // Returns a Model in the [response][google.longrunning.Operation.response] + // field when it completes. + // When you create a model, several model evaluations are created for it: + // a global evaluation, and one evaluation for each annotation spec. + rpc CreateModel(CreateModelRequest) returns (google.longrunning.Operation) { + option (google.api.http) = { + post: "/v1beta1/{parent=projects/*/locations/*}/models" + body: "model" + }; + option (google.api.method_signature) = "parent,model"; + option (google.longrunning.operation_info) = { + response_type: "Model" + metadata_type: "OperationMetadata" + }; + } + + // Gets a model. + rpc GetModel(GetModelRequest) returns (Model) { + option (google.api.http) = { + get: "/v1beta1/{name=projects/*/locations/*/models/*}" + }; + option (google.api.method_signature) = "name"; + } + + // Lists models. + rpc ListModels(ListModelsRequest) returns (ListModelsResponse) { + option (google.api.http) = { + get: "/v1beta1/{parent=projects/*/locations/*}/models" + }; + option (google.api.method_signature) = "parent"; + } + + // Deletes a model. + // Returns `google.protobuf.Empty` in the + // [response][google.longrunning.Operation.response] field when it completes, + // and `delete_details` in the + // [metadata][google.longrunning.Operation.metadata] field. + rpc DeleteModel(DeleteModelRequest) returns (google.longrunning.Operation) { + option (google.api.http) = { + delete: "/v1beta1/{name=projects/*/locations/*/models/*}" + }; + option (google.api.method_signature) = "name"; + option (google.longrunning.operation_info) = { + response_type: "google.protobuf.Empty" + metadata_type: "OperationMetadata" + }; + } + + // Deploys a model. If a model is already deployed, deploying it with the + // same parameters has no effect. Deploying with different parametrs + // (as e.g. changing + // + // [node_number][google.cloud.automl.v1beta1.ImageObjectDetectionModelDeploymentMetadata.node_number]) + // will reset the deployment state without pausing the model's availability. + // + // Only applicable for Text Classification, Image Object Detection , Tables, and Image Segmentation; all other domains manage + // deployment automatically. + // + // Returns an empty response in the + // [response][google.longrunning.Operation.response] field when it completes. + rpc DeployModel(DeployModelRequest) returns (google.longrunning.Operation) { + option (google.api.http) = { + post: "/v1beta1/{name=projects/*/locations/*/models/*}:deploy" + body: "*" + }; + option (google.api.method_signature) = "name"; + option (google.longrunning.operation_info) = { + response_type: "google.protobuf.Empty" + metadata_type: "OperationMetadata" + }; + } + + // Undeploys a model. If the model is not deployed this method has no effect. + // + // Only applicable for Text Classification, Image Object Detection and Tables; + // all other domains manage deployment automatically. + // + // Returns an empty response in the + // [response][google.longrunning.Operation.response] field when it completes. + rpc UndeployModel(UndeployModelRequest) returns (google.longrunning.Operation) { + option (google.api.http) = { + post: "/v1beta1/{name=projects/*/locations/*/models/*}:undeploy" + body: "*" + }; + option (google.api.method_signature) = "name"; + option (google.longrunning.operation_info) = { + response_type: "google.protobuf.Empty" + metadata_type: "OperationMetadata" + }; + } + + // Exports a trained, "export-able", model to a user specified Google Cloud + // Storage location. A model is considered export-able if and only if it has + // an export format defined for it in + // + // [ModelExportOutputConfig][google.cloud.automl.v1beta1.ModelExportOutputConfig]. + // + // Returns an empty response in the + // [response][google.longrunning.Operation.response] field when it completes. + rpc ExportModel(ExportModelRequest) returns (google.longrunning.Operation) { + option (google.api.http) = { + post: "/v1beta1/{name=projects/*/locations/*/models/*}:export" + body: "*" + }; + option (google.api.method_signature) = "name,output_config"; + option (google.longrunning.operation_info) = { + response_type: "google.protobuf.Empty" + metadata_type: "OperationMetadata" + }; + } + + // Exports examples on which the model was evaluated (i.e. which were in the + // TEST set of the dataset the model was created from), together with their + // ground truth annotations and the annotations created (predicted) by the + // model. + // The examples, ground truth and predictions are exported in the state + // they were at the moment the model was evaluated. + // + // This export is available only for 30 days since the model evaluation is + // created. + // + // Currently only available for Tables. + // + // Returns an empty response in the + // [response][google.longrunning.Operation.response] field when it completes. + rpc ExportEvaluatedExamples(ExportEvaluatedExamplesRequest) returns (google.longrunning.Operation) { + option (google.api.http) = { + post: "/v1beta1/{name=projects/*/locations/*/models/*}:exportEvaluatedExamples" + body: "*" + }; + option (google.api.method_signature) = "name,output_config"; + option (google.longrunning.operation_info) = { + response_type: "google.protobuf.Empty" + metadata_type: "OperationMetadata" + }; + } + + // Gets a model evaluation. + rpc GetModelEvaluation(GetModelEvaluationRequest) returns (ModelEvaluation) { + option (google.api.http) = { + get: "/v1beta1/{name=projects/*/locations/*/models/*/modelEvaluations/*}" + }; + option (google.api.method_signature) = "name"; + } + + // Lists model evaluations. + rpc ListModelEvaluations(ListModelEvaluationsRequest) returns (ListModelEvaluationsResponse) { + option (google.api.http) = { + get: "/v1beta1/{parent=projects/*/locations/*/models/*}/modelEvaluations" + }; + option (google.api.method_signature) = "parent"; + } +} + +// Request message for [AutoMl.CreateDataset][google.cloud.automl.v1beta1.AutoMl.CreateDataset]. +message CreateDatasetRequest { + // Required. The resource name of the project to create the dataset for. + string parent = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { + type: "locations.googleapis.com/Location" + } + ]; + + // Required. The dataset to create. + Dataset dataset = 2 [(google.api.field_behavior) = REQUIRED]; +} + +// Request message for [AutoMl.GetDataset][google.cloud.automl.v1beta1.AutoMl.GetDataset]. +message GetDatasetRequest { + // Required. The resource name of the dataset to retrieve. + string name = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { + type: "automl.googleapis.com/Dataset" + } + ]; +} + +// Request message for [AutoMl.ListDatasets][google.cloud.automl.v1beta1.AutoMl.ListDatasets]. +message ListDatasetsRequest { + // Required. The resource name of the project from which to list datasets. + string parent = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { + type: "locations.googleapis.com/Location" + } + ]; + + // An expression for filtering the results of the request. + // + // * `dataset_metadata` - for existence of the case (e.g. + // image_classification_dataset_metadata:*). Some examples of using the filter are: + // + // * `translation_dataset_metadata:*` --> The dataset has + // translation_dataset_metadata. + string filter = 3; + + // Requested page size. Server may return fewer results than requested. + // If unspecified, server will pick a default size. + int32 page_size = 4; + + // A token identifying a page of results for the server to return + // Typically obtained via + // [ListDatasetsResponse.next_page_token][google.cloud.automl.v1beta1.ListDatasetsResponse.next_page_token] of the previous + // [AutoMl.ListDatasets][google.cloud.automl.v1beta1.AutoMl.ListDatasets] call. + string page_token = 6; +} + +// Response message for [AutoMl.ListDatasets][google.cloud.automl.v1beta1.AutoMl.ListDatasets]. +message ListDatasetsResponse { + // The datasets read. + repeated Dataset datasets = 1; + + // A token to retrieve next page of results. + // Pass to [ListDatasetsRequest.page_token][google.cloud.automl.v1beta1.ListDatasetsRequest.page_token] to obtain that page. + string next_page_token = 2; +} + +// Request message for [AutoMl.UpdateDataset][google.cloud.automl.v1beta1.AutoMl.UpdateDataset] +message UpdateDatasetRequest { + // Required. The dataset which replaces the resource on the server. + Dataset dataset = 1 [(google.api.field_behavior) = REQUIRED]; + + // The update mask applies to the resource. + google.protobuf.FieldMask update_mask = 2; +} + +// Request message for [AutoMl.DeleteDataset][google.cloud.automl.v1beta1.AutoMl.DeleteDataset]. +message DeleteDatasetRequest { + // Required. The resource name of the dataset to delete. + string name = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { + type: "automl.googleapis.com/Dataset" + } + ]; +} + +// Request message for [AutoMl.ImportData][google.cloud.automl.v1beta1.AutoMl.ImportData]. +message ImportDataRequest { + // Required. Dataset name. Dataset must already exist. All imported + // annotations and examples will be added. + string name = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { + type: "automl.googleapis.com/Dataset" + } + ]; + + // Required. The desired input location and its domain specific semantics, + // if any. + InputConfig input_config = 3 [(google.api.field_behavior) = REQUIRED]; +} + +// Request message for [AutoMl.ExportData][google.cloud.automl.v1beta1.AutoMl.ExportData]. +message ExportDataRequest { + // Required. The resource name of the dataset. + string name = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { + type: "automl.googleapis.com/Dataset" + } + ]; + + // Required. The desired output location. + OutputConfig output_config = 3 [(google.api.field_behavior) = REQUIRED]; +} + +// Request message for [AutoMl.GetAnnotationSpec][google.cloud.automl.v1beta1.AutoMl.GetAnnotationSpec]. +message GetAnnotationSpecRequest { + // Required. The resource name of the annotation spec to retrieve. + string name = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { + type: "automl.googleapis.com/AnnotationSpec" + } + ]; +} + +// Request message for [AutoMl.GetTableSpec][google.cloud.automl.v1beta1.AutoMl.GetTableSpec]. +message GetTableSpecRequest { + // Required. The resource name of the table spec to retrieve. + string name = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { + type: "automl.googleapis.com/TableSpec" + } + ]; + + // Mask specifying which fields to read. + google.protobuf.FieldMask field_mask = 2; +} + +// Request message for [AutoMl.ListTableSpecs][google.cloud.automl.v1beta1.AutoMl.ListTableSpecs]. +message ListTableSpecsRequest { + // Required. The resource name of the dataset to list table specs from. + string parent = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { + type: "automl.googleapis.com/Dataset" + } + ]; + + // Mask specifying which fields to read. + google.protobuf.FieldMask field_mask = 2; + + // Filter expression, see go/filtering. + string filter = 3; + + // Requested page size. The server can return fewer results than requested. + // If unspecified, the server will pick a default size. + int32 page_size = 4; + + // A token identifying a page of results for the server to return. + // Typically obtained from the + // [ListTableSpecsResponse.next_page_token][google.cloud.automl.v1beta1.ListTableSpecsResponse.next_page_token] field of the previous + // [AutoMl.ListTableSpecs][google.cloud.automl.v1beta1.AutoMl.ListTableSpecs] call. + string page_token = 6; +} + +// Response message for [AutoMl.ListTableSpecs][google.cloud.automl.v1beta1.AutoMl.ListTableSpecs]. +message ListTableSpecsResponse { + // The table specs read. + repeated TableSpec table_specs = 1; + + // A token to retrieve next page of results. + // Pass to [ListTableSpecsRequest.page_token][google.cloud.automl.v1beta1.ListTableSpecsRequest.page_token] to obtain that page. + string next_page_token = 2; +} + +// Request message for [AutoMl.UpdateTableSpec][google.cloud.automl.v1beta1.AutoMl.UpdateTableSpec] +message UpdateTableSpecRequest { + // Required. The table spec which replaces the resource on the server. + TableSpec table_spec = 1 [(google.api.field_behavior) = REQUIRED]; + + // The update mask applies to the resource. + google.protobuf.FieldMask update_mask = 2; +} + +// Request message for [AutoMl.GetColumnSpec][google.cloud.automl.v1beta1.AutoMl.GetColumnSpec]. +message GetColumnSpecRequest { + // Required. The resource name of the column spec to retrieve. + string name = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { + type: "automl.googleapis.com/ColumnSpec" + } + ]; + + // Mask specifying which fields to read. + google.protobuf.FieldMask field_mask = 2; +} + +// Request message for [AutoMl.ListColumnSpecs][google.cloud.automl.v1beta1.AutoMl.ListColumnSpecs]. +message ListColumnSpecsRequest { + // Required. The resource name of the table spec to list column specs from. + string parent = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { + type: "automl.googleapis.com/TableSpec" + } + ]; + + // Mask specifying which fields to read. + google.protobuf.FieldMask field_mask = 2; + + // Filter expression, see go/filtering. + string filter = 3; + + // Requested page size. The server can return fewer results than requested. + // If unspecified, the server will pick a default size. + int32 page_size = 4; + + // A token identifying a page of results for the server to return. + // Typically obtained from the + // [ListColumnSpecsResponse.next_page_token][google.cloud.automl.v1beta1.ListColumnSpecsResponse.next_page_token] field of the previous + // [AutoMl.ListColumnSpecs][google.cloud.automl.v1beta1.AutoMl.ListColumnSpecs] call. + string page_token = 6; +} + +// Response message for [AutoMl.ListColumnSpecs][google.cloud.automl.v1beta1.AutoMl.ListColumnSpecs]. +message ListColumnSpecsResponse { + // The column specs read. + repeated ColumnSpec column_specs = 1; + + // A token to retrieve next page of results. + // Pass to [ListColumnSpecsRequest.page_token][google.cloud.automl.v1beta1.ListColumnSpecsRequest.page_token] to obtain that page. + string next_page_token = 2; +} + +// Request message for [AutoMl.UpdateColumnSpec][google.cloud.automl.v1beta1.AutoMl.UpdateColumnSpec] +message UpdateColumnSpecRequest { + // Required. The column spec which replaces the resource on the server. + ColumnSpec column_spec = 1 [(google.api.field_behavior) = REQUIRED]; + + // The update mask applies to the resource. + google.protobuf.FieldMask update_mask = 2; +} + +// Request message for [AutoMl.CreateModel][google.cloud.automl.v1beta1.AutoMl.CreateModel]. +message CreateModelRequest { + // Required. Resource name of the parent project where the model is being created. + string parent = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { + type: "locations.googleapis.com/Location" + } + ]; + + // Required. The model to create. + Model model = 4 [(google.api.field_behavior) = REQUIRED]; +} + +// Request message for [AutoMl.GetModel][google.cloud.automl.v1beta1.AutoMl.GetModel]. +message GetModelRequest { + // Required. Resource name of the model. + string name = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { + type: "automl.googleapis.com/Model" + } + ]; +} + +// Request message for [AutoMl.ListModels][google.cloud.automl.v1beta1.AutoMl.ListModels]. +message ListModelsRequest { + // Required. Resource name of the project, from which to list the models. + string parent = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { + type: "locations.googleapis.com/Location" + } + ]; + + // An expression for filtering the results of the request. + // + // * `model_metadata` - for existence of the case (e.g. + // video_classification_model_metadata:*). + // * `dataset_id` - for = or !=. Some examples of using the filter are: + // + // * `image_classification_model_metadata:*` --> The model has + // image_classification_model_metadata. + // * `dataset_id=5` --> The model was created from a dataset with ID 5. + string filter = 3; + + // Requested page size. + int32 page_size = 4; + + // A token identifying a page of results for the server to return + // Typically obtained via + // [ListModelsResponse.next_page_token][google.cloud.automl.v1beta1.ListModelsResponse.next_page_token] of the previous + // [AutoMl.ListModels][google.cloud.automl.v1beta1.AutoMl.ListModels] call. + string page_token = 6; +} + +// Response message for [AutoMl.ListModels][google.cloud.automl.v1beta1.AutoMl.ListModels]. +message ListModelsResponse { + // List of models in the requested page. + repeated Model model = 1; + + // A token to retrieve next page of results. + // Pass to [ListModelsRequest.page_token][google.cloud.automl.v1beta1.ListModelsRequest.page_token] to obtain that page. + string next_page_token = 2; +} + +// Request message for [AutoMl.DeleteModel][google.cloud.automl.v1beta1.AutoMl.DeleteModel]. +message DeleteModelRequest { + // Required. Resource name of the model being deleted. + string name = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { + type: "automl.googleapis.com/Model" + } + ]; +} + +// Request message for [AutoMl.DeployModel][google.cloud.automl.v1beta1.AutoMl.DeployModel]. +message DeployModelRequest { + // The per-domain specific deployment parameters. + oneof model_deployment_metadata { + // Model deployment metadata specific to Image Object Detection. + ImageObjectDetectionModelDeploymentMetadata image_object_detection_model_deployment_metadata = 2; + + // Model deployment metadata specific to Image Classification. + ImageClassificationModelDeploymentMetadata image_classification_model_deployment_metadata = 4; + } + + // Required. Resource name of the model to deploy. + string name = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { + type: "automl.googleapis.com/Model" + } + ]; +} + +// Request message for [AutoMl.UndeployModel][google.cloud.automl.v1beta1.AutoMl.UndeployModel]. +message UndeployModelRequest { + // Required. Resource name of the model to undeploy. + string name = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { + type: "automl.googleapis.com/Model" + } + ]; +} + +// Request message for [AutoMl.ExportModel][google.cloud.automl.v1beta1.AutoMl.ExportModel]. +// Models need to be enabled for exporting, otherwise an error code will be +// returned. +message ExportModelRequest { + // Required. The resource name of the model to export. + string name = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { + type: "automl.googleapis.com/Model" + } + ]; + + // Required. The desired output location and configuration. + ModelExportOutputConfig output_config = 3 [(google.api.field_behavior) = REQUIRED]; +} + +// Request message for [AutoMl.ExportEvaluatedExamples][google.cloud.automl.v1beta1.AutoMl.ExportEvaluatedExamples]. +message ExportEvaluatedExamplesRequest { + // Required. The resource name of the model whose evaluated examples are to + // be exported. + string name = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { + type: "automl.googleapis.com/Model" + } + ]; + + // Required. The desired output location and configuration. + ExportEvaluatedExamplesOutputConfig output_config = 3 [(google.api.field_behavior) = REQUIRED]; +} + +// Request message for [AutoMl.GetModelEvaluation][google.cloud.automl.v1beta1.AutoMl.GetModelEvaluation]. +message GetModelEvaluationRequest { + // Required. Resource name for the model evaluation. + string name = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { + type: "automl.googleapis.com/ModelEvaluation" + } + ]; +} + +// Request message for [AutoMl.ListModelEvaluations][google.cloud.automl.v1beta1.AutoMl.ListModelEvaluations]. +message ListModelEvaluationsRequest { + // Required. Resource name of the model to list the model evaluations for. + // If modelId is set as "-", this will list model evaluations from across all + // models of the parent location. + string parent = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { + type: "automl.googleapis.com/Model" + } + ]; + + // An expression for filtering the results of the request. + // + // * `annotation_spec_id` - for =, != or existence. See example below for + // the last. + // + // Some examples of using the filter are: + // + // * `annotation_spec_id!=4` --> The model evaluation was done for + // annotation spec with ID different than 4. + // * `NOT annotation_spec_id:*` --> The model evaluation was done for + // aggregate of all annotation specs. + string filter = 3; + + // Requested page size. + int32 page_size = 4; + + // A token identifying a page of results for the server to return. + // Typically obtained via + // [ListModelEvaluationsResponse.next_page_token][google.cloud.automl.v1beta1.ListModelEvaluationsResponse.next_page_token] of the previous + // [AutoMl.ListModelEvaluations][google.cloud.automl.v1beta1.AutoMl.ListModelEvaluations] call. + string page_token = 6; +} + +// Response message for [AutoMl.ListModelEvaluations][google.cloud.automl.v1beta1.AutoMl.ListModelEvaluations]. +message ListModelEvaluationsResponse { + // List of model evaluations in the requested page. + repeated ModelEvaluation model_evaluation = 1; + + // A token to retrieve next page of results. + // Pass to the [ListModelEvaluationsRequest.page_token][google.cloud.automl.v1beta1.ListModelEvaluationsRequest.page_token] field of a new + // [AutoMl.ListModelEvaluations][google.cloud.automl.v1beta1.AutoMl.ListModelEvaluations] request to obtain that page. + string next_page_token = 2; +} diff --git a/google/cloud/automl_v1beta1/proto/table_spec.proto b/google/cloud/automl_v1beta1/proto/table_spec.proto new file mode 100644 index 00000000..bc3fc744 --- /dev/null +++ b/google/cloud/automl_v1beta1/proto/table_spec.proto @@ -0,0 +1,78 @@ +// 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. + +syntax = "proto3"; + +package google.cloud.automl.v1beta1; + +import "google/api/resource.proto"; +import "google/cloud/automl/v1beta1/io.proto"; +import "google/api/annotations.proto"; + +option go_package = "google.golang.org/genproto/googleapis/cloud/automl/v1beta1;automl"; +option java_multiple_files = true; +option java_package = "com.google.cloud.automl.v1beta1"; +option php_namespace = "Google\\Cloud\\AutoMl\\V1beta1"; +option ruby_package = "Google::Cloud::AutoML::V1beta1"; + +// A specification of a relational table. +// The table's schema is represented via its child column specs. It is +// pre-populated as part of ImportData by schema inference algorithm, the +// version of which is a required parameter of ImportData InputConfig. +// Note: While working with a table, at times the schema may be +// inconsistent with the data in the table (e.g. string in a FLOAT64 column). +// The consistency validation is done upon creation of a model. +// Used by: +// * Tables +message TableSpec { + option (google.api.resource) = { + type: "automl.googleapis.com/TableSpec" + pattern: "projects/{project}/locations/{location}/datasets/{dataset}/tableSpecs/{table_spec}" + }; + + // Output only. The resource name of the table spec. + // Form: + // + // `projects/{project_id}/locations/{location_id}/datasets/{dataset_id}/tableSpecs/{table_spec_id}` + string name = 1; + + // column_spec_id of the time column. Only used if the parent dataset's + // ml_use_column_spec_id is not set. Used to split rows into TRAIN, VALIDATE + // and TEST sets such that oldest rows go to TRAIN set, newest to TEST, and + // those in between to VALIDATE. + // Required type: TIMESTAMP. + // If both this column and ml_use_column are not set, then ML use of all rows + // will be assigned by AutoML. NOTE: Updates of this field will instantly + // affect any other users concurrently working with the dataset. + string time_column_spec_id = 2; + + // Output only. The number of rows (i.e. examples) in the table. + int64 row_count = 3; + + // Output only. The number of valid rows (i.e. without values that don't match + // DataType-s of their columns). + int64 valid_row_count = 4; + + // Output only. The number of columns of the table. That is, the number of + // child ColumnSpec-s. + int64 column_count = 7; + + // Output only. Input configs via which data currently residing in the table + // had been imported. + repeated InputConfig input_configs = 5; + + // Used to perform consistent read-modify-write updates. If not set, a blind + // "overwrite" update happens. + string etag = 6; +} diff --git a/google/cloud/automl_v1beta1/proto/tables.proto b/google/cloud/automl_v1beta1/proto/tables.proto new file mode 100644 index 00000000..5327f5e7 --- /dev/null +++ b/google/cloud/automl_v1beta1/proto/tables.proto @@ -0,0 +1,292 @@ +// 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. + +syntax = "proto3"; + +package google.cloud.automl.v1beta1; + +import "google/cloud/automl/v1beta1/classification.proto"; +import "google/cloud/automl/v1beta1/column_spec.proto"; +import "google/cloud/automl/v1beta1/data_items.proto"; +import "google/cloud/automl/v1beta1/data_stats.proto"; +import "google/cloud/automl/v1beta1/ranges.proto"; +import "google/cloud/automl/v1beta1/regression.proto"; +import "google/cloud/automl/v1beta1/temporal.proto"; +import "google/protobuf/struct.proto"; +import "google/protobuf/timestamp.proto"; +import "google/api/annotations.proto"; + +option go_package = "google.golang.org/genproto/googleapis/cloud/automl/v1beta1;automl"; +option java_multiple_files = true; +option java_package = "com.google.cloud.automl.v1beta1"; +option php_namespace = "Google\\Cloud\\AutoMl\\V1beta1"; +option ruby_package = "Google::Cloud::AutoML::V1beta1"; + +// Metadata for a dataset used for AutoML Tables. +message TablesDatasetMetadata { + // Output only. The table_spec_id of the primary table of this dataset. + string primary_table_spec_id = 1; + + // column_spec_id of the primary table's column that should be used as the + // training & prediction target. + // This column must be non-nullable and have one of following data types + // (otherwise model creation will error): + // + // * CATEGORY + // + // * FLOAT64 + // + // If the type is CATEGORY , only up to + // 100 unique values may exist in that column across all rows. + // + // NOTE: Updates of this field will instantly affect any other users + // concurrently working with the dataset. + string target_column_spec_id = 2; + + // column_spec_id of the primary table's column that should be used as the + // weight column, i.e. the higher the value the more important the row will be + // during model training. + // Required type: FLOAT64. + // Allowed values: 0 to 10000, inclusive on both ends; 0 means the row is + // ignored for training. + // If not set all rows are assumed to have equal weight of 1. + // NOTE: Updates of this field will instantly affect any other users + // concurrently working with the dataset. + string weight_column_spec_id = 3; + + // column_spec_id of the primary table column which specifies a possible ML + // use of the row, i.e. the column will be used to split the rows into TRAIN, + // VALIDATE and TEST sets. + // Required type: STRING. + // This column, if set, must either have all of `TRAIN`, `VALIDATE`, `TEST` + // among its values, or only have `TEST`, `UNASSIGNED` values. In the latter + // case the rows with `UNASSIGNED` value will be assigned by AutoML. Note + // that if a given ml use distribution makes it impossible to create a "good" + // model, that call will error describing the issue. + // If both this column_spec_id and primary table's time_column_spec_id are not + // set, then all rows are treated as `UNASSIGNED`. + // NOTE: Updates of this field will instantly affect any other users + // concurrently working with the dataset. + string ml_use_column_spec_id = 4; + + // Output only. Correlations between + // + // [TablesDatasetMetadata.target_column_spec_id][google.cloud.automl.v1beta1.TablesDatasetMetadata.target_column_spec_id], + // and other columns of the + // + // [TablesDatasetMetadataprimary_table][google.cloud.automl.v1beta1.TablesDatasetMetadata.primary_table_spec_id]. + // Only set if the target column is set. Mapping from other column spec id to + // its CorrelationStats with the target column. + // This field may be stale, see the stats_update_time field for + // for the timestamp at which these stats were last updated. + map target_column_correlations = 6; + + // Output only. The most recent timestamp when target_column_correlations + // field and all descendant ColumnSpec.data_stats and + // ColumnSpec.top_correlated_columns fields were last (re-)generated. Any + // changes that happened to the dataset afterwards are not reflected in these + // fields values. The regeneration happens in the background on a best effort + // basis. + google.protobuf.Timestamp stats_update_time = 7; +} + +// Model metadata specific to AutoML Tables. +message TablesModelMetadata { + // Additional optimization objective configuration. Required for + // `MAXIMIZE_PRECISION_AT_RECALL` and `MAXIMIZE_RECALL_AT_PRECISION`, + // otherwise unused. + oneof additional_optimization_objective_config { + // Required when optimization_objective is "MAXIMIZE_PRECISION_AT_RECALL". + // Must be between 0 and 1, inclusive. + float optimization_objective_recall_value = 17; + + // Required when optimization_objective is "MAXIMIZE_RECALL_AT_PRECISION". + // Must be between 0 and 1, inclusive. + float optimization_objective_precision_value = 18; + } + + // Column spec of the dataset's primary table's column the model is + // predicting. Snapshotted when model creation started. + // Only 3 fields are used: + // name - May be set on CreateModel, if it's not then the ColumnSpec + // corresponding to the current target_column_spec_id of the dataset + // the model is trained from is used. + // If neither is set, CreateModel will error. + // display_name - Output only. + // data_type - Output only. + ColumnSpec target_column_spec = 2; + + // Column specs of the dataset's primary table's columns, on which + // the model is trained and which are used as the input for predictions. + // The + // + // [target_column][google.cloud.automl.v1beta1.TablesModelMetadata.target_column_spec] + // as well as, according to dataset's state upon model creation, + // + // [weight_column][google.cloud.automl.v1beta1.TablesDatasetMetadata.weight_column_spec_id], + // and + // + // [ml_use_column][google.cloud.automl.v1beta1.TablesDatasetMetadata.ml_use_column_spec_id] + // must never be included here. + // + // Only 3 fields are used: + // + // * name - May be set on CreateModel, if set only the columns specified are + // used, otherwise all primary table's columns (except the ones listed + // above) are used for the training and prediction input. + // + // * display_name - Output only. + // + // * data_type - Output only. + repeated ColumnSpec input_feature_column_specs = 3; + + // Objective function the model is optimizing towards. The training process + // creates a model that maximizes/minimizes the value of the objective + // function over the validation set. + // + // The supported optimization objectives depend on the prediction type. + // If the field is not set, a default objective function is used. + // + // CLASSIFICATION_BINARY: + // "MAXIMIZE_AU_ROC" (default) - Maximize the area under the receiver + // operating characteristic (ROC) curve. + // "MINIMIZE_LOG_LOSS" - Minimize log loss. + // "MAXIMIZE_AU_PRC" - Maximize the area under the precision-recall curve. + // "MAXIMIZE_PRECISION_AT_RECALL" - Maximize precision for a specified + // recall value. + // "MAXIMIZE_RECALL_AT_PRECISION" - Maximize recall for a specified + // precision value. + // + // CLASSIFICATION_MULTI_CLASS : + // "MINIMIZE_LOG_LOSS" (default) - Minimize log loss. + // + // + // REGRESSION: + // "MINIMIZE_RMSE" (default) - Minimize root-mean-squared error (RMSE). + // "MINIMIZE_MAE" - Minimize mean-absolute error (MAE). + // "MINIMIZE_RMSLE" - Minimize root-mean-squared log error (RMSLE). + string optimization_objective = 4; + + // Output only. Auxiliary information for each of the + // input_feature_column_specs with respect to this particular model. + repeated TablesModelColumnInfo tables_model_column_info = 5; + + // Required. The train budget of creating this model, expressed in milli node + // hours i.e. 1,000 value in this field means 1 node hour. + // + // The training cost of the model will not exceed this budget. The final cost + // will be attempted to be close to the budget, though may end up being (even) + // noticeably smaller - at the backend's discretion. This especially may + // happen when further model training ceases to provide any improvements. + // + // If the budget is set to a value known to be insufficient to train a + // model for the given dataset, the training won't be attempted and + // will error. + // + // The train budget must be between 1,000 and 72,000 milli node hours, + // inclusive. + int64 train_budget_milli_node_hours = 6; + + // Output only. The actual training cost of the model, expressed in milli + // node hours, i.e. 1,000 value in this field means 1 node hour. Guaranteed + // to not exceed the train budget. + int64 train_cost_milli_node_hours = 7; + + // Use the entire training budget. This disables the early stopping feature. + // By default, the early stopping feature is enabled, which means that AutoML + // Tables might stop training before the entire training budget has been used. + bool disable_early_stopping = 12; +} + +// Contains annotation details specific to Tables. +message TablesAnnotation { + // Output only. A confidence estimate between 0.0 and 1.0, inclusive. A higher + // value means greater confidence in the returned value. + // For + // + // [target_column_spec][google.cloud.automl.v1beta1.TablesModelMetadata.target_column_spec] + // of FLOAT64 data type the score is not populated. + float score = 1; + + // Output only. Only populated when + // + // [target_column_spec][google.cloud.automl.v1beta1.TablesModelMetadata.target_column_spec] + // has FLOAT64 data type. An interval in which the exactly correct target + // value has 95% chance to be in. + DoubleRange prediction_interval = 4; + + // The predicted value of the row's + // + // [target_column][google.cloud.automl.v1beta1.TablesModelMetadata.target_column_spec]. + // The value depends on the column's DataType: + // + // * CATEGORY - the predicted (with the above confidence `score`) CATEGORY + // value. + // + // * FLOAT64 - the predicted (with above `prediction_interval`) FLOAT64 value. + google.protobuf.Value value = 2; + + // Output only. Auxiliary information for each of the model's + // + // [input_feature_column_specs][google.cloud.automl.v1beta1.TablesModelMetadata.input_feature_column_specs] + // with respect to this particular prediction. + // If no other fields than + // + // [column_spec_name][google.cloud.automl.v1beta1.TablesModelColumnInfo.column_spec_name] + // and + // + // [column_display_name][google.cloud.automl.v1beta1.TablesModelColumnInfo.column_display_name] + // would be populated, then this whole field is not. + repeated TablesModelColumnInfo tables_model_column_info = 3; + + // Output only. Stores the prediction score for the baseline example, which + // is defined as the example with all values set to their baseline values. + // This is used as part of the Sampled Shapley explanation of the model's + // prediction. This field is populated only when feature importance is + // requested. For regression models, this holds the baseline prediction for + // the baseline example. For classification models, this holds the baseline + // prediction for the baseline example for the argmax class. + float baseline_score = 5; +} + +// An information specific to given column and Tables Model, in context +// of the Model and the predictions created by it. +message TablesModelColumnInfo { + // Output only. The name of the ColumnSpec describing the column. Not + // populated when this proto is outputted to BigQuery. + string column_spec_name = 1; + + // Output only. The display name of the column (same as the display_name of + // its ColumnSpec). + string column_display_name = 2; + + // Output only. When given as part of a Model (always populated): + // Measurement of how much model predictions correctness on the TEST data + // depend on values in this column. A value between 0 and 1, higher means + // higher influence. These values are normalized - for all input feature + // columns of a given model they add to 1. + // + // When given back by Predict (populated iff + // [feature_importance + // param][google.cloud.automl.v1beta1.PredictRequest.params] is set) or Batch + // Predict (populated iff + // [feature_importance][google.cloud.automl.v1beta1.PredictRequest.params] + // param is set): + // Measurement of how impactful for the prediction returned for the given row + // the value in this column was. Specifically, the feature importance + // specifies the marginal contribution that the feature made to the prediction + // score compared to the baseline score. These values are computed using the + // Sampled Shapley method. + float feature_importance = 3; +} diff --git a/google/cloud/automl_v1beta1/proto/temporal.proto b/google/cloud/automl_v1beta1/proto/temporal.proto new file mode 100644 index 00000000..76db8887 --- /dev/null +++ b/google/cloud/automl_v1beta1/proto/temporal.proto @@ -0,0 +1,37 @@ +// 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. + +syntax = "proto3"; + +package google.cloud.automl.v1beta1; + +import "google/protobuf/duration.proto"; +import "google/api/annotations.proto"; + +option go_package = "google.golang.org/genproto/googleapis/cloud/automl/v1beta1;automl"; +option java_multiple_files = true; +option java_package = "com.google.cloud.automl.v1beta1"; +option php_namespace = "Google\\Cloud\\AutoMl\\V1beta1"; +option ruby_package = "Google::Cloud::AutoML::V1beta1"; + +// A time period inside of an example that has a time dimension (e.g. video). +message TimeSegment { + // Start of the time segment (inclusive), represented as the duration since + // the example start. + google.protobuf.Duration start_time_offset = 1; + + // End of the time segment (exclusive), represented as the duration since the + // example start. + google.protobuf.Duration end_time_offset = 2; +} diff --git a/google/cloud/automl_v1beta1/proto/text.proto b/google/cloud/automl_v1beta1/proto/text.proto new file mode 100644 index 00000000..3319a094 --- /dev/null +++ b/google/cloud/automl_v1beta1/proto/text.proto @@ -0,0 +1,71 @@ +// 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. + +syntax = "proto3"; + +package google.cloud.automl.v1beta1; + +import "google/cloud/automl/v1beta1/classification.proto"; +import "google/api/annotations.proto"; + +option go_package = "google.golang.org/genproto/googleapis/cloud/automl/v1beta1;automl"; +option java_multiple_files = true; +option java_outer_classname = "TextProto"; +option java_package = "com.google.cloud.automl.v1beta1"; +option php_namespace = "Google\\Cloud\\AutoMl\\V1beta1"; +option ruby_package = "Google::Cloud::AutoML::V1beta1"; + +// Dataset metadata for classification. +message TextClassificationDatasetMetadata { + // Required. Type of the classification problem. + ClassificationType classification_type = 1; +} + +// Model metadata that is specific to text classification. +message TextClassificationModelMetadata { + // Output only. Classification type of the dataset used to train this model. + ClassificationType classification_type = 3; +} + +// Dataset metadata that is specific to text extraction +message TextExtractionDatasetMetadata { + +} + +// Model metadata that is specific to text extraction. +message TextExtractionModelMetadata { + // Indicates the scope of model use case. + // + // * `default`: Use to train a general text extraction model. Default value. + // + // * `health_care`: Use to train a text extraction model that is tuned for + // healthcare applications. + string model_hint = 3; +} + +// Dataset metadata for text sentiment. +message TextSentimentDatasetMetadata { + // Required. A sentiment is expressed as an integer ordinal, where higher value + // means a more positive sentiment. The range of sentiments that will be used + // is between 0 and sentiment_max (inclusive on both ends), and all the values + // in the range must be represented in the dataset before a model can be + // created. + // sentiment_max value must be between 1 and 10 (inclusive). + int32 sentiment_max = 1; +} + +// Model metadata that is specific to text sentiment. +message TextSentimentModelMetadata { + +} diff --git a/google/cloud/automl_v1beta1/proto/text_extraction.proto b/google/cloud/automl_v1beta1/proto/text_extraction.proto new file mode 100644 index 00000000..cfb0e0b3 --- /dev/null +++ b/google/cloud/automl_v1beta1/proto/text_extraction.proto @@ -0,0 +1,68 @@ +// 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. + +syntax = "proto3"; + +package google.cloud.automl.v1beta1; + +import "google/cloud/automl/v1beta1/text_segment.proto"; +import "google/api/annotations.proto"; + +option go_package = "google.golang.org/genproto/googleapis/cloud/automl/v1beta1;automl"; +option java_multiple_files = true; +option java_package = "com.google.cloud.automl.v1beta1"; +option php_namespace = "Google\\Cloud\\AutoMl\\V1beta1"; +option ruby_package = "Google::Cloud::AutoML::V1beta1"; + +// Annotation for identifying spans of text. +message TextExtractionAnnotation { + // Required. Text extraction annotations can either be a text segment or a + // text relation. + oneof annotation { + // An entity annotation will set this, which is the part of the original + // text to which the annotation pertains. + TextSegment text_segment = 3; + } + + // Output only. A confidence estimate between 0.0 and 1.0. A higher value + // means greater confidence in correctness of the annotation. + float score = 1; +} + +// Model evaluation metrics for text extraction problems. +message TextExtractionEvaluationMetrics { + // Metrics for a single confidence threshold. + message ConfidenceMetricsEntry { + // Output only. The confidence threshold value used to compute the metrics. + // Only annotations with score of at least this threshold are considered to + // be ones the model would return. + float confidence_threshold = 1; + + // Output only. Recall under the given confidence threshold. + float recall = 3; + + // Output only. Precision under the given confidence threshold. + float precision = 4; + + // Output only. The harmonic mean of recall and precision. + float f1_score = 5; + } + + // Output only. The Area under precision recall curve metric. + float au_prc = 1; + + // Output only. Metrics that have confidence thresholds. + // Precision-recall curve can be derived from it. + repeated ConfidenceMetricsEntry confidence_metrics_entries = 2; +} diff --git a/google/cloud/automl_v1beta1/proto/text_segment.proto b/google/cloud/automl_v1beta1/proto/text_segment.proto new file mode 100644 index 00000000..94b17d93 --- /dev/null +++ b/google/cloud/automl_v1beta1/proto/text_segment.proto @@ -0,0 +1,41 @@ +// 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. + +syntax = "proto3"; + +package google.cloud.automl.v1beta1; + +import "google/api/annotations.proto"; + +option go_package = "google.golang.org/genproto/googleapis/cloud/automl/v1beta1;automl"; +option java_multiple_files = true; +option java_outer_classname = "TextSegmentProto"; +option java_package = "com.google.cloud.automl.v1beta1"; +option php_namespace = "Google\\Cloud\\AutoMl\\V1beta1"; +option ruby_package = "Google::Cloud::AutoML::V1beta1"; + +// A contiguous part of a text (string), assuming it has an UTF-8 NFC encoding. +message TextSegment { + // Output only. The content of the TextSegment. + string content = 3; + + // Required. Zero-based character index of the first character of the text + // segment (counting characters from the beginning of the text). + int64 start_offset = 1; + + // Required. Zero-based character index of the first character past the end of + // the text segment (counting character from the beginning of the text). + // The character at the end_offset is NOT included in the text segment. + int64 end_offset = 2; +} diff --git a/google/cloud/automl_v1beta1/proto/text_sentiment.proto b/google/cloud/automl_v1beta1/proto/text_sentiment.proto new file mode 100644 index 00000000..5444c52b --- /dev/null +++ b/google/cloud/automl_v1beta1/proto/text_sentiment.proto @@ -0,0 +1,80 @@ +// 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. + +syntax = "proto3"; + +package google.cloud.automl.v1beta1; + +import "google/cloud/automl/v1beta1/classification.proto"; +import "google/api/annotations.proto"; + +option go_package = "google.golang.org/genproto/googleapis/cloud/automl/v1beta1;automl"; +option java_outer_classname = "TextSentimentProto"; +option java_package = "com.google.cloud.automl.v1beta1"; +option php_namespace = "Google\\Cloud\\AutoMl\\V1beta1"; +option ruby_package = "Google::Cloud::AutoML::V1beta1"; + +// Contains annotation details specific to text sentiment. +message TextSentimentAnnotation { + // Output only. The sentiment with the semantic, as given to the + // [AutoMl.ImportData][google.cloud.automl.v1beta1.AutoMl.ImportData] when populating the dataset from which the model used + // for the prediction had been trained. + // The sentiment values are between 0 and + // Dataset.text_sentiment_dataset_metadata.sentiment_max (inclusive), + // with higher value meaning more positive sentiment. They are completely + // relative, i.e. 0 means least positive sentiment and sentiment_max means + // the most positive from the sentiments present in the train data. Therefore + // e.g. if train data had only negative sentiment, then sentiment_max, would + // be still negative (although least negative). + // The sentiment shouldn't be confused with "score" or "magnitude" + // from the previous Natural Language Sentiment Analysis API. + int32 sentiment = 1; +} + +// Model evaluation metrics for text sentiment problems. +message TextSentimentEvaluationMetrics { + // Output only. Precision. + float precision = 1; + + // Output only. Recall. + float recall = 2; + + // Output only. The harmonic mean of recall and precision. + float f1_score = 3; + + // Output only. Mean absolute error. Only set for the overall model + // evaluation, not for evaluation of a single annotation spec. + float mean_absolute_error = 4; + + // Output only. Mean squared error. Only set for the overall model + // evaluation, not for evaluation of a single annotation spec. + float mean_squared_error = 5; + + // Output only. Linear weighted kappa. Only set for the overall model + // evaluation, not for evaluation of a single annotation spec. + float linear_kappa = 6; + + // Output only. Quadratic weighted kappa. Only set for the overall model + // evaluation, not for evaluation of a single annotation spec. + float quadratic_kappa = 7; + + // Output only. Confusion matrix of the evaluation. + // Only set for the overall model evaluation, not for evaluation of a single + // annotation spec. + ClassificationEvaluationMetrics.ConfusionMatrix confusion_matrix = 8; + + // Output only. The annotation spec ids used for this evaluation. + // Deprecated . + repeated string annotation_spec_id = 9 [deprecated = true]; +} diff --git a/google/cloud/automl_v1beta1/proto/translation.proto b/google/cloud/automl_v1beta1/proto/translation.proto new file mode 100644 index 00000000..8585bd41 --- /dev/null +++ b/google/cloud/automl_v1beta1/proto/translation.proto @@ -0,0 +1,69 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.cloud.automl.v1beta1; + +import "google/api/field_behavior.proto"; +import "google/cloud/automl/v1beta1/data_items.proto"; +import "google/api/annotations.proto"; + +option go_package = "google.golang.org/genproto/googleapis/cloud/automl/v1beta1;automl"; +option java_multiple_files = true; +option java_outer_classname = "TranslationProto"; +option java_package = "com.google.cloud.automl.v1beta1"; +option php_namespace = "Google\\Cloud\\AutoMl\\V1beta1"; +option ruby_package = "Google::Cloud::AutoML::V1beta1"; + +// Dataset metadata that is specific to translation. +message TranslationDatasetMetadata { + // Required. The BCP-47 language code of the source language. + string source_language_code = 1 [(google.api.field_behavior) = REQUIRED]; + + // Required. The BCP-47 language code of the target language. + string target_language_code = 2 [(google.api.field_behavior) = REQUIRED]; +} + +// Evaluation metrics for the dataset. +message TranslationEvaluationMetrics { + // Output only. BLEU score. + double bleu_score = 1; + + // Output only. BLEU score for base model. + double base_bleu_score = 2; +} + +// Model metadata that is specific to translation. +message TranslationModelMetadata { + // The resource name of the model to use as a baseline to train the custom + // model. If unset, we use the default base model provided by Google + // Translate. Format: + // `projects/{project_id}/locations/{location_id}/models/{model_id}` + string base_model = 1; + + // Output only. Inferred from the dataset. + // The source languge (The BCP-47 language code) that is used for training. + string source_language_code = 2; + + // Output only. The target languge (The BCP-47 language code) that is used for + // training. + string target_language_code = 3; +} + +// Annotation details specific to translation. +message TranslationAnnotation { + // Output only . The translated content. + TextSnippet translated_content = 1; +} diff --git a/google/cloud/automl_v1beta1/proto/video.proto b/google/cloud/automl_v1beta1/proto/video.proto new file mode 100644 index 00000000..268ae2a8 --- /dev/null +++ b/google/cloud/automl_v1beta1/proto/video.proto @@ -0,0 +1,48 @@ +// 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. + +syntax = "proto3"; + +package google.cloud.automl.v1beta1; + +import "google/cloud/automl/v1beta1/classification.proto"; +import "google/api/annotations.proto"; + +option go_package = "google.golang.org/genproto/googleapis/cloud/automl/v1beta1;automl"; +option java_multiple_files = true; +option java_outer_classname = "VideoProto"; +option java_package = "com.google.cloud.automl.v1beta1"; +option php_namespace = "Google\\Cloud\\AutoMl\\V1beta1"; +option ruby_package = "Google::Cloud::AutoML::V1beta1"; + +// Dataset metadata specific to video classification. +// All Video Classification datasets are treated as multi label. +message VideoClassificationDatasetMetadata { + +} + +// Dataset metadata specific to video object tracking. +message VideoObjectTrackingDatasetMetadata { + +} + +// Model metadata specific to video classification. +message VideoClassificationModelMetadata { + +} + +// Model metadata specific to video object tracking. +message VideoObjectTrackingModelMetadata { + +} diff --git a/google/cloud/automl_v1beta1/services/auto_ml/async_client.py b/google/cloud/automl_v1beta1/services/auto_ml/async_client.py index 5c6d1f5b..b7a10974 100644 --- a/google/cloud/automl_v1beta1/services/auto_ml/async_client.py +++ b/google/cloud/automl_v1beta1/services/auto_ml/async_client.py @@ -28,8 +28,8 @@ from google.auth import credentials # type: ignore from google.oauth2 import service_account # type: ignore -from google.api_core import operation -from google.api_core import operation_async +from google.api_core import operation # type: ignore +from google.api_core import operation_async # type: ignore from google.cloud.automl_v1beta1.services.auto_ml import pagers from google.cloud.automl_v1beta1.types import annotation_spec from google.cloud.automl_v1beta1.types import classification @@ -87,13 +87,14 @@ class AutoMlAsyncClient: DEFAULT_ENDPOINT = AutoMlClient.DEFAULT_ENDPOINT DEFAULT_MTLS_ENDPOINT = AutoMlClient.DEFAULT_MTLS_ENDPOINT + column_spec_path = staticmethod(AutoMlClient.column_spec_path) + parse_column_spec_path = staticmethod(AutoMlClient.parse_column_spec_path) dataset_path = staticmethod(AutoMlClient.dataset_path) - + parse_dataset_path = staticmethod(AutoMlClient.parse_dataset_path) model_path = staticmethod(AutoMlClient.model_path) - - column_spec_path = staticmethod(AutoMlClient.column_spec_path) - + parse_model_path = staticmethod(AutoMlClient.parse_model_path) table_spec_path = staticmethod(AutoMlClient.table_spec_path) + parse_table_spec_path = staticmethod(AutoMlClient.parse_table_spec_path) from_service_account_file = AutoMlClient.from_service_account_file from_service_account_json = from_service_account_file @@ -124,16 +125,19 @@ def __init__( client_options (ClientOptions): Custom options for the client. It won't take effect if a ``transport`` instance is provided. (1) The ``api_endpoint`` property can be used to override the - default endpoint provided by the client. GOOGLE_API_USE_MTLS + default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT environment variable can also be used to override the endpoint: "always" (always use the default mTLS endpoint), "never" (always - use the default regular endpoint, this is the default value for - the environment variable) and "auto" (auto switch to the default - mTLS endpoint if client SSL credentials is present). However, - the ``api_endpoint`` property takes precedence if provided. - (2) The ``client_cert_source`` property is used to provide client - SSL credentials for mutual TLS transport. If not provided, the - default SSL credentials will be used if present. + use the default regular endpoint) and "auto" (auto switch to the + default mTLS endpoint if client certificate is present, this is + the default value). However, the ``api_endpoint`` property takes + precedence if provided. + (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable + is "true", then the ``client_cert_source`` property can be used + to provide client certificate for mutual TLS transport. If + not provided, the default SSL client certificate will be used if + present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not + set, no client certificate will be used. Raises: google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport diff --git a/google/cloud/automl_v1beta1/services/auto_ml/client.py b/google/cloud/automl_v1beta1/services/auto_ml/client.py index 9416b524..6ae4f4c2 100644 --- a/google/cloud/automl_v1beta1/services/auto_ml/client.py +++ b/google/cloud/automl_v1beta1/services/auto_ml/client.py @@ -16,22 +16,24 @@ # from collections import OrderedDict +from distutils import util import os import re -from typing import Callable, Dict, Sequence, Tuple, Type, Union +from typing import Callable, Dict, Optional, Sequence, Tuple, Type, Union import pkg_resources -import google.api_core.client_options as ClientOptions # type: ignore +from google.api_core import client_options as client_options_lib # type: ignore from google.api_core import exceptions # type: ignore from google.api_core import gapic_v1 # type: ignore from google.api_core import retry as retries # type: ignore from google.auth import credentials # type: ignore from google.auth.transport import mtls # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore from google.auth.exceptions import MutualTLSChannelError # type: ignore from google.oauth2 import service_account # type: ignore -from google.api_core import operation -from google.api_core import operation_async +from google.api_core import operation # type: ignore +from google.api_core import operation_async # type: ignore from google.cloud.automl_v1beta1.services.auto_ml import pagers from google.cloud.automl_v1beta1.types import annotation_spec from google.cloud.automl_v1beta1.types import classification @@ -244,9 +246,9 @@ def parse_table_spec_path(path: str) -> Dict[str, str]: def __init__( self, *, - credentials: credentials.Credentials = None, - transport: Union[str, AutoMlTransport] = None, - client_options: ClientOptions = None, + credentials: Optional[credentials.Credentials] = None, + transport: Union[str, AutoMlTransport, None] = None, + client_options: Optional[client_options_lib.ClientOptions] = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: """Instantiate the auto ml client. @@ -260,19 +262,22 @@ def __init__( transport (Union[str, ~.AutoMlTransport]): The transport to use. If set to None, a transport is chosen automatically. - client_options (ClientOptions): Custom options for the client. It - won't take effect if a ``transport`` instance is provided. + client_options (client_options_lib.ClientOptions): Custom options for the + client. It won't take effect if a ``transport`` instance is provided. (1) The ``api_endpoint`` property can be used to override the - default endpoint provided by the client. GOOGLE_API_USE_MTLS + default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT environment variable can also be used to override the endpoint: "always" (always use the default mTLS endpoint), "never" (always - use the default regular endpoint, this is the default value for - the environment variable) and "auto" (auto switch to the default - mTLS endpoint if client SSL credentials is present). However, - the ``api_endpoint`` property takes precedence if provided. - (2) The ``client_cert_source`` property is used to provide client - SSL credentials for mutual TLS transport. If not provided, the - default SSL credentials will be used if present. + use the default regular endpoint) and "auto" (auto switch to the + default mTLS endpoint if client certificate is present, this is + the default value). However, the ``api_endpoint`` property takes + precedence if provided. + (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable + is "true", then the ``client_cert_source`` property can be used + to provide client certificate for mutual TLS transport. If + not provided, the default SSL client certificate will be used if + present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not + set, no client certificate will be used. client_info (google.api_core.gapic_v1.client_info.ClientInfo): The client info used to send a user-agent string along with API requests. If ``None``, then default info will be used. @@ -284,29 +289,47 @@ def __init__( creation failed for any reason. """ if isinstance(client_options, dict): - client_options = ClientOptions.from_dict(client_options) + client_options = client_options_lib.from_dict(client_options) if client_options is None: - client_options = ClientOptions.ClientOptions() + client_options = client_options_lib.ClientOptions() - if client_options.api_endpoint is None: - use_mtls_env = os.getenv("GOOGLE_API_USE_MTLS", "never") + # Create SSL credentials for mutual TLS if needed. + use_client_cert = bool( + util.strtobool(os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false")) + ) + + ssl_credentials = None + is_mtls = False + if use_client_cert: + if client_options.client_cert_source: + import grpc # type: ignore + + cert, key = client_options.client_cert_source() + ssl_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + is_mtls = True + else: + creds = SslCredentials() + is_mtls = creds.is_mtls + ssl_credentials = creds.ssl_credentials if is_mtls else None + + # Figure out which api endpoint to use. + if client_options.api_endpoint is not None: + api_endpoint = client_options.api_endpoint + else: + use_mtls_env = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto") if use_mtls_env == "never": - client_options.api_endpoint = self.DEFAULT_ENDPOINT + api_endpoint = self.DEFAULT_ENDPOINT elif use_mtls_env == "always": - client_options.api_endpoint = self.DEFAULT_MTLS_ENDPOINT + api_endpoint = self.DEFAULT_MTLS_ENDPOINT elif use_mtls_env == "auto": - has_client_cert_source = ( - client_options.client_cert_source is not None - or mtls.has_default_client_cert_source() - ) - client_options.api_endpoint = ( - self.DEFAULT_MTLS_ENDPOINT - if has_client_cert_source - else self.DEFAULT_ENDPOINT + api_endpoint = ( + self.DEFAULT_MTLS_ENDPOINT if is_mtls else self.DEFAULT_ENDPOINT ) else: raise MutualTLSChannelError( - "Unsupported GOOGLE_API_USE_MTLS value. Accepted values: never, auto, always" + "Unsupported GOOGLE_API_USE_MTLS_ENDPOINT value. Accepted values: never, auto, always" ) # Save or instantiate the transport. @@ -330,10 +353,9 @@ def __init__( self._transport = Transport( credentials=credentials, credentials_file=client_options.credentials_file, - host=client_options.api_endpoint, + host=api_endpoint, scopes=client_options.scopes, - api_mtls_endpoint=client_options.api_endpoint, - client_cert_source=client_options.client_cert_source, + ssl_channel_credentials=ssl_credentials, quota_project_id=client_options.quota_project_id, client_info=client_info, ) diff --git a/google/cloud/automl_v1beta1/services/auto_ml/transports/base.py b/google/cloud/automl_v1beta1/services/auto_ml/transports/base.py index d50f2201..642c9f7b 100644 --- a/google/cloud/automl_v1beta1/services/auto_ml/transports/base.py +++ b/google/cloud/automl_v1beta1/services/auto_ml/transports/base.py @@ -19,7 +19,7 @@ import typing import pkg_resources -from google import auth +from google import auth # type: ignore from google.api_core import exceptions # type: ignore from google.api_core import gapic_v1 # type: ignore from google.api_core import retry as retries # type: ignore diff --git a/google/cloud/automl_v1beta1/services/auto_ml/transports/grpc.py b/google/cloud/automl_v1beta1/services/auto_ml/transports/grpc.py index a3c183e4..a8cb2fd7 100644 --- a/google/cloud/automl_v1beta1/services/auto_ml/transports/grpc.py +++ b/google/cloud/automl_v1beta1/services/auto_ml/transports/grpc.py @@ -15,6 +15,7 @@ # limitations under the License. # +import warnings from typing import Callable, Dict, Optional, Sequence, Tuple from google.api_core import grpc_helpers # type: ignore @@ -24,7 +25,6 @@ from google.auth import credentials # type: ignore from google.auth.transport.grpc import SslCredentials # type: ignore - import grpc # type: ignore from google.cloud.automl_v1beta1.types import annotation_spec @@ -81,6 +81,7 @@ def __init__( channel: grpc.Channel = None, api_mtls_endpoint: str = None, client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, + ssl_channel_credentials: grpc.ChannelCredentials = None, quota_project_id: Optional[str] = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: @@ -101,14 +102,16 @@ def __init__( ignored if ``channel`` is provided. channel (Optional[grpc.Channel]): A ``Channel`` instance through which to make calls. - api_mtls_endpoint (Optional[str]): The mutual TLS endpoint. If - provided, it overrides the ``host`` argument and tries to create + api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. + If provided, it overrides the ``host`` argument and tries to create a mutual TLS channel with client SSL credentials from ``client_cert_source`` or applicatin default SSL credentials. - client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): A - callback to provide client SSL certificate bytes and private key - bytes, both in PEM format. It is ignored if ``api_mtls_endpoint`` - is None. + client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): + Deprecated. A callback to provide client SSL certificate bytes and + private key bytes, both in PEM format. It is ignored if + ``api_mtls_endpoint`` is None. + ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials + for grpc channel. It is ignored if ``channel`` is provided. quota_project_id (Optional[str]): An optional project to use for billing and quota. client_info (google.api_core.gapic_v1.client_info.ClientInfo): @@ -131,6 +134,11 @@ def __init__( # If a channel was explicitly provided, set it. self._grpc_channel = channel elif api_mtls_endpoint: + warnings.warn( + "api_mtls_endpoint and client_cert_source are deprecated", + DeprecationWarning, + ) + host = ( api_mtls_endpoint if ":" in api_mtls_endpoint @@ -161,6 +169,23 @@ def __init__( scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, ) + else: + host = host if ":" in host else host + ":443" + + if credentials is None: + credentials, _ = auth.default( + scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id + ) + + # create a new channel. The provided one is ignored. + self._grpc_channel = type(self).create_channel( + host, + credentials=credentials, + credentials_file=credentials_file, + ssl_credentials=ssl_channel_credentials, + scopes=scopes or self.AUTH_SCOPES, + quota_project_id=quota_project_id, + ) self._stubs = {} # type: Dict[str, Callable] @@ -226,13 +251,6 @@ def grpc_channel(self) -> grpc.Channel: This property caches on the instance; repeated calls return the same channel. """ - # Sanity check: Only create a new channel if we do not already - # have one. - if not hasattr(self, "_grpc_channel"): - self._grpc_channel = self.create_channel( - self._host, credentials=self._credentials, - ) - # Return the channel from cache. return self._grpc_channel diff --git a/google/cloud/automl_v1beta1/services/auto_ml/transports/grpc_asyncio.py b/google/cloud/automl_v1beta1/services/auto_ml/transports/grpc_asyncio.py index c8d24dad..a977ad45 100644 --- a/google/cloud/automl_v1beta1/services/auto_ml/transports/grpc_asyncio.py +++ b/google/cloud/automl_v1beta1/services/auto_ml/transports/grpc_asyncio.py @@ -15,11 +15,13 @@ # limitations under the License. # +import warnings from typing import Awaitable, Callable, Dict, Optional, Sequence, Tuple from google.api_core import gapic_v1 # type: ignore from google.api_core import grpc_helpers_async # type: ignore from google.api_core import operations_v1 # type: ignore +from google import auth # type: ignore from google.auth import credentials # type: ignore from google.auth.transport.grpc import SslCredentials # type: ignore @@ -123,6 +125,7 @@ def __init__( channel: aio.Channel = None, api_mtls_endpoint: str = None, client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, + ssl_channel_credentials: grpc.ChannelCredentials = None, quota_project_id=None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: @@ -144,14 +147,16 @@ def __init__( are passed to :func:`google.auth.default`. channel (Optional[aio.Channel]): A ``Channel`` instance through which to make calls. - api_mtls_endpoint (Optional[str]): The mutual TLS endpoint. If - provided, it overrides the ``host`` argument and tries to create + api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. + If provided, it overrides the ``host`` argument and tries to create a mutual TLS channel with client SSL credentials from ``client_cert_source`` or applicatin default SSL credentials. - client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): A - callback to provide client SSL certificate bytes and private key - bytes, both in PEM format. It is ignored if ``api_mtls_endpoint`` - is None. + client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): + Deprecated. A callback to provide client SSL certificate bytes and + private key bytes, both in PEM format. It is ignored if + ``api_mtls_endpoint`` is None. + ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials + for grpc channel. It is ignored if ``channel`` is provided. quota_project_id (Optional[str]): An optional project to use for billing and quota. client_info (google.api_core.gapic_v1.client_info.ClientInfo): @@ -174,12 +179,22 @@ def __init__( # If a channel was explicitly provided, set it. self._grpc_channel = channel elif api_mtls_endpoint: + warnings.warn( + "api_mtls_endpoint and client_cert_source are deprecated", + DeprecationWarning, + ) + host = ( api_mtls_endpoint if ":" in api_mtls_endpoint else api_mtls_endpoint + ":443" ) + if credentials is None: + credentials, _ = auth.default( + scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id + ) + # Create SSL credentials with client_cert_source or application # default SSL credentials. if client_cert_source: @@ -199,6 +214,23 @@ def __init__( scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, ) + else: + host = host if ":" in host else host + ":443" + + if credentials is None: + credentials, _ = auth.default( + scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id + ) + + # create a new channel. The provided one is ignored. + self._grpc_channel = type(self).create_channel( + host, + credentials=credentials, + credentials_file=credentials_file, + ssl_credentials=ssl_channel_credentials, + scopes=scopes or self.AUTH_SCOPES, + quota_project_id=quota_project_id, + ) # Run the base constructor. super().__init__( @@ -219,13 +251,6 @@ def grpc_channel(self) -> aio.Channel: This property caches on the instance; repeated calls return the same channel. """ - # Sanity check: Only create a new channel if we do not already - # have one. - if not hasattr(self, "_grpc_channel"): - self._grpc_channel = self.create_channel( - self._host, credentials=self._credentials, - ) - # Return the channel from cache. return self._grpc_channel diff --git a/google/cloud/automl_v1beta1/services/prediction_service/async_client.py b/google/cloud/automl_v1beta1/services/prediction_service/async_client.py index cd313402..c204325b 100644 --- a/google/cloud/automl_v1beta1/services/prediction_service/async_client.py +++ b/google/cloud/automl_v1beta1/services/prediction_service/async_client.py @@ -28,8 +28,8 @@ from google.auth import credentials # type: ignore from google.oauth2 import service_account # type: ignore -from google.api_core import operation -from google.api_core import operation_async +from google.api_core import operation # type: ignore +from google.api_core import operation_async # type: ignore from google.cloud.automl_v1beta1.types import annotation_payload from google.cloud.automl_v1beta1.types import data_items from google.cloud.automl_v1beta1.types import io @@ -82,16 +82,19 @@ def __init__( client_options (ClientOptions): Custom options for the client. It won't take effect if a ``transport`` instance is provided. (1) The ``api_endpoint`` property can be used to override the - default endpoint provided by the client. GOOGLE_API_USE_MTLS + default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT environment variable can also be used to override the endpoint: "always" (always use the default mTLS endpoint), "never" (always - use the default regular endpoint, this is the default value for - the environment variable) and "auto" (auto switch to the default - mTLS endpoint if client SSL credentials is present). However, - the ``api_endpoint`` property takes precedence if provided. - (2) The ``client_cert_source`` property is used to provide client - SSL credentials for mutual TLS transport. If not provided, the - default SSL credentials will be used if present. + use the default regular endpoint) and "auto" (auto switch to the + default mTLS endpoint if client certificate is present, this is + the default value). However, the ``api_endpoint`` property takes + precedence if provided. + (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable + is "true", then the ``client_cert_source`` property can be used + to provide client certificate for mutual TLS transport. If + not provided, the default SSL client certificate will be used if + present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not + set, no client certificate will be used. Raises: google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport diff --git a/google/cloud/automl_v1beta1/services/prediction_service/client.py b/google/cloud/automl_v1beta1/services/prediction_service/client.py index 81cb0649..78ec510c 100644 --- a/google/cloud/automl_v1beta1/services/prediction_service/client.py +++ b/google/cloud/automl_v1beta1/services/prediction_service/client.py @@ -16,22 +16,24 @@ # from collections import OrderedDict +from distutils import util import os import re -from typing import Callable, Dict, Sequence, Tuple, Type, Union +from typing import Callable, Dict, Optional, Sequence, Tuple, Type, Union import pkg_resources -import google.api_core.client_options as ClientOptions # type: ignore +from google.api_core import client_options as client_options_lib # type: ignore from google.api_core import exceptions # type: ignore from google.api_core import gapic_v1 # type: ignore from google.api_core import retry as retries # type: ignore from google.auth import credentials # type: ignore from google.auth.transport import mtls # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore from google.auth.exceptions import MutualTLSChannelError # type: ignore from google.oauth2 import service_account # type: ignore -from google.api_core import operation -from google.api_core import operation_async +from google.api_core import operation # type: ignore +from google.api_core import operation_async # type: ignore from google.cloud.automl_v1beta1.types import annotation_payload from google.cloud.automl_v1beta1.types import data_items from google.cloud.automl_v1beta1.types import io @@ -142,9 +144,9 @@ def from_service_account_file(cls, filename: str, *args, **kwargs): def __init__( self, *, - credentials: credentials.Credentials = None, - transport: Union[str, PredictionServiceTransport] = None, - client_options: ClientOptions = None, + credentials: Optional[credentials.Credentials] = None, + transport: Union[str, PredictionServiceTransport, None] = None, + client_options: Optional[client_options_lib.ClientOptions] = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: """Instantiate the prediction service client. @@ -158,19 +160,22 @@ def __init__( transport (Union[str, ~.PredictionServiceTransport]): The transport to use. If set to None, a transport is chosen automatically. - client_options (ClientOptions): Custom options for the client. It - won't take effect if a ``transport`` instance is provided. + client_options (client_options_lib.ClientOptions): Custom options for the + client. It won't take effect if a ``transport`` instance is provided. (1) The ``api_endpoint`` property can be used to override the - default endpoint provided by the client. GOOGLE_API_USE_MTLS + default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT environment variable can also be used to override the endpoint: "always" (always use the default mTLS endpoint), "never" (always - use the default regular endpoint, this is the default value for - the environment variable) and "auto" (auto switch to the default - mTLS endpoint if client SSL credentials is present). However, - the ``api_endpoint`` property takes precedence if provided. - (2) The ``client_cert_source`` property is used to provide client - SSL credentials for mutual TLS transport. If not provided, the - default SSL credentials will be used if present. + use the default regular endpoint) and "auto" (auto switch to the + default mTLS endpoint if client certificate is present, this is + the default value). However, the ``api_endpoint`` property takes + precedence if provided. + (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable + is "true", then the ``client_cert_source`` property can be used + to provide client certificate for mutual TLS transport. If + not provided, the default SSL client certificate will be used if + present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not + set, no client certificate will be used. client_info (google.api_core.gapic_v1.client_info.ClientInfo): The client info used to send a user-agent string along with API requests. If ``None``, then default info will be used. @@ -182,29 +187,47 @@ def __init__( creation failed for any reason. """ if isinstance(client_options, dict): - client_options = ClientOptions.from_dict(client_options) + client_options = client_options_lib.from_dict(client_options) if client_options is None: - client_options = ClientOptions.ClientOptions() + client_options = client_options_lib.ClientOptions() - if client_options.api_endpoint is None: - use_mtls_env = os.getenv("GOOGLE_API_USE_MTLS", "never") + # Create SSL credentials for mutual TLS if needed. + use_client_cert = bool( + util.strtobool(os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false")) + ) + + ssl_credentials = None + is_mtls = False + if use_client_cert: + if client_options.client_cert_source: + import grpc # type: ignore + + cert, key = client_options.client_cert_source() + ssl_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + is_mtls = True + else: + creds = SslCredentials() + is_mtls = creds.is_mtls + ssl_credentials = creds.ssl_credentials if is_mtls else None + + # Figure out which api endpoint to use. + if client_options.api_endpoint is not None: + api_endpoint = client_options.api_endpoint + else: + use_mtls_env = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto") if use_mtls_env == "never": - client_options.api_endpoint = self.DEFAULT_ENDPOINT + api_endpoint = self.DEFAULT_ENDPOINT elif use_mtls_env == "always": - client_options.api_endpoint = self.DEFAULT_MTLS_ENDPOINT + api_endpoint = self.DEFAULT_MTLS_ENDPOINT elif use_mtls_env == "auto": - has_client_cert_source = ( - client_options.client_cert_source is not None - or mtls.has_default_client_cert_source() - ) - client_options.api_endpoint = ( - self.DEFAULT_MTLS_ENDPOINT - if has_client_cert_source - else self.DEFAULT_ENDPOINT + api_endpoint = ( + self.DEFAULT_MTLS_ENDPOINT if is_mtls else self.DEFAULT_ENDPOINT ) else: raise MutualTLSChannelError( - "Unsupported GOOGLE_API_USE_MTLS value. Accepted values: never, auto, always" + "Unsupported GOOGLE_API_USE_MTLS_ENDPOINT value. Accepted values: never, auto, always" ) # Save or instantiate the transport. @@ -228,10 +251,9 @@ def __init__( self._transport = Transport( credentials=credentials, credentials_file=client_options.credentials_file, - host=client_options.api_endpoint, + host=api_endpoint, scopes=client_options.scopes, - api_mtls_endpoint=client_options.api_endpoint, - client_cert_source=client_options.client_cert_source, + ssl_channel_credentials=ssl_credentials, quota_project_id=client_options.quota_project_id, client_info=client_info, ) diff --git a/google/cloud/automl_v1beta1/services/prediction_service/transports/base.py b/google/cloud/automl_v1beta1/services/prediction_service/transports/base.py index bb674eca..04857f4c 100644 --- a/google/cloud/automl_v1beta1/services/prediction_service/transports/base.py +++ b/google/cloud/automl_v1beta1/services/prediction_service/transports/base.py @@ -19,7 +19,7 @@ import typing import pkg_resources -from google import auth +from google import auth # type: ignore from google.api_core import exceptions # type: ignore from google.api_core import gapic_v1 # type: ignore from google.api_core import retry as retries # type: ignore diff --git a/google/cloud/automl_v1beta1/services/prediction_service/transports/grpc.py b/google/cloud/automl_v1beta1/services/prediction_service/transports/grpc.py index 9bc30cdd..3c484247 100644 --- a/google/cloud/automl_v1beta1/services/prediction_service/transports/grpc.py +++ b/google/cloud/automl_v1beta1/services/prediction_service/transports/grpc.py @@ -15,6 +15,7 @@ # limitations under the License. # +import warnings from typing import Callable, Dict, Optional, Sequence, Tuple from google.api_core import grpc_helpers # type: ignore @@ -24,7 +25,6 @@ from google.auth import credentials # type: ignore from google.auth.transport.grpc import SslCredentials # type: ignore - import grpc # type: ignore from google.cloud.automl_v1beta1.types import prediction_service @@ -61,6 +61,7 @@ def __init__( channel: grpc.Channel = None, api_mtls_endpoint: str = None, client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, + ssl_channel_credentials: grpc.ChannelCredentials = None, quota_project_id: Optional[str] = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: @@ -81,14 +82,16 @@ def __init__( ignored if ``channel`` is provided. channel (Optional[grpc.Channel]): A ``Channel`` instance through which to make calls. - api_mtls_endpoint (Optional[str]): The mutual TLS endpoint. If - provided, it overrides the ``host`` argument and tries to create + api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. + If provided, it overrides the ``host`` argument and tries to create a mutual TLS channel with client SSL credentials from ``client_cert_source`` or applicatin default SSL credentials. - client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): A - callback to provide client SSL certificate bytes and private key - bytes, both in PEM format. It is ignored if ``api_mtls_endpoint`` - is None. + client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): + Deprecated. A callback to provide client SSL certificate bytes and + private key bytes, both in PEM format. It is ignored if + ``api_mtls_endpoint`` is None. + ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials + for grpc channel. It is ignored if ``channel`` is provided. quota_project_id (Optional[str]): An optional project to use for billing and quota. client_info (google.api_core.gapic_v1.client_info.ClientInfo): @@ -111,6 +114,11 @@ def __init__( # If a channel was explicitly provided, set it. self._grpc_channel = channel elif api_mtls_endpoint: + warnings.warn( + "api_mtls_endpoint and client_cert_source are deprecated", + DeprecationWarning, + ) + host = ( api_mtls_endpoint if ":" in api_mtls_endpoint @@ -141,6 +149,23 @@ def __init__( scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, ) + else: + host = host if ":" in host else host + ":443" + + if credentials is None: + credentials, _ = auth.default( + scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id + ) + + # create a new channel. The provided one is ignored. + self._grpc_channel = type(self).create_channel( + host, + credentials=credentials, + credentials_file=credentials_file, + ssl_credentials=ssl_channel_credentials, + scopes=scopes or self.AUTH_SCOPES, + quota_project_id=quota_project_id, + ) self._stubs = {} # type: Dict[str, Callable] @@ -206,13 +231,6 @@ def grpc_channel(self) -> grpc.Channel: This property caches on the instance; repeated calls return the same channel. """ - # Sanity check: Only create a new channel if we do not already - # have one. - if not hasattr(self, "_grpc_channel"): - self._grpc_channel = self.create_channel( - self._host, credentials=self._credentials, - ) - # Return the channel from cache. return self._grpc_channel diff --git a/google/cloud/automl_v1beta1/services/prediction_service/transports/grpc_asyncio.py b/google/cloud/automl_v1beta1/services/prediction_service/transports/grpc_asyncio.py index 2c7d9712..0b1bb638 100644 --- a/google/cloud/automl_v1beta1/services/prediction_service/transports/grpc_asyncio.py +++ b/google/cloud/automl_v1beta1/services/prediction_service/transports/grpc_asyncio.py @@ -15,11 +15,13 @@ # limitations under the License. # +import warnings from typing import Awaitable, Callable, Dict, Optional, Sequence, Tuple from google.api_core import gapic_v1 # type: ignore from google.api_core import grpc_helpers_async # type: ignore from google.api_core import operations_v1 # type: ignore +from google import auth # type: ignore from google.auth import credentials # type: ignore from google.auth.transport.grpc import SslCredentials # type: ignore @@ -103,6 +105,7 @@ def __init__( channel: aio.Channel = None, api_mtls_endpoint: str = None, client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, + ssl_channel_credentials: grpc.ChannelCredentials = None, quota_project_id=None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: @@ -124,14 +127,16 @@ def __init__( are passed to :func:`google.auth.default`. channel (Optional[aio.Channel]): A ``Channel`` instance through which to make calls. - api_mtls_endpoint (Optional[str]): The mutual TLS endpoint. If - provided, it overrides the ``host`` argument and tries to create + api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. + If provided, it overrides the ``host`` argument and tries to create a mutual TLS channel with client SSL credentials from ``client_cert_source`` or applicatin default SSL credentials. - client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): A - callback to provide client SSL certificate bytes and private key - bytes, both in PEM format. It is ignored if ``api_mtls_endpoint`` - is None. + client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): + Deprecated. A callback to provide client SSL certificate bytes and + private key bytes, both in PEM format. It is ignored if + ``api_mtls_endpoint`` is None. + ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials + for grpc channel. It is ignored if ``channel`` is provided. quota_project_id (Optional[str]): An optional project to use for billing and quota. client_info (google.api_core.gapic_v1.client_info.ClientInfo): @@ -154,12 +159,22 @@ def __init__( # If a channel was explicitly provided, set it. self._grpc_channel = channel elif api_mtls_endpoint: + warnings.warn( + "api_mtls_endpoint and client_cert_source are deprecated", + DeprecationWarning, + ) + host = ( api_mtls_endpoint if ":" in api_mtls_endpoint else api_mtls_endpoint + ":443" ) + if credentials is None: + credentials, _ = auth.default( + scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id + ) + # Create SSL credentials with client_cert_source or application # default SSL credentials. if client_cert_source: @@ -179,6 +194,23 @@ def __init__( scopes=scopes or self.AUTH_SCOPES, quota_project_id=quota_project_id, ) + else: + host = host if ":" in host else host + ":443" + + if credentials is None: + credentials, _ = auth.default( + scopes=self.AUTH_SCOPES, quota_project_id=quota_project_id + ) + + # create a new channel. The provided one is ignored. + self._grpc_channel = type(self).create_channel( + host, + credentials=credentials, + credentials_file=credentials_file, + ssl_credentials=ssl_channel_credentials, + scopes=scopes or self.AUTH_SCOPES, + quota_project_id=quota_project_id, + ) # Run the base constructor. super().__init__( @@ -199,13 +231,6 @@ def grpc_channel(self) -> aio.Channel: This property caches on the instance; repeated calls return the same channel. """ - # Sanity check: Only create a new channel if we do not already - # have one. - if not hasattr(self, "_grpc_channel"): - self._grpc_channel = self.create_channel( - self._host, credentials=self._credentials, - ) - # Return the channel from cache. return self._grpc_channel diff --git a/google/cloud/automl_v1beta1/types/classification.py b/google/cloud/automl_v1beta1/types/classification.py index 8c879bf2..4b5e5a2a 100644 --- a/google/cloud/automl_v1beta1/types/classification.py +++ b/google/cloud/automl_v1beta1/types/classification.py @@ -60,7 +60,7 @@ class VideoClassificationAnnotation(proto.Message): r"""Contains annotation details specific to video classification. Attributes: - type (str): + type_ (str): Output only. Expresses the type of video classification. Possible values: @@ -96,7 +96,7 @@ class VideoClassificationAnnotation(proto.Message): to which the annotation applies. """ - type = proto.Field(proto.STRING, number=1) + type_ = proto.Field(proto.STRING, number=1) classification_annotation = proto.Field( proto.MESSAGE, number=2, message=ClassificationAnnotation, diff --git a/google/cloud/automl_v1beta1/types/data_stats.py b/google/cloud/automl_v1beta1/types/data_stats.py index 4ae40fc8..4405185f 100644 --- a/google/cloud/automl_v1beta1/types/data_stats.py +++ b/google/cloud/automl_v1beta1/types/data_stats.py @@ -115,9 +115,9 @@ class HistogramBucket(proto.Message): r"""A bucket of a histogram. Attributes: - min (float): + min_ (float): The minimum value of the bucket, inclusive. - max (float): + max_ (float): The maximum value of the bucket, exclusive unless max = ``"Infinity"``, in which case it's inclusive. count (int): @@ -125,9 +125,9 @@ class HistogramBucket(proto.Message): bucket, i.e. are between min and max values. """ - min = proto.Field(proto.DOUBLE, number=1) + min_ = proto.Field(proto.DOUBLE, number=1) - max = proto.Field(proto.DOUBLE, number=2) + max_ = proto.Field(proto.DOUBLE, number=2) count = proto.Field(proto.INT64, number=3) diff --git a/google/cloud/automl_v1beta1/types/io.py b/google/cloud/automl_v1beta1/types/io.py index bb91b204..5be23eb2 100644 --- a/google/cloud/automl_v1beta1/types/io.py +++ b/google/cloud/automl_v1beta1/types/io.py @@ -944,20 +944,39 @@ class ModelExportOutputConfig(proto.Message): - For Image Classification mobile-core-ml-low-latency-1, mobile-core-ml-versatile-1, mobile-core-ml-high-accuracy-1: "core_ml" (default). - Formats description: - - tflite - Used for Android mobile devices. + - For Image Object Detection mobile-low-latency-1, + mobile-versatile-1, mobile-high-accuracy-1: "tflite", + "tf_saved_model", "tf_js". + + - For Video Classification cloud, "tf_saved_model". + + - For Video Object Tracking cloud, "tf_saved_model". + + - For Video Object Tracking mobile-versatile-1: "tflite", + "edgetpu_tflite", "tf_saved_model", "docker". + + - For Video Object Tracking mobile-coral-versatile-1: + "tflite", "edgetpu_tflite", "docker". + + - For Video Object Tracking mobile-coral-low-latency-1: + "tflite", "edgetpu_tflite", "docker". + + - For Video Object Tracking mobile-jetson-versatile-1: + "tf_saved_model", "docker". + - For Tables: "docker". + + Formats description: + + - tflite - Used for Android mobile devices. - edgetpu_tflite - Used for `Edge TPU `__ devices. - - tf_saved_model - A tensorflow model in SavedModel format. - - tf_js - A `TensorFlow.js `__ model that can be used in the browser and in Node.js using JavaScript. - - docker - Used for Docker containers. Use the params field to customize the container. The container is verified to work correctly on ubuntu 16.04 operating system. See more diff --git a/google/cloud/automl_v1beta1/types/text.py b/google/cloud/automl_v1beta1/types/text.py index 8ecd3869..bc2b888c 100644 --- a/google/cloud/automl_v1beta1/types/text.py +++ b/google/cloud/automl_v1beta1/types/text.py @@ -66,7 +66,20 @@ class TextExtractionDatasetMetadata(proto.Message): class TextExtractionModelMetadata(proto.Message): - r"""Model metadata that is specific to text extraction.""" + r"""Model metadata that is specific to text extraction. + + Attributes: + model_hint (str): + Indicates the scope of model use case. + + - ``default``: Use to train a general text extraction + model. Default value. + + - ``health_care``: Use to train a text extraction model + that is tuned for healthcare applications. + """ + + model_hint = proto.Field(proto.STRING, number=3) class TextSentimentDatasetMetadata(proto.Message): diff --git a/noxfile.py b/noxfile.py index 9c69b3b7..709afdde 100644 --- a/noxfile.py +++ b/noxfile.py @@ -74,7 +74,6 @@ def default(session): session.install("mock", "pytest", "pytest-cov") session.install("-e", ".[pandas,storage]") - session.install("proto-plus==1.8.1") # Run py.test against the unit tests. session.run( @@ -199,36 +198,3 @@ def docfx(session): os.path.join("docs", ""), os.path.join("docs", "_build", "html", ""), ) - - -@nox.session(python=DEFAULT_PYTHON_VERSION) -def docfx(session): - """Build the docfx yaml files for this library.""" - - session.install("-e", ".[pandas,storage]") - session.install("sphinx<3.0.0", "alabaster", "recommonmark", "sphinx-docfx-yaml") - - shutil.rmtree(os.path.join("docs", "_build"), ignore_errors=True) - session.run( - "sphinx-build", - "-T", # show full traceback on exception - "-N", # no colors - "-D", - ( - "extensions=sphinx.ext.autodoc," - "sphinx.ext.autosummary," - "docfx_yaml.extension," - "sphinx.ext.intersphinx," - "sphinx.ext.coverage," - "sphinx.ext.napoleon," - "sphinx.ext.todo," - "sphinx.ext.viewcode," - "recommonmark" - ), - "-b", - "html", - "-d", - os.path.join("docs", "_build", "doctrees", ""), - os.path.join("docs", ""), - os.path.join("docs", "_build", "html", ""), - ) diff --git a/setup.py b/setup.py index d9a7b069..6c0ad166 100644 --- a/setup.py +++ b/setup.py @@ -23,7 +23,7 @@ release_status = "Development Status :: 5 - Production/Stable" dependencies = [ "google-api-core[grpc] >= 1.22.0, < 2.0.0dev", - "proto-plus >= 1.4.0", + "proto-plus >= 1.10.0", "libcst >= 0.2.5", ] extras = { diff --git a/synth.metadata b/synth.metadata index 6c3bc216..fe27c523 100644 --- a/synth.metadata +++ b/synth.metadata @@ -3,16 +3,16 @@ { "git": { "name": ".", - "remote": "git@github.com:googleapis/python-automl", - "sha": "9b218b1f1cd0caef664e51064baf5f4af07a97c1" + "remote": "https://github.com/googleapis/python-automl.git", + "sha": "8c7d54872a6e5628171f160e1a39a067d5f46563" } }, { "git": { "name": "googleapis", "remote": "https://github.com/googleapis/googleapis.git", - "sha": "17de2b31f9450385e739bedeeaac6e1ec4f239a8", - "internalRef": "327504150" + "sha": "20b11dfe4538cd5da7b4c3dd7d2bf5b9922ff3ed", + "internalRef": "338646463" } }, { @@ -49,5 +49,221 @@ "generator": "bazel" } } + ], + "generatedFiles": [ + ".coveragerc", + ".flake8", + ".github/CONTRIBUTING.md", + ".github/ISSUE_TEMPLATE/bug_report.md", + ".github/ISSUE_TEMPLATE/feature_request.md", + ".github/ISSUE_TEMPLATE/support_request.md", + ".github/PULL_REQUEST_TEMPLATE.md", + ".github/release-please.yml", + ".gitignore", + ".kokoro/build.sh", + ".kokoro/continuous/common.cfg", + ".kokoro/continuous/continuous.cfg", + ".kokoro/docker/docs/Dockerfile", + ".kokoro/docker/docs/fetch_gpg_keys.sh", + ".kokoro/docs/common.cfg", + ".kokoro/docs/docs-presubmit.cfg", + ".kokoro/docs/docs.cfg", + ".kokoro/presubmit/common.cfg", + ".kokoro/presubmit/presubmit.cfg", + ".kokoro/publish-docs.sh", + ".kokoro/release.sh", + ".kokoro/release/common.cfg", + ".kokoro/release/release.cfg", + ".kokoro/samples/lint/common.cfg", + ".kokoro/samples/lint/continuous.cfg", + ".kokoro/samples/lint/periodic.cfg", + ".kokoro/samples/lint/presubmit.cfg", + ".kokoro/samples/python3.6/common.cfg", + ".kokoro/samples/python3.6/continuous.cfg", + ".kokoro/samples/python3.6/periodic.cfg", + ".kokoro/samples/python3.6/presubmit.cfg", + ".kokoro/samples/python3.7/common.cfg", + ".kokoro/samples/python3.7/continuous.cfg", + ".kokoro/samples/python3.7/periodic.cfg", + ".kokoro/samples/python3.7/presubmit.cfg", + ".kokoro/samples/python3.8/common.cfg", + ".kokoro/samples/python3.8/continuous.cfg", + ".kokoro/samples/python3.8/periodic.cfg", + ".kokoro/samples/python3.8/presubmit.cfg", + ".kokoro/test-samples.sh", + ".kokoro/trampoline.sh", + ".kokoro/trampoline_v2.sh", + ".trampolinerc", + "CODE_OF_CONDUCT.md", + "CONTRIBUTING.rst", + "LICENSE", + "MANIFEST.in", + "docs/_static/custom.css", + "docs/_templates/layout.html", + "docs/automl_v1/services.rst", + "docs/automl_v1/types.rst", + "docs/automl_v1beta1/services.rst", + "docs/automl_v1beta1/types.rst", + "docs/conf.py", + "docs/multiprocessing.rst", + "google/cloud/automl/__init__.py", + "google/cloud/automl/py.typed", + "google/cloud/automl_v1/__init__.py", + "google/cloud/automl_v1/proto/annotation_payload.proto", + "google/cloud/automl_v1/proto/annotation_spec.proto", + "google/cloud/automl_v1/proto/classification.proto", + "google/cloud/automl_v1/proto/data_items.proto", + "google/cloud/automl_v1/proto/dataset.proto", + "google/cloud/automl_v1/proto/detection.proto", + "google/cloud/automl_v1/proto/geometry.proto", + "google/cloud/automl_v1/proto/image.proto", + "google/cloud/automl_v1/proto/io.proto", + "google/cloud/automl_v1/proto/model.proto", + "google/cloud/automl_v1/proto/model_evaluation.proto", + "google/cloud/automl_v1/proto/operations.proto", + "google/cloud/automl_v1/proto/prediction_service.proto", + "google/cloud/automl_v1/proto/service.proto", + "google/cloud/automl_v1/proto/text.proto", + "google/cloud/automl_v1/proto/text_extraction.proto", + "google/cloud/automl_v1/proto/text_segment.proto", + "google/cloud/automl_v1/proto/text_sentiment.proto", + "google/cloud/automl_v1/proto/translation.proto", + "google/cloud/automl_v1/py.typed", + "google/cloud/automl_v1/services/__init__.py", + "google/cloud/automl_v1/services/auto_ml/__init__.py", + "google/cloud/automl_v1/services/auto_ml/async_client.py", + "google/cloud/automl_v1/services/auto_ml/client.py", + "google/cloud/automl_v1/services/auto_ml/pagers.py", + "google/cloud/automl_v1/services/auto_ml/transports/__init__.py", + "google/cloud/automl_v1/services/auto_ml/transports/base.py", + "google/cloud/automl_v1/services/auto_ml/transports/grpc.py", + "google/cloud/automl_v1/services/auto_ml/transports/grpc_asyncio.py", + "google/cloud/automl_v1/services/prediction_service/__init__.py", + "google/cloud/automl_v1/services/prediction_service/async_client.py", + "google/cloud/automl_v1/services/prediction_service/client.py", + "google/cloud/automl_v1/services/prediction_service/transports/__init__.py", + "google/cloud/automl_v1/services/prediction_service/transports/base.py", + "google/cloud/automl_v1/services/prediction_service/transports/grpc.py", + "google/cloud/automl_v1/services/prediction_service/transports/grpc_asyncio.py", + "google/cloud/automl_v1/types/__init__.py", + "google/cloud/automl_v1/types/annotation_payload.py", + "google/cloud/automl_v1/types/annotation_spec.py", + "google/cloud/automl_v1/types/classification.py", + "google/cloud/automl_v1/types/data_items.py", + "google/cloud/automl_v1/types/dataset.py", + "google/cloud/automl_v1/types/detection.py", + "google/cloud/automl_v1/types/geometry.py", + "google/cloud/automl_v1/types/image.py", + "google/cloud/automl_v1/types/io.py", + "google/cloud/automl_v1/types/model.py", + "google/cloud/automl_v1/types/model_evaluation.py", + "google/cloud/automl_v1/types/operations.py", + "google/cloud/automl_v1/types/prediction_service.py", + "google/cloud/automl_v1/types/service.py", + "google/cloud/automl_v1/types/text.py", + "google/cloud/automl_v1/types/text_extraction.py", + "google/cloud/automl_v1/types/text_segment.py", + "google/cloud/automl_v1/types/text_sentiment.py", + "google/cloud/automl_v1/types/translation.py", + "google/cloud/automl_v1beta1/__init__.py", + "google/cloud/automl_v1beta1/proto/annotation_payload.proto", + "google/cloud/automl_v1beta1/proto/annotation_spec.proto", + "google/cloud/automl_v1beta1/proto/classification.proto", + "google/cloud/automl_v1beta1/proto/column_spec.proto", + "google/cloud/automl_v1beta1/proto/data_items.proto", + "google/cloud/automl_v1beta1/proto/data_stats.proto", + "google/cloud/automl_v1beta1/proto/data_types.proto", + "google/cloud/automl_v1beta1/proto/dataset.proto", + "google/cloud/automl_v1beta1/proto/detection.proto", + "google/cloud/automl_v1beta1/proto/geometry.proto", + "google/cloud/automl_v1beta1/proto/image.proto", + "google/cloud/automl_v1beta1/proto/io.proto", + "google/cloud/automl_v1beta1/proto/model.proto", + "google/cloud/automl_v1beta1/proto/model_evaluation.proto", + "google/cloud/automl_v1beta1/proto/operations.proto", + "google/cloud/automl_v1beta1/proto/prediction_service.proto", + "google/cloud/automl_v1beta1/proto/ranges.proto", + "google/cloud/automl_v1beta1/proto/regression.proto", + "google/cloud/automl_v1beta1/proto/service.proto", + "google/cloud/automl_v1beta1/proto/table_spec.proto", + "google/cloud/automl_v1beta1/proto/tables.proto", + "google/cloud/automl_v1beta1/proto/temporal.proto", + "google/cloud/automl_v1beta1/proto/text.proto", + "google/cloud/automl_v1beta1/proto/text_extraction.proto", + "google/cloud/automl_v1beta1/proto/text_segment.proto", + "google/cloud/automl_v1beta1/proto/text_sentiment.proto", + "google/cloud/automl_v1beta1/proto/translation.proto", + "google/cloud/automl_v1beta1/proto/video.proto", + "google/cloud/automl_v1beta1/py.typed", + "google/cloud/automl_v1beta1/services/__init__.py", + "google/cloud/automl_v1beta1/services/auto_ml/__init__.py", + "google/cloud/automl_v1beta1/services/auto_ml/async_client.py", + "google/cloud/automl_v1beta1/services/auto_ml/client.py", + "google/cloud/automl_v1beta1/services/auto_ml/pagers.py", + "google/cloud/automl_v1beta1/services/auto_ml/transports/__init__.py", + "google/cloud/automl_v1beta1/services/auto_ml/transports/base.py", + "google/cloud/automl_v1beta1/services/auto_ml/transports/grpc.py", + "google/cloud/automl_v1beta1/services/auto_ml/transports/grpc_asyncio.py", + "google/cloud/automl_v1beta1/services/prediction_service/__init__.py", + "google/cloud/automl_v1beta1/services/prediction_service/async_client.py", + "google/cloud/automl_v1beta1/services/prediction_service/client.py", + "google/cloud/automl_v1beta1/services/prediction_service/transports/__init__.py", + "google/cloud/automl_v1beta1/services/prediction_service/transports/base.py", + "google/cloud/automl_v1beta1/services/prediction_service/transports/grpc.py", + "google/cloud/automl_v1beta1/services/prediction_service/transports/grpc_asyncio.py", + "google/cloud/automl_v1beta1/types/__init__.py", + "google/cloud/automl_v1beta1/types/annotation_payload.py", + "google/cloud/automl_v1beta1/types/annotation_spec.py", + "google/cloud/automl_v1beta1/types/classification.py", + "google/cloud/automl_v1beta1/types/column_spec.py", + "google/cloud/automl_v1beta1/types/data_items.py", + "google/cloud/automl_v1beta1/types/data_stats.py", + "google/cloud/automl_v1beta1/types/data_types.py", + "google/cloud/automl_v1beta1/types/dataset.py", + "google/cloud/automl_v1beta1/types/detection.py", + "google/cloud/automl_v1beta1/types/geometry.py", + "google/cloud/automl_v1beta1/types/image.py", + "google/cloud/automl_v1beta1/types/io.py", + "google/cloud/automl_v1beta1/types/model.py", + "google/cloud/automl_v1beta1/types/model_evaluation.py", + "google/cloud/automl_v1beta1/types/operations.py", + "google/cloud/automl_v1beta1/types/prediction_service.py", + "google/cloud/automl_v1beta1/types/ranges.py", + "google/cloud/automl_v1beta1/types/regression.py", + "google/cloud/automl_v1beta1/types/service.py", + "google/cloud/automl_v1beta1/types/table_spec.py", + "google/cloud/automl_v1beta1/types/tables.py", + "google/cloud/automl_v1beta1/types/temporal.py", + "google/cloud/automl_v1beta1/types/text.py", + "google/cloud/automl_v1beta1/types/text_extraction.py", + "google/cloud/automl_v1beta1/types/text_segment.py", + "google/cloud/automl_v1beta1/types/text_sentiment.py", + "google/cloud/automl_v1beta1/types/translation.py", + "google/cloud/automl_v1beta1/types/video.py", + "mypy.ini", + "noxfile.py", + "renovate.json", + "samples/AUTHORING_GUIDE.md", + "samples/CONTRIBUTING.md", + "samples/beta/noxfile.py", + "samples/snippets/noxfile.py", + "samples/tables/noxfile.py", + "scripts/decrypt-secrets.sh", + "scripts/fixup_automl_v1_keywords.py", + "scripts/fixup_automl_v1beta1_keywords.py", + "scripts/readme-gen/readme_gen.py", + "scripts/readme-gen/templates/README.tmpl.rst", + "scripts/readme-gen/templates/auth.tmpl.rst", + "scripts/readme-gen/templates/auth_api_key.tmpl.rst", + "scripts/readme-gen/templates/install_deps.tmpl.rst", + "scripts/readme-gen/templates/install_portaudio.tmpl.rst", + "setup.cfg", + "testing/.gitignore", + "tests/unit/gapic/automl_v1/__init__.py", + "tests/unit/gapic/automl_v1/test_auto_ml.py", + "tests/unit/gapic/automl_v1/test_prediction_service.py", + "tests/unit/gapic/automl_v1beta1/__init__.py", + "tests/unit/gapic/automl_v1beta1/test_auto_ml.py", + "tests/unit/gapic/automl_v1beta1/test_prediction_service.py" ] } \ No newline at end of file diff --git a/synth.py b/synth.py index 017d2a67..638228ec 100644 --- a/synth.py +++ b/synth.py @@ -46,8 +46,8 @@ from \.services\.prediction_service import PredictionServiceClient""", """from .services.auto_ml import AutoMlClient from .services.prediction_service import PredictionServiceClient -from .tables.gcs_client import GcsClient -from .tables.tables_client import TablesClient""" +from .services.tables.gcs_client import GcsClient +from .services.tables.tables_client import TablesClient""" ) s.replace( @@ -56,6 +56,15 @@ """__all__ = ("GcsClient", "TablesClient",""" ) +s.replace( + "docs/automl_v1beta1/services.rst", + """(google\.cloud\.automl_v1beta1\.services\.prediction_service + :members: + :inherited-members:)""", + """\g<1>\n.. automodule:: google.cloud.automl_v1beta1.services.tables + :members: + :inherited-members:""" +) # ---------------------------------------------------------------------------- # Add templated files diff --git a/tests/unit/gapic/automl_v1/test_auto_ml.py b/tests/unit/gapic/automl_v1/test_auto_ml.py index 42ad394e..a11480cd 100644 --- a/tests/unit/gapic/automl_v1/test_auto_ml.py +++ b/tests/unit/gapic/automl_v1/test_auto_ml.py @@ -31,7 +31,7 @@ from google.api_core import gapic_v1 from google.api_core import grpc_helpers from google.api_core import grpc_helpers_async -from google.api_core import operation_async +from google.api_core import operation_async # type: ignore from google.api_core import operations_v1 from google.auth import credentials from google.auth.exceptions import MutualTLSChannelError @@ -158,15 +158,14 @@ def test_auto_ml_client_client_options(client_class, transport_class, transport_ credentials_file=None, host="squid.clam.whelk", scopes=None, - api_mtls_endpoint="squid.clam.whelk", - client_cert_source=None, + ssl_channel_credentials=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) - # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS is + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT is # "never". - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS": "never"}): + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}): with mock.patch.object(transport_class, "__init__") as patched: patched.return_value = None client = client_class() @@ -175,15 +174,14 @@ def test_auto_ml_client_client_options(client_class, transport_class, transport_ credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=None, - api_mtls_endpoint=client.DEFAULT_ENDPOINT, - client_cert_source=None, + ssl_channel_credentials=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) - # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS is + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT is # "always". - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS": "always"}): + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}): with mock.patch.object(transport_class, "__init__") as patched: patched.return_value = None client = client_class() @@ -192,95 +190,171 @@ def test_auto_ml_client_client_options(client_class, transport_class, transport_ credentials_file=None, host=client.DEFAULT_MTLS_ENDPOINT, scopes=None, - api_mtls_endpoint=client.DEFAULT_MTLS_ENDPOINT, - client_cert_source=None, + ssl_channel_credentials=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) - # Check the case api_endpoint is not provided, GOOGLE_API_USE_MTLS is - # "auto", and client_cert_source is provided. - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS": "auto"}): + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT has + # unsupported value. + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "Unsupported"}): + with pytest.raises(MutualTLSChannelError): + client = client_class() + + # Check the case GOOGLE_API_USE_CLIENT_CERTIFICATE has unsupported value. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"} + ): + with pytest.raises(ValueError): + client = client_class() + + # Check the case quota_project_id is provided + options = client_options.ClientOptions(quota_project_id="octopus") + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(client_options=options) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=None, + ssl_channel_credentials=None, + quota_project_id="octopus", + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) + + +@pytest.mark.parametrize( + "client_class,transport_class,transport_name,use_client_cert_env", + [ + (AutoMlClient, transports.AutoMlGrpcTransport, "grpc", "true"), + ( + AutoMlAsyncClient, + transports.AutoMlGrpcAsyncIOTransport, + "grpc_asyncio", + "true", + ), + (AutoMlClient, transports.AutoMlGrpcTransport, "grpc", "false"), + ( + AutoMlAsyncClient, + transports.AutoMlGrpcAsyncIOTransport, + "grpc_asyncio", + "false", + ), + ], +) +@mock.patch.object( + AutoMlClient, "DEFAULT_ENDPOINT", modify_default_endpoint(AutoMlClient) +) +@mock.patch.object( + AutoMlAsyncClient, "DEFAULT_ENDPOINT", modify_default_endpoint(AutoMlAsyncClient) +) +@mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "auto"}) +def test_auto_ml_client_mtls_env_auto( + client_class, transport_class, transport_name, use_client_cert_env +): + # This tests the endpoint autoswitch behavior. Endpoint is autoswitched to the default + # mtls endpoint, if GOOGLE_API_USE_CLIENT_CERTIFICATE is "true" and client cert exists. + + # Check the case client_cert_source is provided. Whether client cert is used depends on + # GOOGLE_API_USE_CLIENT_CERTIFICATE value. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env} + ): options = client_options.ClientOptions( client_cert_source=client_cert_source_callback ) with mock.patch.object(transport_class, "__init__") as patched: - patched.return_value = None - client = client_class(client_options=options) - patched.assert_called_once_with( - credentials=None, - credentials_file=None, - host=client.DEFAULT_MTLS_ENDPOINT, - scopes=None, - api_mtls_endpoint=client.DEFAULT_MTLS_ENDPOINT, - client_cert_source=client_cert_source_callback, - quota_project_id=None, - client_info=transports.base.DEFAULT_CLIENT_INFO, - ) - - # Check the case api_endpoint is not provided, GOOGLE_API_USE_MTLS is - # "auto", and default_client_cert_source is provided. - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS": "auto"}): - with mock.patch.object(transport_class, "__init__") as patched: + ssl_channel_creds = mock.Mock() with mock.patch( - "google.auth.transport.mtls.has_default_client_cert_source", - return_value=True, + "grpc.ssl_channel_credentials", return_value=ssl_channel_creds ): patched.return_value = None - client = client_class() + client = client_class(client_options=options) + + if use_client_cert_env == "false": + expected_ssl_channel_creds = None + expected_host = client.DEFAULT_ENDPOINT + else: + expected_ssl_channel_creds = ssl_channel_creds + expected_host = client.DEFAULT_MTLS_ENDPOINT + patched.assert_called_once_with( credentials=None, credentials_file=None, - host=client.DEFAULT_MTLS_ENDPOINT, + host=expected_host, scopes=None, - api_mtls_endpoint=client.DEFAULT_MTLS_ENDPOINT, - client_cert_source=None, + ssl_channel_credentials=expected_ssl_channel_creds, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) - # Check the case api_endpoint is not provided, GOOGLE_API_USE_MTLS is - # "auto", but client_cert_source and default_client_cert_source are None. - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS": "auto"}): + # Check the case ADC client cert is provided. Whether client cert is used depends on + # GOOGLE_API_USE_CLIENT_CERTIFICATE value. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env} + ): with mock.patch.object(transport_class, "__init__") as patched: with mock.patch( - "google.auth.transport.mtls.has_default_client_cert_source", - return_value=False, + "google.auth.transport.grpc.SslCredentials.__init__", return_value=None ): - patched.return_value = None - client = client_class() - patched.assert_called_once_with( - credentials=None, - credentials_file=None, - host=client.DEFAULT_ENDPOINT, - scopes=None, - api_mtls_endpoint=client.DEFAULT_ENDPOINT, - client_cert_source=None, - quota_project_id=None, - client_info=transports.base.DEFAULT_CLIENT_INFO, - ) - - # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS has - # unsupported value. - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS": "Unsupported"}): - with pytest.raises(MutualTLSChannelError): - client = client_class() - - # Check the case quota_project_id is provided - options = client_options.ClientOptions(quota_project_id="octopus") - with mock.patch.object(transport_class, "__init__") as patched: - patched.return_value = None - client = client_class(client_options=options) - patched.assert_called_once_with( - credentials=None, - credentials_file=None, - host=client.DEFAULT_ENDPOINT, - scopes=None, - api_mtls_endpoint=client.DEFAULT_ENDPOINT, - client_cert_source=None, - quota_project_id="octopus", - client_info=transports.base.DEFAULT_CLIENT_INFO, - ) + with mock.patch( + "google.auth.transport.grpc.SslCredentials.is_mtls", + new_callable=mock.PropertyMock, + ) as is_mtls_mock: + with mock.patch( + "google.auth.transport.grpc.SslCredentials.ssl_credentials", + new_callable=mock.PropertyMock, + ) as ssl_credentials_mock: + if use_client_cert_env == "false": + is_mtls_mock.return_value = False + ssl_credentials_mock.return_value = None + expected_host = client.DEFAULT_ENDPOINT + expected_ssl_channel_creds = None + else: + is_mtls_mock.return_value = True + ssl_credentials_mock.return_value = mock.Mock() + expected_host = client.DEFAULT_MTLS_ENDPOINT + expected_ssl_channel_creds = ( + ssl_credentials_mock.return_value + ) + + patched.return_value = None + client = client_class() + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=expected_host, + scopes=None, + ssl_channel_credentials=expected_ssl_channel_creds, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) + + # Check the case client_cert_source and ADC client cert are not provided. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env} + ): + with mock.patch.object(transport_class, "__init__") as patched: + with mock.patch( + "google.auth.transport.grpc.SslCredentials.__init__", return_value=None + ): + with mock.patch( + "google.auth.transport.grpc.SslCredentials.is_mtls", + new_callable=mock.PropertyMock, + ) as is_mtls_mock: + is_mtls_mock.return_value = False + patched.return_value = None + client = client_class() + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=None, + ssl_channel_credentials=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) @pytest.mark.parametrize( @@ -303,8 +377,7 @@ def test_auto_ml_client_client_options_scopes( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=["1", "2"], - api_mtls_endpoint=client.DEFAULT_ENDPOINT, - client_cert_source=None, + ssl_channel_credentials=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -330,8 +403,7 @@ def test_auto_ml_client_client_options_credentials_file( credentials_file="credentials.json", host=client.DEFAULT_ENDPOINT, scopes=None, - api_mtls_endpoint=client.DEFAULT_ENDPOINT, - client_cert_source=None, + ssl_channel_credentials=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -348,8 +420,7 @@ def test_auto_ml_client_client_options_from_dict(): credentials_file=None, host="squid.clam.whelk", scopes=None, - api_mtls_endpoint="squid.clam.whelk", - client_cert_source=None, + ssl_channel_credentials=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -1038,8 +1109,8 @@ def test_list_datasets_pages(): RuntimeError, ) pages = list(client.list_datasets(request={}).pages) - for page, token in zip(pages, ["abc", "def", "ghi", ""]): - assert page.raw_page.next_page_token == token + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token @pytest.mark.asyncio @@ -1103,10 +1174,10 @@ async def test_list_datasets_async_pages(): RuntimeError, ) pages = [] - async for page in (await client.list_datasets(request={})).pages: - pages.append(page) - for page, token in zip(pages, ["abc", "def", "ghi", ""]): - assert page.raw_page.next_page_token == token + async for page_ in (await client.list_datasets(request={})).pages: + pages.append(page_) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token def test_update_dataset( @@ -2862,8 +2933,8 @@ def test_list_models_pages(): RuntimeError, ) pages = list(client.list_models(request={}).pages) - for page, token in zip(pages, ["abc", "def", "ghi", ""]): - assert page.raw_page.next_page_token == token + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token @pytest.mark.asyncio @@ -2919,10 +2990,10 @@ async def test_list_models_async_pages(): RuntimeError, ) pages = [] - async for page in (await client.list_models(request={})).pages: - pages.append(page) - for page, token in zip(pages, ["abc", "def", "ghi", ""]): - assert page.raw_page.next_page_token == token + async for page_ in (await client.list_models(request={})).pages: + pages.append(page_) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token def test_delete_model(transport: str = "grpc", request_type=service.DeleteModelRequest): @@ -4459,8 +4530,8 @@ def test_list_model_evaluations_pages(): RuntimeError, ) pages = list(client.list_model_evaluations(request={}).pages) - for page, token in zip(pages, ["abc", "def", "ghi", ""]): - assert page.raw_page.next_page_token == token + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token @pytest.mark.asyncio @@ -4544,10 +4615,10 @@ async def test_list_model_evaluations_async_pages(): RuntimeError, ) pages = [] - async for page in (await client.list_model_evaluations(request={})).pages: - pages.append(page) - for page, token in zip(pages, ["abc", "def", "ghi", ""]): - assert page.raw_page.next_page_token == token + async for page_ in (await client.list_model_evaluations(request={})).pages: + pages.append(page_) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token def test_credentials_transport_error(): @@ -4604,6 +4675,18 @@ def test_transport_get_channel(): assert channel +@pytest.mark.parametrize( + "transport_class", + [transports.AutoMlGrpcTransport, transports.AutoMlGrpcAsyncIOTransport], +) +def test_transport_adc(transport_class): + # Test default credentials are used if not provided. + with mock.patch.object(auth, "default") as adc: + adc.return_value = (credentials.AnonymousCredentials(), None) + transport_class() + adc.assert_called_once() + + def test_transport_grpc_default(): # A client should use the gRPC transport by default. client = AutoMlClient(credentials=credentials.AnonymousCredentials(),) @@ -4680,6 +4763,17 @@ def test_auto_ml_base_transport_with_credentials_file(): ) +def test_auto_ml_base_transport_with_adc(): + # Test the default credentials are used if credentials and credentials_file are None. + with mock.patch.object(auth, "default") as adc, mock.patch( + "google.cloud.automl_v1.services.auto_ml.transports.AutoMlTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + adc.return_value = (credentials.AnonymousCredentials(), None) + transport = transports.AutoMlTransport() + adc.assert_called_once() + + def test_auto_ml_auth_adc(): # If no credentials are provided, we should use ADC credentials. with mock.patch.object(auth, "default") as adc: @@ -4728,179 +4822,102 @@ def test_auto_ml_host_with_port(): def test_auto_ml_grpc_transport_channel(): channel = grpc.insecure_channel("http://localhost/") - # Check that if channel is provided, mtls endpoint and client_cert_source - # won't be used. - callback = mock.MagicMock() + # Check that channel is used if provided. transport = transports.AutoMlGrpcTransport( - host="squid.clam.whelk", - channel=channel, - api_mtls_endpoint="mtls.squid.clam.whelk", - client_cert_source=callback, + host="squid.clam.whelk", channel=channel, ) assert transport.grpc_channel == channel assert transport._host == "squid.clam.whelk:443" - assert not callback.called def test_auto_ml_grpc_asyncio_transport_channel(): channel = aio.insecure_channel("http://localhost/") - # Check that if channel is provided, mtls endpoint and client_cert_source - # won't be used. - callback = mock.MagicMock() + # Check that channel is used if provided. transport = transports.AutoMlGrpcAsyncIOTransport( - host="squid.clam.whelk", - channel=channel, - api_mtls_endpoint="mtls.squid.clam.whelk", - client_cert_source=callback, + host="squid.clam.whelk", channel=channel, ) assert transport.grpc_channel == channel assert transport._host == "squid.clam.whelk:443" - assert not callback.called - - -@mock.patch("grpc.ssl_channel_credentials", autospec=True) -@mock.patch("google.api_core.grpc_helpers.create_channel", autospec=True) -def test_auto_ml_grpc_transport_channel_mtls_with_client_cert_source( - grpc_create_channel, grpc_ssl_channel_cred -): - # Check that if channel is None, but api_mtls_endpoint and client_cert_source - # are provided, then a mTLS channel will be created. - mock_cred = mock.Mock() - - mock_ssl_cred = mock.Mock() - grpc_ssl_channel_cred.return_value = mock_ssl_cred - - mock_grpc_channel = mock.Mock() - grpc_create_channel.return_value = mock_grpc_channel - - transport = transports.AutoMlGrpcTransport( - host="squid.clam.whelk", - credentials=mock_cred, - api_mtls_endpoint="mtls.squid.clam.whelk", - client_cert_source=client_cert_source_callback, - ) - grpc_ssl_channel_cred.assert_called_once_with( - certificate_chain=b"cert bytes", private_key=b"key bytes" - ) - grpc_create_channel.assert_called_once_with( - "mtls.squid.clam.whelk:443", - credentials=mock_cred, - credentials_file=None, - scopes=("https://www.googleapis.com/auth/cloud-platform",), - ssl_credentials=mock_ssl_cred, - quota_project_id=None, - ) - assert transport.grpc_channel == mock_grpc_channel - - -@mock.patch("grpc.ssl_channel_credentials", autospec=True) -@mock.patch("google.api_core.grpc_helpers_async.create_channel", autospec=True) -def test_auto_ml_grpc_asyncio_transport_channel_mtls_with_client_cert_source( - grpc_create_channel, grpc_ssl_channel_cred -): - # Check that if channel is None, but api_mtls_endpoint and client_cert_source - # are provided, then a mTLS channel will be created. - mock_cred = mock.Mock() - - mock_ssl_cred = mock.Mock() - grpc_ssl_channel_cred.return_value = mock_ssl_cred - - mock_grpc_channel = mock.Mock() - grpc_create_channel.return_value = mock_grpc_channel - - transport = transports.AutoMlGrpcAsyncIOTransport( - host="squid.clam.whelk", - credentials=mock_cred, - api_mtls_endpoint="mtls.squid.clam.whelk", - client_cert_source=client_cert_source_callback, - ) - grpc_ssl_channel_cred.assert_called_once_with( - certificate_chain=b"cert bytes", private_key=b"key bytes" - ) - grpc_create_channel.assert_called_once_with( - "mtls.squid.clam.whelk:443", - credentials=mock_cred, - credentials_file=None, - scopes=("https://www.googleapis.com/auth/cloud-platform",), - ssl_credentials=mock_ssl_cred, - quota_project_id=None, - ) - assert transport.grpc_channel == mock_grpc_channel @pytest.mark.parametrize( - "api_mtls_endpoint", ["mtls.squid.clam.whelk", "mtls.squid.clam.whelk:443"] + "transport_class", + [transports.AutoMlGrpcTransport, transports.AutoMlGrpcAsyncIOTransport], ) -@mock.patch("google.api_core.grpc_helpers.create_channel", autospec=True) -def test_auto_ml_grpc_transport_channel_mtls_with_adc( - grpc_create_channel, api_mtls_endpoint -): - # Check that if channel and client_cert_source are None, but api_mtls_endpoint - # is provided, then a mTLS channel will be created with SSL ADC. - mock_grpc_channel = mock.Mock() - grpc_create_channel.return_value = mock_grpc_channel - - # Mock google.auth.transport.grpc.SslCredentials class. - mock_ssl_cred = mock.Mock() - with mock.patch.multiple( - "google.auth.transport.grpc.SslCredentials", - __init__=mock.Mock(return_value=None), - ssl_credentials=mock.PropertyMock(return_value=mock_ssl_cred), - ): - mock_cred = mock.Mock() - transport = transports.AutoMlGrpcTransport( - host="squid.clam.whelk", - credentials=mock_cred, - api_mtls_endpoint=api_mtls_endpoint, - client_cert_source=None, - ) - grpc_create_channel.assert_called_once_with( - "mtls.squid.clam.whelk:443", - credentials=mock_cred, - credentials_file=None, - scopes=("https://www.googleapis.com/auth/cloud-platform",), - ssl_credentials=mock_ssl_cred, - quota_project_id=None, - ) - assert transport.grpc_channel == mock_grpc_channel +def test_auto_ml_transport_channel_mtls_with_client_cert_source(transport_class): + with mock.patch( + "grpc.ssl_channel_credentials", autospec=True + ) as grpc_ssl_channel_cred: + with mock.patch.object( + transport_class, "create_channel", autospec=True + ) as grpc_create_channel: + mock_ssl_cred = mock.Mock() + grpc_ssl_channel_cred.return_value = mock_ssl_cred + + mock_grpc_channel = mock.Mock() + grpc_create_channel.return_value = mock_grpc_channel + + cred = credentials.AnonymousCredentials() + with pytest.warns(DeprecationWarning): + with mock.patch.object(auth, "default") as adc: + adc.return_value = (cred, None) + transport = transport_class( + host="squid.clam.whelk", + api_mtls_endpoint="mtls.squid.clam.whelk", + client_cert_source=client_cert_source_callback, + ) + adc.assert_called_once() + + grpc_ssl_channel_cred.assert_called_once_with( + certificate_chain=b"cert bytes", private_key=b"key bytes" + ) + grpc_create_channel.assert_called_once_with( + "mtls.squid.clam.whelk:443", + credentials=cred, + credentials_file=None, + scopes=("https://www.googleapis.com/auth/cloud-platform",), + ssl_credentials=mock_ssl_cred, + quota_project_id=None, + ) + assert transport.grpc_channel == mock_grpc_channel @pytest.mark.parametrize( - "api_mtls_endpoint", ["mtls.squid.clam.whelk", "mtls.squid.clam.whelk:443"] + "transport_class", + [transports.AutoMlGrpcTransport, transports.AutoMlGrpcAsyncIOTransport], ) -@mock.patch("google.api_core.grpc_helpers_async.create_channel", autospec=True) -def test_auto_ml_grpc_asyncio_transport_channel_mtls_with_adc( - grpc_create_channel, api_mtls_endpoint -): - # Check that if channel and client_cert_source are None, but api_mtls_endpoint - # is provided, then a mTLS channel will be created with SSL ADC. - mock_grpc_channel = mock.Mock() - grpc_create_channel.return_value = mock_grpc_channel - - # Mock google.auth.transport.grpc.SslCredentials class. +def test_auto_ml_transport_channel_mtls_with_adc(transport_class): mock_ssl_cred = mock.Mock() with mock.patch.multiple( "google.auth.transport.grpc.SslCredentials", __init__=mock.Mock(return_value=None), ssl_credentials=mock.PropertyMock(return_value=mock_ssl_cred), ): - mock_cred = mock.Mock() - transport = transports.AutoMlGrpcAsyncIOTransport( - host="squid.clam.whelk", - credentials=mock_cred, - api_mtls_endpoint=api_mtls_endpoint, - client_cert_source=None, - ) - grpc_create_channel.assert_called_once_with( - "mtls.squid.clam.whelk:443", - credentials=mock_cred, - credentials_file=None, - scopes=("https://www.googleapis.com/auth/cloud-platform",), - ssl_credentials=mock_ssl_cred, - quota_project_id=None, - ) - assert transport.grpc_channel == mock_grpc_channel + with mock.patch.object( + transport_class, "create_channel", autospec=True + ) as grpc_create_channel: + mock_grpc_channel = mock.Mock() + grpc_create_channel.return_value = mock_grpc_channel + mock_cred = mock.Mock() + + with pytest.warns(DeprecationWarning): + transport = transport_class( + host="squid.clam.whelk", + credentials=mock_cred, + api_mtls_endpoint="mtls.squid.clam.whelk", + client_cert_source=None, + ) + + grpc_create_channel.assert_called_once_with( + "mtls.squid.clam.whelk:443", + credentials=mock_cred, + credentials_file=None, + scopes=("https://www.googleapis.com/auth/cloud-platform",), + ssl_credentials=mock_ssl_cred, + quota_project_id=None, + ) + assert transport.grpc_channel == mock_grpc_channel def test_auto_ml_grpc_lro_client(): @@ -4929,53 +4946,53 @@ def test_auto_ml_grpc_lro_async_client(): assert transport.operations_client is transport.operations_client -def test_model_path(): +def test_dataset_path(): project = "squid" location = "clam" - model = "whelk" + dataset = "whelk" - expected = "projects/{project}/locations/{location}/models/{model}".format( - project=project, location=location, model=model, + expected = "projects/{project}/locations/{location}/datasets/{dataset}".format( + project=project, location=location, dataset=dataset, ) - actual = AutoMlClient.model_path(project, location, model) + actual = AutoMlClient.dataset_path(project, location, dataset) assert expected == actual -def test_parse_model_path(): +def test_parse_dataset_path(): expected = { "project": "octopus", "location": "oyster", - "model": "nudibranch", + "dataset": "nudibranch", } - path = AutoMlClient.model_path(**expected) + path = AutoMlClient.dataset_path(**expected) # Check that the path construction is reversible. - actual = AutoMlClient.parse_model_path(path) + actual = AutoMlClient.parse_dataset_path(path) assert expected == actual -def test_dataset_path(): +def test_model_path(): project = "squid" location = "clam" - dataset = "whelk" + model = "whelk" - expected = "projects/{project}/locations/{location}/datasets/{dataset}".format( - project=project, location=location, dataset=dataset, + expected = "projects/{project}/locations/{location}/models/{model}".format( + project=project, location=location, model=model, ) - actual = AutoMlClient.dataset_path(project, location, dataset) + actual = AutoMlClient.model_path(project, location, model) assert expected == actual -def test_parse_dataset_path(): +def test_parse_model_path(): expected = { "project": "octopus", "location": "oyster", - "dataset": "nudibranch", + "model": "nudibranch", } - path = AutoMlClient.dataset_path(**expected) + path = AutoMlClient.model_path(**expected) # Check that the path construction is reversible. - actual = AutoMlClient.parse_dataset_path(path) + actual = AutoMlClient.parse_model_path(path) assert expected == actual diff --git a/tests/unit/gapic/automl_v1/test_prediction_service.py b/tests/unit/gapic/automl_v1/test_prediction_service.py index a0087eae..fd886203 100644 --- a/tests/unit/gapic/automl_v1/test_prediction_service.py +++ b/tests/unit/gapic/automl_v1/test_prediction_service.py @@ -31,7 +31,7 @@ from google.api_core import gapic_v1 from google.api_core import grpc_helpers from google.api_core import grpc_helpers_async -from google.api_core import operation_async +from google.api_core import operation_async # type: ignore from google.api_core import operations_v1 from google.auth import credentials from google.auth.exceptions import MutualTLSChannelError @@ -167,15 +167,14 @@ def test_prediction_service_client_client_options( credentials_file=None, host="squid.clam.whelk", scopes=None, - api_mtls_endpoint="squid.clam.whelk", - client_cert_source=None, + ssl_channel_credentials=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) - # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS is + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT is # "never". - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS": "never"}): + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}): with mock.patch.object(transport_class, "__init__") as patched: patched.return_value = None client = client_class() @@ -184,15 +183,14 @@ def test_prediction_service_client_client_options( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=None, - api_mtls_endpoint=client.DEFAULT_ENDPOINT, - client_cert_source=None, + ssl_channel_credentials=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) - # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS is + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT is # "always". - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS": "always"}): + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}): with mock.patch.object(transport_class, "__init__") as patched: patched.return_value = None client = client_class() @@ -201,95 +199,185 @@ def test_prediction_service_client_client_options( credentials_file=None, host=client.DEFAULT_MTLS_ENDPOINT, scopes=None, - api_mtls_endpoint=client.DEFAULT_MTLS_ENDPOINT, - client_cert_source=None, + ssl_channel_credentials=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) - # Check the case api_endpoint is not provided, GOOGLE_API_USE_MTLS is - # "auto", and client_cert_source is provided. - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS": "auto"}): + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT has + # unsupported value. + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "Unsupported"}): + with pytest.raises(MutualTLSChannelError): + client = client_class() + + # Check the case GOOGLE_API_USE_CLIENT_CERTIFICATE has unsupported value. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"} + ): + with pytest.raises(ValueError): + client = client_class() + + # Check the case quota_project_id is provided + options = client_options.ClientOptions(quota_project_id="octopus") + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(client_options=options) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=None, + ssl_channel_credentials=None, + quota_project_id="octopus", + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) + + +@pytest.mark.parametrize( + "client_class,transport_class,transport_name,use_client_cert_env", + [ + ( + PredictionServiceClient, + transports.PredictionServiceGrpcTransport, + "grpc", + "true", + ), + ( + PredictionServiceAsyncClient, + transports.PredictionServiceGrpcAsyncIOTransport, + "grpc_asyncio", + "true", + ), + ( + PredictionServiceClient, + transports.PredictionServiceGrpcTransport, + "grpc", + "false", + ), + ( + PredictionServiceAsyncClient, + transports.PredictionServiceGrpcAsyncIOTransport, + "grpc_asyncio", + "false", + ), + ], +) +@mock.patch.object( + PredictionServiceClient, + "DEFAULT_ENDPOINT", + modify_default_endpoint(PredictionServiceClient), +) +@mock.patch.object( + PredictionServiceAsyncClient, + "DEFAULT_ENDPOINT", + modify_default_endpoint(PredictionServiceAsyncClient), +) +@mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "auto"}) +def test_prediction_service_client_mtls_env_auto( + client_class, transport_class, transport_name, use_client_cert_env +): + # This tests the endpoint autoswitch behavior. Endpoint is autoswitched to the default + # mtls endpoint, if GOOGLE_API_USE_CLIENT_CERTIFICATE is "true" and client cert exists. + + # Check the case client_cert_source is provided. Whether client cert is used depends on + # GOOGLE_API_USE_CLIENT_CERTIFICATE value. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env} + ): options = client_options.ClientOptions( client_cert_source=client_cert_source_callback ) with mock.patch.object(transport_class, "__init__") as patched: - patched.return_value = None - client = client_class(client_options=options) - patched.assert_called_once_with( - credentials=None, - credentials_file=None, - host=client.DEFAULT_MTLS_ENDPOINT, - scopes=None, - api_mtls_endpoint=client.DEFAULT_MTLS_ENDPOINT, - client_cert_source=client_cert_source_callback, - quota_project_id=None, - client_info=transports.base.DEFAULT_CLIENT_INFO, - ) - - # Check the case api_endpoint is not provided, GOOGLE_API_USE_MTLS is - # "auto", and default_client_cert_source is provided. - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS": "auto"}): - with mock.patch.object(transport_class, "__init__") as patched: + ssl_channel_creds = mock.Mock() with mock.patch( - "google.auth.transport.mtls.has_default_client_cert_source", - return_value=True, + "grpc.ssl_channel_credentials", return_value=ssl_channel_creds ): patched.return_value = None - client = client_class() + client = client_class(client_options=options) + + if use_client_cert_env == "false": + expected_ssl_channel_creds = None + expected_host = client.DEFAULT_ENDPOINT + else: + expected_ssl_channel_creds = ssl_channel_creds + expected_host = client.DEFAULT_MTLS_ENDPOINT + patched.assert_called_once_with( credentials=None, credentials_file=None, - host=client.DEFAULT_MTLS_ENDPOINT, + host=expected_host, scopes=None, - api_mtls_endpoint=client.DEFAULT_MTLS_ENDPOINT, - client_cert_source=None, + ssl_channel_credentials=expected_ssl_channel_creds, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) - # Check the case api_endpoint is not provided, GOOGLE_API_USE_MTLS is - # "auto", but client_cert_source and default_client_cert_source are None. - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS": "auto"}): + # Check the case ADC client cert is provided. Whether client cert is used depends on + # GOOGLE_API_USE_CLIENT_CERTIFICATE value. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env} + ): with mock.patch.object(transport_class, "__init__") as patched: with mock.patch( - "google.auth.transport.mtls.has_default_client_cert_source", - return_value=False, + "google.auth.transport.grpc.SslCredentials.__init__", return_value=None ): - patched.return_value = None - client = client_class() - patched.assert_called_once_with( - credentials=None, - credentials_file=None, - host=client.DEFAULT_ENDPOINT, - scopes=None, - api_mtls_endpoint=client.DEFAULT_ENDPOINT, - client_cert_source=None, - quota_project_id=None, - client_info=transports.base.DEFAULT_CLIENT_INFO, - ) - - # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS has - # unsupported value. - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS": "Unsupported"}): - with pytest.raises(MutualTLSChannelError): - client = client_class() - - # Check the case quota_project_id is provided - options = client_options.ClientOptions(quota_project_id="octopus") - with mock.patch.object(transport_class, "__init__") as patched: - patched.return_value = None - client = client_class(client_options=options) - patched.assert_called_once_with( - credentials=None, - credentials_file=None, - host=client.DEFAULT_ENDPOINT, - scopes=None, - api_mtls_endpoint=client.DEFAULT_ENDPOINT, - client_cert_source=None, - quota_project_id="octopus", - client_info=transports.base.DEFAULT_CLIENT_INFO, - ) + with mock.patch( + "google.auth.transport.grpc.SslCredentials.is_mtls", + new_callable=mock.PropertyMock, + ) as is_mtls_mock: + with mock.patch( + "google.auth.transport.grpc.SslCredentials.ssl_credentials", + new_callable=mock.PropertyMock, + ) as ssl_credentials_mock: + if use_client_cert_env == "false": + is_mtls_mock.return_value = False + ssl_credentials_mock.return_value = None + expected_host = client.DEFAULT_ENDPOINT + expected_ssl_channel_creds = None + else: + is_mtls_mock.return_value = True + ssl_credentials_mock.return_value = mock.Mock() + expected_host = client.DEFAULT_MTLS_ENDPOINT + expected_ssl_channel_creds = ( + ssl_credentials_mock.return_value + ) + + patched.return_value = None + client = client_class() + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=expected_host, + scopes=None, + ssl_channel_credentials=expected_ssl_channel_creds, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) + + # Check the case client_cert_source and ADC client cert are not provided. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env} + ): + with mock.patch.object(transport_class, "__init__") as patched: + with mock.patch( + "google.auth.transport.grpc.SslCredentials.__init__", return_value=None + ): + with mock.patch( + "google.auth.transport.grpc.SslCredentials.is_mtls", + new_callable=mock.PropertyMock, + ) as is_mtls_mock: + is_mtls_mock.return_value = False + patched.return_value = None + client = client_class() + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=None, + ssl_channel_credentials=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) @pytest.mark.parametrize( @@ -316,8 +404,7 @@ def test_prediction_service_client_client_options_scopes( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=["1", "2"], - api_mtls_endpoint=client.DEFAULT_ENDPOINT, - client_cert_source=None, + ssl_channel_credentials=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -347,8 +434,7 @@ def test_prediction_service_client_client_options_credentials_file( credentials_file="credentials.json", host=client.DEFAULT_ENDPOINT, scopes=None, - api_mtls_endpoint=client.DEFAULT_ENDPOINT, - client_cert_source=None, + ssl_channel_credentials=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -367,8 +453,7 @@ def test_prediction_service_client_client_options_from_dict(): credentials_file=None, host="squid.clam.whelk", scopes=None, - api_mtls_endpoint="squid.clam.whelk", - client_cert_source=None, + ssl_channel_credentials=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -904,6 +989,21 @@ def test_transport_get_channel(): assert channel +@pytest.mark.parametrize( + "transport_class", + [ + transports.PredictionServiceGrpcTransport, + transports.PredictionServiceGrpcAsyncIOTransport, + ], +) +def test_transport_adc(transport_class): + # Test default credentials are used if not provided. + with mock.patch.object(auth, "default") as adc: + adc.return_value = (credentials.AnonymousCredentials(), None) + transport_class() + adc.assert_called_once() + + def test_transport_grpc_default(): # A client should use the gRPC transport by default. client = PredictionServiceClient(credentials=credentials.AnonymousCredentials(),) @@ -964,6 +1064,17 @@ def test_prediction_service_base_transport_with_credentials_file(): ) +def test_prediction_service_base_transport_with_adc(): + # Test the default credentials are used if credentials and credentials_file are None. + with mock.patch.object(auth, "default") as adc, mock.patch( + "google.cloud.automl_v1.services.prediction_service.transports.PredictionServiceTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + adc.return_value = (credentials.AnonymousCredentials(), None) + transport = transports.PredictionServiceTransport() + adc.assert_called_once() + + def test_prediction_service_auth_adc(): # If no credentials are provided, we should use ADC credentials. with mock.patch.object(auth, "default") as adc: @@ -1012,179 +1123,110 @@ def test_prediction_service_host_with_port(): def test_prediction_service_grpc_transport_channel(): channel = grpc.insecure_channel("http://localhost/") - # Check that if channel is provided, mtls endpoint and client_cert_source - # won't be used. - callback = mock.MagicMock() + # Check that channel is used if provided. transport = transports.PredictionServiceGrpcTransport( - host="squid.clam.whelk", - channel=channel, - api_mtls_endpoint="mtls.squid.clam.whelk", - client_cert_source=callback, + host="squid.clam.whelk", channel=channel, ) assert transport.grpc_channel == channel assert transport._host == "squid.clam.whelk:443" - assert not callback.called def test_prediction_service_grpc_asyncio_transport_channel(): channel = aio.insecure_channel("http://localhost/") - # Check that if channel is provided, mtls endpoint and client_cert_source - # won't be used. - callback = mock.MagicMock() + # Check that channel is used if provided. transport = transports.PredictionServiceGrpcAsyncIOTransport( - host="squid.clam.whelk", - channel=channel, - api_mtls_endpoint="mtls.squid.clam.whelk", - client_cert_source=callback, + host="squid.clam.whelk", channel=channel, ) assert transport.grpc_channel == channel assert transport._host == "squid.clam.whelk:443" - assert not callback.called - - -@mock.patch("grpc.ssl_channel_credentials", autospec=True) -@mock.patch("google.api_core.grpc_helpers.create_channel", autospec=True) -def test_prediction_service_grpc_transport_channel_mtls_with_client_cert_source( - grpc_create_channel, grpc_ssl_channel_cred -): - # Check that if channel is None, but api_mtls_endpoint and client_cert_source - # are provided, then a mTLS channel will be created. - mock_cred = mock.Mock() - - mock_ssl_cred = mock.Mock() - grpc_ssl_channel_cred.return_value = mock_ssl_cred - - mock_grpc_channel = mock.Mock() - grpc_create_channel.return_value = mock_grpc_channel - - transport = transports.PredictionServiceGrpcTransport( - host="squid.clam.whelk", - credentials=mock_cred, - api_mtls_endpoint="mtls.squid.clam.whelk", - client_cert_source=client_cert_source_callback, - ) - grpc_ssl_channel_cred.assert_called_once_with( - certificate_chain=b"cert bytes", private_key=b"key bytes" - ) - grpc_create_channel.assert_called_once_with( - "mtls.squid.clam.whelk:443", - credentials=mock_cred, - credentials_file=None, - scopes=("https://www.googleapis.com/auth/cloud-platform",), - ssl_credentials=mock_ssl_cred, - quota_project_id=None, - ) - assert transport.grpc_channel == mock_grpc_channel - - -@mock.patch("grpc.ssl_channel_credentials", autospec=True) -@mock.patch("google.api_core.grpc_helpers_async.create_channel", autospec=True) -def test_prediction_service_grpc_asyncio_transport_channel_mtls_with_client_cert_source( - grpc_create_channel, grpc_ssl_channel_cred -): - # Check that if channel is None, but api_mtls_endpoint and client_cert_source - # are provided, then a mTLS channel will be created. - mock_cred = mock.Mock() - - mock_ssl_cred = mock.Mock() - grpc_ssl_channel_cred.return_value = mock_ssl_cred - - mock_grpc_channel = mock.Mock() - grpc_create_channel.return_value = mock_grpc_channel - - transport = transports.PredictionServiceGrpcAsyncIOTransport( - host="squid.clam.whelk", - credentials=mock_cred, - api_mtls_endpoint="mtls.squid.clam.whelk", - client_cert_source=client_cert_source_callback, - ) - grpc_ssl_channel_cred.assert_called_once_with( - certificate_chain=b"cert bytes", private_key=b"key bytes" - ) - grpc_create_channel.assert_called_once_with( - "mtls.squid.clam.whelk:443", - credentials=mock_cred, - credentials_file=None, - scopes=("https://www.googleapis.com/auth/cloud-platform",), - ssl_credentials=mock_ssl_cred, - quota_project_id=None, - ) - assert transport.grpc_channel == mock_grpc_channel @pytest.mark.parametrize( - "api_mtls_endpoint", ["mtls.squid.clam.whelk", "mtls.squid.clam.whelk:443"] + "transport_class", + [ + transports.PredictionServiceGrpcTransport, + transports.PredictionServiceGrpcAsyncIOTransport, + ], ) -@mock.patch("google.api_core.grpc_helpers.create_channel", autospec=True) -def test_prediction_service_grpc_transport_channel_mtls_with_adc( - grpc_create_channel, api_mtls_endpoint +def test_prediction_service_transport_channel_mtls_with_client_cert_source( + transport_class, ): - # Check that if channel and client_cert_source are None, but api_mtls_endpoint - # is provided, then a mTLS channel will be created with SSL ADC. - mock_grpc_channel = mock.Mock() - grpc_create_channel.return_value = mock_grpc_channel - - # Mock google.auth.transport.grpc.SslCredentials class. - mock_ssl_cred = mock.Mock() - with mock.patch.multiple( - "google.auth.transport.grpc.SslCredentials", - __init__=mock.Mock(return_value=None), - ssl_credentials=mock.PropertyMock(return_value=mock_ssl_cred), - ): - mock_cred = mock.Mock() - transport = transports.PredictionServiceGrpcTransport( - host="squid.clam.whelk", - credentials=mock_cred, - api_mtls_endpoint=api_mtls_endpoint, - client_cert_source=None, - ) - grpc_create_channel.assert_called_once_with( - "mtls.squid.clam.whelk:443", - credentials=mock_cred, - credentials_file=None, - scopes=("https://www.googleapis.com/auth/cloud-platform",), - ssl_credentials=mock_ssl_cred, - quota_project_id=None, - ) - assert transport.grpc_channel == mock_grpc_channel + with mock.patch( + "grpc.ssl_channel_credentials", autospec=True + ) as grpc_ssl_channel_cred: + with mock.patch.object( + transport_class, "create_channel", autospec=True + ) as grpc_create_channel: + mock_ssl_cred = mock.Mock() + grpc_ssl_channel_cred.return_value = mock_ssl_cred + + mock_grpc_channel = mock.Mock() + grpc_create_channel.return_value = mock_grpc_channel + + cred = credentials.AnonymousCredentials() + with pytest.warns(DeprecationWarning): + with mock.patch.object(auth, "default") as adc: + adc.return_value = (cred, None) + transport = transport_class( + host="squid.clam.whelk", + api_mtls_endpoint="mtls.squid.clam.whelk", + client_cert_source=client_cert_source_callback, + ) + adc.assert_called_once() + + grpc_ssl_channel_cred.assert_called_once_with( + certificate_chain=b"cert bytes", private_key=b"key bytes" + ) + grpc_create_channel.assert_called_once_with( + "mtls.squid.clam.whelk:443", + credentials=cred, + credentials_file=None, + scopes=("https://www.googleapis.com/auth/cloud-platform",), + ssl_credentials=mock_ssl_cred, + quota_project_id=None, + ) + assert transport.grpc_channel == mock_grpc_channel @pytest.mark.parametrize( - "api_mtls_endpoint", ["mtls.squid.clam.whelk", "mtls.squid.clam.whelk:443"] + "transport_class", + [ + transports.PredictionServiceGrpcTransport, + transports.PredictionServiceGrpcAsyncIOTransport, + ], ) -@mock.patch("google.api_core.grpc_helpers_async.create_channel", autospec=True) -def test_prediction_service_grpc_asyncio_transport_channel_mtls_with_adc( - grpc_create_channel, api_mtls_endpoint -): - # Check that if channel and client_cert_source are None, but api_mtls_endpoint - # is provided, then a mTLS channel will be created with SSL ADC. - mock_grpc_channel = mock.Mock() - grpc_create_channel.return_value = mock_grpc_channel - - # Mock google.auth.transport.grpc.SslCredentials class. +def test_prediction_service_transport_channel_mtls_with_adc(transport_class): mock_ssl_cred = mock.Mock() with mock.patch.multiple( "google.auth.transport.grpc.SslCredentials", __init__=mock.Mock(return_value=None), ssl_credentials=mock.PropertyMock(return_value=mock_ssl_cred), ): - mock_cred = mock.Mock() - transport = transports.PredictionServiceGrpcAsyncIOTransport( - host="squid.clam.whelk", - credentials=mock_cred, - api_mtls_endpoint=api_mtls_endpoint, - client_cert_source=None, - ) - grpc_create_channel.assert_called_once_with( - "mtls.squid.clam.whelk:443", - credentials=mock_cred, - credentials_file=None, - scopes=("https://www.googleapis.com/auth/cloud-platform",), - ssl_credentials=mock_ssl_cred, - quota_project_id=None, - ) - assert transport.grpc_channel == mock_grpc_channel + with mock.patch.object( + transport_class, "create_channel", autospec=True + ) as grpc_create_channel: + mock_grpc_channel = mock.Mock() + grpc_create_channel.return_value = mock_grpc_channel + mock_cred = mock.Mock() + + with pytest.warns(DeprecationWarning): + transport = transport_class( + host="squid.clam.whelk", + credentials=mock_cred, + api_mtls_endpoint="mtls.squid.clam.whelk", + client_cert_source=None, + ) + + grpc_create_channel.assert_called_once_with( + "mtls.squid.clam.whelk:443", + credentials=mock_cred, + credentials_file=None, + scopes=("https://www.googleapis.com/auth/cloud-platform",), + ssl_credentials=mock_ssl_cred, + quota_project_id=None, + ) + assert transport.grpc_channel == mock_grpc_channel def test_prediction_service_grpc_lro_client(): diff --git a/tests/unit/gapic/automl_v1beta1/test_auto_ml.py b/tests/unit/gapic/automl_v1beta1/test_auto_ml.py index 2464c824..09cb0749 100644 --- a/tests/unit/gapic/automl_v1beta1/test_auto_ml.py +++ b/tests/unit/gapic/automl_v1beta1/test_auto_ml.py @@ -31,7 +31,7 @@ from google.api_core import gapic_v1 from google.api_core import grpc_helpers from google.api_core import grpc_helpers_async -from google.api_core import operation_async +from google.api_core import operation_async # type: ignore from google.api_core import operations_v1 from google.auth import credentials from google.auth.exceptions import MutualTLSChannelError @@ -168,15 +168,14 @@ def test_auto_ml_client_client_options(client_class, transport_class, transport_ credentials_file=None, host="squid.clam.whelk", scopes=None, - api_mtls_endpoint="squid.clam.whelk", - client_cert_source=None, + ssl_channel_credentials=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) - # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS is + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT is # "never". - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS": "never"}): + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}): with mock.patch.object(transport_class, "__init__") as patched: patched.return_value = None client = client_class() @@ -185,15 +184,14 @@ def test_auto_ml_client_client_options(client_class, transport_class, transport_ credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=None, - api_mtls_endpoint=client.DEFAULT_ENDPOINT, - client_cert_source=None, + ssl_channel_credentials=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) - # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS is + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT is # "always". - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS": "always"}): + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}): with mock.patch.object(transport_class, "__init__") as patched: patched.return_value = None client = client_class() @@ -202,95 +200,171 @@ def test_auto_ml_client_client_options(client_class, transport_class, transport_ credentials_file=None, host=client.DEFAULT_MTLS_ENDPOINT, scopes=None, - api_mtls_endpoint=client.DEFAULT_MTLS_ENDPOINT, - client_cert_source=None, + ssl_channel_credentials=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) - # Check the case api_endpoint is not provided, GOOGLE_API_USE_MTLS is - # "auto", and client_cert_source is provided. - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS": "auto"}): + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT has + # unsupported value. + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "Unsupported"}): + with pytest.raises(MutualTLSChannelError): + client = client_class() + + # Check the case GOOGLE_API_USE_CLIENT_CERTIFICATE has unsupported value. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"} + ): + with pytest.raises(ValueError): + client = client_class() + + # Check the case quota_project_id is provided + options = client_options.ClientOptions(quota_project_id="octopus") + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(client_options=options) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=None, + ssl_channel_credentials=None, + quota_project_id="octopus", + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) + + +@pytest.mark.parametrize( + "client_class,transport_class,transport_name,use_client_cert_env", + [ + (AutoMlClient, transports.AutoMlGrpcTransport, "grpc", "true"), + ( + AutoMlAsyncClient, + transports.AutoMlGrpcAsyncIOTransport, + "grpc_asyncio", + "true", + ), + (AutoMlClient, transports.AutoMlGrpcTransport, "grpc", "false"), + ( + AutoMlAsyncClient, + transports.AutoMlGrpcAsyncIOTransport, + "grpc_asyncio", + "false", + ), + ], +) +@mock.patch.object( + AutoMlClient, "DEFAULT_ENDPOINT", modify_default_endpoint(AutoMlClient) +) +@mock.patch.object( + AutoMlAsyncClient, "DEFAULT_ENDPOINT", modify_default_endpoint(AutoMlAsyncClient) +) +@mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "auto"}) +def test_auto_ml_client_mtls_env_auto( + client_class, transport_class, transport_name, use_client_cert_env +): + # This tests the endpoint autoswitch behavior. Endpoint is autoswitched to the default + # mtls endpoint, if GOOGLE_API_USE_CLIENT_CERTIFICATE is "true" and client cert exists. + + # Check the case client_cert_source is provided. Whether client cert is used depends on + # GOOGLE_API_USE_CLIENT_CERTIFICATE value. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env} + ): options = client_options.ClientOptions( client_cert_source=client_cert_source_callback ) with mock.patch.object(transport_class, "__init__") as patched: - patched.return_value = None - client = client_class(client_options=options) - patched.assert_called_once_with( - credentials=None, - credentials_file=None, - host=client.DEFAULT_MTLS_ENDPOINT, - scopes=None, - api_mtls_endpoint=client.DEFAULT_MTLS_ENDPOINT, - client_cert_source=client_cert_source_callback, - quota_project_id=None, - client_info=transports.base.DEFAULT_CLIENT_INFO, - ) - - # Check the case api_endpoint is not provided, GOOGLE_API_USE_MTLS is - # "auto", and default_client_cert_source is provided. - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS": "auto"}): - with mock.patch.object(transport_class, "__init__") as patched: + ssl_channel_creds = mock.Mock() with mock.patch( - "google.auth.transport.mtls.has_default_client_cert_source", - return_value=True, + "grpc.ssl_channel_credentials", return_value=ssl_channel_creds ): patched.return_value = None - client = client_class() + client = client_class(client_options=options) + + if use_client_cert_env == "false": + expected_ssl_channel_creds = None + expected_host = client.DEFAULT_ENDPOINT + else: + expected_ssl_channel_creds = ssl_channel_creds + expected_host = client.DEFAULT_MTLS_ENDPOINT + patched.assert_called_once_with( credentials=None, credentials_file=None, - host=client.DEFAULT_MTLS_ENDPOINT, + host=expected_host, scopes=None, - api_mtls_endpoint=client.DEFAULT_MTLS_ENDPOINT, - client_cert_source=None, + ssl_channel_credentials=expected_ssl_channel_creds, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) - # Check the case api_endpoint is not provided, GOOGLE_API_USE_MTLS is - # "auto", but client_cert_source and default_client_cert_source are None. - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS": "auto"}): + # Check the case ADC client cert is provided. Whether client cert is used depends on + # GOOGLE_API_USE_CLIENT_CERTIFICATE value. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env} + ): with mock.patch.object(transport_class, "__init__") as patched: with mock.patch( - "google.auth.transport.mtls.has_default_client_cert_source", - return_value=False, + "google.auth.transport.grpc.SslCredentials.__init__", return_value=None ): - patched.return_value = None - client = client_class() - patched.assert_called_once_with( - credentials=None, - credentials_file=None, - host=client.DEFAULT_ENDPOINT, - scopes=None, - api_mtls_endpoint=client.DEFAULT_ENDPOINT, - client_cert_source=None, - quota_project_id=None, - client_info=transports.base.DEFAULT_CLIENT_INFO, - ) - - # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS has - # unsupported value. - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS": "Unsupported"}): - with pytest.raises(MutualTLSChannelError): - client = client_class() - - # Check the case quota_project_id is provided - options = client_options.ClientOptions(quota_project_id="octopus") - with mock.patch.object(transport_class, "__init__") as patched: - patched.return_value = None - client = client_class(client_options=options) - patched.assert_called_once_with( - credentials=None, - credentials_file=None, - host=client.DEFAULT_ENDPOINT, - scopes=None, - api_mtls_endpoint=client.DEFAULT_ENDPOINT, - client_cert_source=None, - quota_project_id="octopus", - client_info=transports.base.DEFAULT_CLIENT_INFO, - ) + with mock.patch( + "google.auth.transport.grpc.SslCredentials.is_mtls", + new_callable=mock.PropertyMock, + ) as is_mtls_mock: + with mock.patch( + "google.auth.transport.grpc.SslCredentials.ssl_credentials", + new_callable=mock.PropertyMock, + ) as ssl_credentials_mock: + if use_client_cert_env == "false": + is_mtls_mock.return_value = False + ssl_credentials_mock.return_value = None + expected_host = client.DEFAULT_ENDPOINT + expected_ssl_channel_creds = None + else: + is_mtls_mock.return_value = True + ssl_credentials_mock.return_value = mock.Mock() + expected_host = client.DEFAULT_MTLS_ENDPOINT + expected_ssl_channel_creds = ( + ssl_credentials_mock.return_value + ) + + patched.return_value = None + client = client_class() + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=expected_host, + scopes=None, + ssl_channel_credentials=expected_ssl_channel_creds, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) + + # Check the case client_cert_source and ADC client cert are not provided. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env} + ): + with mock.patch.object(transport_class, "__init__") as patched: + with mock.patch( + "google.auth.transport.grpc.SslCredentials.__init__", return_value=None + ): + with mock.patch( + "google.auth.transport.grpc.SslCredentials.is_mtls", + new_callable=mock.PropertyMock, + ) as is_mtls_mock: + is_mtls_mock.return_value = False + patched.return_value = None + client = client_class() + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=None, + ssl_channel_credentials=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) @pytest.mark.parametrize( @@ -313,8 +387,7 @@ def test_auto_ml_client_client_options_scopes( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=["1", "2"], - api_mtls_endpoint=client.DEFAULT_ENDPOINT, - client_cert_source=None, + ssl_channel_credentials=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -340,8 +413,7 @@ def test_auto_ml_client_client_options_credentials_file( credentials_file="credentials.json", host=client.DEFAULT_ENDPOINT, scopes=None, - api_mtls_endpoint=client.DEFAULT_ENDPOINT, - client_cert_source=None, + ssl_channel_credentials=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -358,8 +430,7 @@ def test_auto_ml_client_client_options_from_dict(): credentials_file=None, host="squid.clam.whelk", scopes=None, - api_mtls_endpoint="squid.clam.whelk", - client_cert_source=None, + ssl_channel_credentials=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -1079,8 +1150,8 @@ def test_list_datasets_pages(): RuntimeError, ) pages = list(client.list_datasets(request={}).pages) - for page, token in zip(pages, ["abc", "def", "ghi", ""]): - assert page.raw_page.next_page_token == token + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token @pytest.mark.asyncio @@ -1144,10 +1215,10 @@ async def test_list_datasets_async_pages(): RuntimeError, ) pages = [] - async for page in (await client.list_datasets(request={})).pages: - pages.append(page) - for page, token in zip(pages, ["abc", "def", "ghi", ""]): - assert page.raw_page.next_page_token == token + async for page_ in (await client.list_datasets(request={})).pages: + pages.append(page_) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token def test_update_dataset( @@ -2711,8 +2782,8 @@ def test_list_table_specs_pages(): RuntimeError, ) pages = list(client.list_table_specs(request={}).pages) - for page, token in zip(pages, ["abc", "def", "ghi", ""]): - assert page.raw_page.next_page_token == token + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token @pytest.mark.asyncio @@ -2784,10 +2855,10 @@ async def test_list_table_specs_async_pages(): RuntimeError, ) pages = [] - async for page in (await client.list_table_specs(request={})).pages: - pages.append(page) - for page, token in zip(pages, ["abc", "def", "ghi", ""]): - assert page.raw_page.next_page_token == token + async for page_ in (await client.list_table_specs(request={})).pages: + pages.append(page_) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token def test_update_table_spec( @@ -3494,8 +3565,8 @@ def test_list_column_specs_pages(): RuntimeError, ) pages = list(client.list_column_specs(request={}).pages) - for page, token in zip(pages, ["abc", "def", "ghi", ""]): - assert page.raw_page.next_page_token == token + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token @pytest.mark.asyncio @@ -3567,10 +3638,10 @@ async def test_list_column_specs_async_pages(): RuntimeError, ) pages = [] - async for page in (await client.list_column_specs(request={})).pages: - pages.append(page) - for page, token in zip(pages, ["abc", "def", "ghi", ""]): - assert page.raw_page.next_page_token == token + async for page_ in (await client.list_column_specs(request={})).pages: + pages.append(page_) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token def test_update_column_spec( @@ -4455,8 +4526,8 @@ def test_list_models_pages(): RuntimeError, ) pages = list(client.list_models(request={}).pages) - for page, token in zip(pages, ["abc", "def", "ghi", ""]): - assert page.raw_page.next_page_token == token + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token @pytest.mark.asyncio @@ -4512,10 +4583,10 @@ async def test_list_models_async_pages(): RuntimeError, ) pages = [] - async for page in (await client.list_models(request={})).pages: - pages.append(page) - for page, token in zip(pages, ["abc", "def", "ghi", ""]): - assert page.raw_page.next_page_token == token + async for page_ in (await client.list_models(request={})).pages: + pages.append(page_) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token def test_delete_model(transport: str = "grpc", request_type=service.DeleteModelRequest): @@ -6013,8 +6084,8 @@ def test_list_model_evaluations_pages(): RuntimeError, ) pages = list(client.list_model_evaluations(request={}).pages) - for page, token in zip(pages, ["abc", "def", "ghi", ""]): - assert page.raw_page.next_page_token == token + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token @pytest.mark.asyncio @@ -6098,10 +6169,10 @@ async def test_list_model_evaluations_async_pages(): RuntimeError, ) pages = [] - async for page in (await client.list_model_evaluations(request={})).pages: - pages.append(page) - for page, token in zip(pages, ["abc", "def", "ghi", ""]): - assert page.raw_page.next_page_token == token + async for page_ in (await client.list_model_evaluations(request={})).pages: + pages.append(page_) + for page_, token in zip(pages, ["abc", "def", "ghi", ""]): + assert page_.raw_page.next_page_token == token def test_credentials_transport_error(): @@ -6158,6 +6229,18 @@ def test_transport_get_channel(): assert channel +@pytest.mark.parametrize( + "transport_class", + [transports.AutoMlGrpcTransport, transports.AutoMlGrpcAsyncIOTransport], +) +def test_transport_adc(transport_class): + # Test default credentials are used if not provided. + with mock.patch.object(auth, "default") as adc: + adc.return_value = (credentials.AnonymousCredentials(), None) + transport_class() + adc.assert_called_once() + + def test_transport_grpc_default(): # A client should use the gRPC transport by default. client = AutoMlClient(credentials=credentials.AnonymousCredentials(),) @@ -6240,6 +6323,17 @@ def test_auto_ml_base_transport_with_credentials_file(): ) +def test_auto_ml_base_transport_with_adc(): + # Test the default credentials are used if credentials and credentials_file are None. + with mock.patch.object(auth, "default") as adc, mock.patch( + "google.cloud.automl_v1beta1.services.auto_ml.transports.AutoMlTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + adc.return_value = (credentials.AnonymousCredentials(), None) + transport = transports.AutoMlTransport() + adc.assert_called_once() + + def test_auto_ml_auth_adc(): # If no credentials are provided, we should use ADC credentials. with mock.patch.object(auth, "default") as adc: @@ -6288,179 +6382,102 @@ def test_auto_ml_host_with_port(): def test_auto_ml_grpc_transport_channel(): channel = grpc.insecure_channel("http://localhost/") - # Check that if channel is provided, mtls endpoint and client_cert_source - # won't be used. - callback = mock.MagicMock() + # Check that channel is used if provided. transport = transports.AutoMlGrpcTransport( - host="squid.clam.whelk", - channel=channel, - api_mtls_endpoint="mtls.squid.clam.whelk", - client_cert_source=callback, + host="squid.clam.whelk", channel=channel, ) assert transport.grpc_channel == channel assert transport._host == "squid.clam.whelk:443" - assert not callback.called def test_auto_ml_grpc_asyncio_transport_channel(): channel = aio.insecure_channel("http://localhost/") - # Check that if channel is provided, mtls endpoint and client_cert_source - # won't be used. - callback = mock.MagicMock() + # Check that channel is used if provided. transport = transports.AutoMlGrpcAsyncIOTransport( - host="squid.clam.whelk", - channel=channel, - api_mtls_endpoint="mtls.squid.clam.whelk", - client_cert_source=callback, + host="squid.clam.whelk", channel=channel, ) assert transport.grpc_channel == channel assert transport._host == "squid.clam.whelk:443" - assert not callback.called - - -@mock.patch("grpc.ssl_channel_credentials", autospec=True) -@mock.patch("google.api_core.grpc_helpers.create_channel", autospec=True) -def test_auto_ml_grpc_transport_channel_mtls_with_client_cert_source( - grpc_create_channel, grpc_ssl_channel_cred -): - # Check that if channel is None, but api_mtls_endpoint and client_cert_source - # are provided, then a mTLS channel will be created. - mock_cred = mock.Mock() - - mock_ssl_cred = mock.Mock() - grpc_ssl_channel_cred.return_value = mock_ssl_cred - - mock_grpc_channel = mock.Mock() - grpc_create_channel.return_value = mock_grpc_channel - - transport = transports.AutoMlGrpcTransport( - host="squid.clam.whelk", - credentials=mock_cred, - api_mtls_endpoint="mtls.squid.clam.whelk", - client_cert_source=client_cert_source_callback, - ) - grpc_ssl_channel_cred.assert_called_once_with( - certificate_chain=b"cert bytes", private_key=b"key bytes" - ) - grpc_create_channel.assert_called_once_with( - "mtls.squid.clam.whelk:443", - credentials=mock_cred, - credentials_file=None, - scopes=("https://www.googleapis.com/auth/cloud-platform",), - ssl_credentials=mock_ssl_cred, - quota_project_id=None, - ) - assert transport.grpc_channel == mock_grpc_channel - - -@mock.patch("grpc.ssl_channel_credentials", autospec=True) -@mock.patch("google.api_core.grpc_helpers_async.create_channel", autospec=True) -def test_auto_ml_grpc_asyncio_transport_channel_mtls_with_client_cert_source( - grpc_create_channel, grpc_ssl_channel_cred -): - # Check that if channel is None, but api_mtls_endpoint and client_cert_source - # are provided, then a mTLS channel will be created. - mock_cred = mock.Mock() - - mock_ssl_cred = mock.Mock() - grpc_ssl_channel_cred.return_value = mock_ssl_cred - - mock_grpc_channel = mock.Mock() - grpc_create_channel.return_value = mock_grpc_channel - - transport = transports.AutoMlGrpcAsyncIOTransport( - host="squid.clam.whelk", - credentials=mock_cred, - api_mtls_endpoint="mtls.squid.clam.whelk", - client_cert_source=client_cert_source_callback, - ) - grpc_ssl_channel_cred.assert_called_once_with( - certificate_chain=b"cert bytes", private_key=b"key bytes" - ) - grpc_create_channel.assert_called_once_with( - "mtls.squid.clam.whelk:443", - credentials=mock_cred, - credentials_file=None, - scopes=("https://www.googleapis.com/auth/cloud-platform",), - ssl_credentials=mock_ssl_cred, - quota_project_id=None, - ) - assert transport.grpc_channel == mock_grpc_channel @pytest.mark.parametrize( - "api_mtls_endpoint", ["mtls.squid.clam.whelk", "mtls.squid.clam.whelk:443"] + "transport_class", + [transports.AutoMlGrpcTransport, transports.AutoMlGrpcAsyncIOTransport], ) -@mock.patch("google.api_core.grpc_helpers.create_channel", autospec=True) -def test_auto_ml_grpc_transport_channel_mtls_with_adc( - grpc_create_channel, api_mtls_endpoint -): - # Check that if channel and client_cert_source are None, but api_mtls_endpoint - # is provided, then a mTLS channel will be created with SSL ADC. - mock_grpc_channel = mock.Mock() - grpc_create_channel.return_value = mock_grpc_channel - - # Mock google.auth.transport.grpc.SslCredentials class. - mock_ssl_cred = mock.Mock() - with mock.patch.multiple( - "google.auth.transport.grpc.SslCredentials", - __init__=mock.Mock(return_value=None), - ssl_credentials=mock.PropertyMock(return_value=mock_ssl_cred), - ): - mock_cred = mock.Mock() - transport = transports.AutoMlGrpcTransport( - host="squid.clam.whelk", - credentials=mock_cred, - api_mtls_endpoint=api_mtls_endpoint, - client_cert_source=None, - ) - grpc_create_channel.assert_called_once_with( - "mtls.squid.clam.whelk:443", - credentials=mock_cred, - credentials_file=None, - scopes=("https://www.googleapis.com/auth/cloud-platform",), - ssl_credentials=mock_ssl_cred, - quota_project_id=None, - ) - assert transport.grpc_channel == mock_grpc_channel +def test_auto_ml_transport_channel_mtls_with_client_cert_source(transport_class): + with mock.patch( + "grpc.ssl_channel_credentials", autospec=True + ) as grpc_ssl_channel_cred: + with mock.patch.object( + transport_class, "create_channel", autospec=True + ) as grpc_create_channel: + mock_ssl_cred = mock.Mock() + grpc_ssl_channel_cred.return_value = mock_ssl_cred + + mock_grpc_channel = mock.Mock() + grpc_create_channel.return_value = mock_grpc_channel + + cred = credentials.AnonymousCredentials() + with pytest.warns(DeprecationWarning): + with mock.patch.object(auth, "default") as adc: + adc.return_value = (cred, None) + transport = transport_class( + host="squid.clam.whelk", + api_mtls_endpoint="mtls.squid.clam.whelk", + client_cert_source=client_cert_source_callback, + ) + adc.assert_called_once() + + grpc_ssl_channel_cred.assert_called_once_with( + certificate_chain=b"cert bytes", private_key=b"key bytes" + ) + grpc_create_channel.assert_called_once_with( + "mtls.squid.clam.whelk:443", + credentials=cred, + credentials_file=None, + scopes=("https://www.googleapis.com/auth/cloud-platform",), + ssl_credentials=mock_ssl_cred, + quota_project_id=None, + ) + assert transport.grpc_channel == mock_grpc_channel @pytest.mark.parametrize( - "api_mtls_endpoint", ["mtls.squid.clam.whelk", "mtls.squid.clam.whelk:443"] + "transport_class", + [transports.AutoMlGrpcTransport, transports.AutoMlGrpcAsyncIOTransport], ) -@mock.patch("google.api_core.grpc_helpers_async.create_channel", autospec=True) -def test_auto_ml_grpc_asyncio_transport_channel_mtls_with_adc( - grpc_create_channel, api_mtls_endpoint -): - # Check that if channel and client_cert_source are None, but api_mtls_endpoint - # is provided, then a mTLS channel will be created with SSL ADC. - mock_grpc_channel = mock.Mock() - grpc_create_channel.return_value = mock_grpc_channel - - # Mock google.auth.transport.grpc.SslCredentials class. +def test_auto_ml_transport_channel_mtls_with_adc(transport_class): mock_ssl_cred = mock.Mock() with mock.patch.multiple( "google.auth.transport.grpc.SslCredentials", __init__=mock.Mock(return_value=None), ssl_credentials=mock.PropertyMock(return_value=mock_ssl_cred), ): - mock_cred = mock.Mock() - transport = transports.AutoMlGrpcAsyncIOTransport( - host="squid.clam.whelk", - credentials=mock_cred, - api_mtls_endpoint=api_mtls_endpoint, - client_cert_source=None, - ) - grpc_create_channel.assert_called_once_with( - "mtls.squid.clam.whelk:443", - credentials=mock_cred, - credentials_file=None, - scopes=("https://www.googleapis.com/auth/cloud-platform",), - ssl_credentials=mock_ssl_cred, - quota_project_id=None, - ) - assert transport.grpc_channel == mock_grpc_channel + with mock.patch.object( + transport_class, "create_channel", autospec=True + ) as grpc_create_channel: + mock_grpc_channel = mock.Mock() + grpc_create_channel.return_value = mock_grpc_channel + mock_cred = mock.Mock() + + with pytest.warns(DeprecationWarning): + transport = transport_class( + host="squid.clam.whelk", + credentials=mock_cred, + api_mtls_endpoint="mtls.squid.clam.whelk", + client_cert_source=None, + ) + + grpc_create_channel.assert_called_once_with( + "mtls.squid.clam.whelk:443", + credentials=mock_cred, + credentials_file=None, + scopes=("https://www.googleapis.com/auth/cloud-platform",), + ssl_credentials=mock_ssl_cred, + quota_project_id=None, + ) + assert transport.grpc_channel == mock_grpc_channel def test_auto_ml_grpc_lro_client(): @@ -6489,6 +6506,41 @@ def test_auto_ml_grpc_lro_async_client(): assert transport.operations_client is transport.operations_client +def test_column_spec_path(): + project = "squid" + location = "clam" + dataset = "whelk" + table_spec = "octopus" + column_spec = "oyster" + + expected = "projects/{project}/locations/{location}/datasets/{dataset}/tableSpecs/{table_spec}/columnSpecs/{column_spec}".format( + project=project, + location=location, + dataset=dataset, + table_spec=table_spec, + column_spec=column_spec, + ) + actual = AutoMlClient.column_spec_path( + project, location, dataset, table_spec, column_spec + ) + assert expected == actual + + +def test_parse_column_spec_path(): + expected = { + "project": "nudibranch", + "location": "cuttlefish", + "dataset": "mussel", + "table_spec": "winkle", + "column_spec": "nautilus", + } + path = AutoMlClient.column_spec_path(**expected) + + # Check that the path construction is reversible. + actual = AutoMlClient.parse_column_spec_path(path) + assert expected == actual + + def test_dataset_path(): project = "squid" location = "clam" @@ -6539,41 +6591,6 @@ def test_parse_model_path(): assert expected == actual -def test_column_spec_path(): - project = "squid" - location = "clam" - dataset = "whelk" - table_spec = "octopus" - column_spec = "oyster" - - expected = "projects/{project}/locations/{location}/datasets/{dataset}/tableSpecs/{table_spec}/columnSpecs/{column_spec}".format( - project=project, - location=location, - dataset=dataset, - table_spec=table_spec, - column_spec=column_spec, - ) - actual = AutoMlClient.column_spec_path( - project, location, dataset, table_spec, column_spec - ) - assert expected == actual - - -def test_parse_column_spec_path(): - expected = { - "project": "nudibranch", - "location": "cuttlefish", - "dataset": "mussel", - "table_spec": "winkle", - "column_spec": "nautilus", - } - path = AutoMlClient.column_spec_path(**expected) - - # Check that the path construction is reversible. - actual = AutoMlClient.parse_column_spec_path(path) - assert expected == actual - - def test_table_spec_path(): project = "squid" location = "clam" diff --git a/tests/unit/gapic/automl_v1beta1/test_prediction_service.py b/tests/unit/gapic/automl_v1beta1/test_prediction_service.py index c21f17b9..44c966c5 100644 --- a/tests/unit/gapic/automl_v1beta1/test_prediction_service.py +++ b/tests/unit/gapic/automl_v1beta1/test_prediction_service.py @@ -31,7 +31,7 @@ from google.api_core import gapic_v1 from google.api_core import grpc_helpers from google.api_core import grpc_helpers_async -from google.api_core import operation_async +from google.api_core import operation_async # type: ignore from google.api_core import operations_v1 from google.auth import credentials from google.auth.exceptions import MutualTLSChannelError @@ -170,15 +170,14 @@ def test_prediction_service_client_client_options( credentials_file=None, host="squid.clam.whelk", scopes=None, - api_mtls_endpoint="squid.clam.whelk", - client_cert_source=None, + ssl_channel_credentials=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) - # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS is + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT is # "never". - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS": "never"}): + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}): with mock.patch.object(transport_class, "__init__") as patched: patched.return_value = None client = client_class() @@ -187,15 +186,14 @@ def test_prediction_service_client_client_options( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=None, - api_mtls_endpoint=client.DEFAULT_ENDPOINT, - client_cert_source=None, + ssl_channel_credentials=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) - # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS is + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT is # "always". - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS": "always"}): + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}): with mock.patch.object(transport_class, "__init__") as patched: patched.return_value = None client = client_class() @@ -204,95 +202,185 @@ def test_prediction_service_client_client_options( credentials_file=None, host=client.DEFAULT_MTLS_ENDPOINT, scopes=None, - api_mtls_endpoint=client.DEFAULT_MTLS_ENDPOINT, - client_cert_source=None, + ssl_channel_credentials=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) - # Check the case api_endpoint is not provided, GOOGLE_API_USE_MTLS is - # "auto", and client_cert_source is provided. - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS": "auto"}): + # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS_ENDPOINT has + # unsupported value. + with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "Unsupported"}): + with pytest.raises(MutualTLSChannelError): + client = client_class() + + # Check the case GOOGLE_API_USE_CLIENT_CERTIFICATE has unsupported value. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"} + ): + with pytest.raises(ValueError): + client = client_class() + + # Check the case quota_project_id is provided + options = client_options.ClientOptions(quota_project_id="octopus") + with mock.patch.object(transport_class, "__init__") as patched: + patched.return_value = None + client = client_class(client_options=options) + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=None, + ssl_channel_credentials=None, + quota_project_id="octopus", + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) + + +@pytest.mark.parametrize( + "client_class,transport_class,transport_name,use_client_cert_env", + [ + ( + PredictionServiceClient, + transports.PredictionServiceGrpcTransport, + "grpc", + "true", + ), + ( + PredictionServiceAsyncClient, + transports.PredictionServiceGrpcAsyncIOTransport, + "grpc_asyncio", + "true", + ), + ( + PredictionServiceClient, + transports.PredictionServiceGrpcTransport, + "grpc", + "false", + ), + ( + PredictionServiceAsyncClient, + transports.PredictionServiceGrpcAsyncIOTransport, + "grpc_asyncio", + "false", + ), + ], +) +@mock.patch.object( + PredictionServiceClient, + "DEFAULT_ENDPOINT", + modify_default_endpoint(PredictionServiceClient), +) +@mock.patch.object( + PredictionServiceAsyncClient, + "DEFAULT_ENDPOINT", + modify_default_endpoint(PredictionServiceAsyncClient), +) +@mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "auto"}) +def test_prediction_service_client_mtls_env_auto( + client_class, transport_class, transport_name, use_client_cert_env +): + # This tests the endpoint autoswitch behavior. Endpoint is autoswitched to the default + # mtls endpoint, if GOOGLE_API_USE_CLIENT_CERTIFICATE is "true" and client cert exists. + + # Check the case client_cert_source is provided. Whether client cert is used depends on + # GOOGLE_API_USE_CLIENT_CERTIFICATE value. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env} + ): options = client_options.ClientOptions( client_cert_source=client_cert_source_callback ) with mock.patch.object(transport_class, "__init__") as patched: - patched.return_value = None - client = client_class(client_options=options) - patched.assert_called_once_with( - credentials=None, - credentials_file=None, - host=client.DEFAULT_MTLS_ENDPOINT, - scopes=None, - api_mtls_endpoint=client.DEFAULT_MTLS_ENDPOINT, - client_cert_source=client_cert_source_callback, - quota_project_id=None, - client_info=transports.base.DEFAULT_CLIENT_INFO, - ) - - # Check the case api_endpoint is not provided, GOOGLE_API_USE_MTLS is - # "auto", and default_client_cert_source is provided. - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS": "auto"}): - with mock.patch.object(transport_class, "__init__") as patched: + ssl_channel_creds = mock.Mock() with mock.patch( - "google.auth.transport.mtls.has_default_client_cert_source", - return_value=True, + "grpc.ssl_channel_credentials", return_value=ssl_channel_creds ): patched.return_value = None - client = client_class() + client = client_class(client_options=options) + + if use_client_cert_env == "false": + expected_ssl_channel_creds = None + expected_host = client.DEFAULT_ENDPOINT + else: + expected_ssl_channel_creds = ssl_channel_creds + expected_host = client.DEFAULT_MTLS_ENDPOINT + patched.assert_called_once_with( credentials=None, credentials_file=None, - host=client.DEFAULT_MTLS_ENDPOINT, + host=expected_host, scopes=None, - api_mtls_endpoint=client.DEFAULT_MTLS_ENDPOINT, - client_cert_source=None, + ssl_channel_credentials=expected_ssl_channel_creds, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) - # Check the case api_endpoint is not provided, GOOGLE_API_USE_MTLS is - # "auto", but client_cert_source and default_client_cert_source are None. - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS": "auto"}): + # Check the case ADC client cert is provided. Whether client cert is used depends on + # GOOGLE_API_USE_CLIENT_CERTIFICATE value. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env} + ): with mock.patch.object(transport_class, "__init__") as patched: with mock.patch( - "google.auth.transport.mtls.has_default_client_cert_source", - return_value=False, + "google.auth.transport.grpc.SslCredentials.__init__", return_value=None ): - patched.return_value = None - client = client_class() - patched.assert_called_once_with( - credentials=None, - credentials_file=None, - host=client.DEFAULT_ENDPOINT, - scopes=None, - api_mtls_endpoint=client.DEFAULT_ENDPOINT, - client_cert_source=None, - quota_project_id=None, - client_info=transports.base.DEFAULT_CLIENT_INFO, - ) - - # Check the case api_endpoint is not provided and GOOGLE_API_USE_MTLS has - # unsupported value. - with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS": "Unsupported"}): - with pytest.raises(MutualTLSChannelError): - client = client_class() - - # Check the case quota_project_id is provided - options = client_options.ClientOptions(quota_project_id="octopus") - with mock.patch.object(transport_class, "__init__") as patched: - patched.return_value = None - client = client_class(client_options=options) - patched.assert_called_once_with( - credentials=None, - credentials_file=None, - host=client.DEFAULT_ENDPOINT, - scopes=None, - api_mtls_endpoint=client.DEFAULT_ENDPOINT, - client_cert_source=None, - quota_project_id="octopus", - client_info=transports.base.DEFAULT_CLIENT_INFO, - ) + with mock.patch( + "google.auth.transport.grpc.SslCredentials.is_mtls", + new_callable=mock.PropertyMock, + ) as is_mtls_mock: + with mock.patch( + "google.auth.transport.grpc.SslCredentials.ssl_credentials", + new_callable=mock.PropertyMock, + ) as ssl_credentials_mock: + if use_client_cert_env == "false": + is_mtls_mock.return_value = False + ssl_credentials_mock.return_value = None + expected_host = client.DEFAULT_ENDPOINT + expected_ssl_channel_creds = None + else: + is_mtls_mock.return_value = True + ssl_credentials_mock.return_value = mock.Mock() + expected_host = client.DEFAULT_MTLS_ENDPOINT + expected_ssl_channel_creds = ( + ssl_credentials_mock.return_value + ) + + patched.return_value = None + client = client_class() + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=expected_host, + scopes=None, + ssl_channel_credentials=expected_ssl_channel_creds, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) + + # Check the case client_cert_source and ADC client cert are not provided. + with mock.patch.dict( + os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": use_client_cert_env} + ): + with mock.patch.object(transport_class, "__init__") as patched: + with mock.patch( + "google.auth.transport.grpc.SslCredentials.__init__", return_value=None + ): + with mock.patch( + "google.auth.transport.grpc.SslCredentials.is_mtls", + new_callable=mock.PropertyMock, + ) as is_mtls_mock: + is_mtls_mock.return_value = False + patched.return_value = None + client = client_class() + patched.assert_called_once_with( + credentials=None, + credentials_file=None, + host=client.DEFAULT_ENDPOINT, + scopes=None, + ssl_channel_credentials=None, + quota_project_id=None, + client_info=transports.base.DEFAULT_CLIENT_INFO, + ) @pytest.mark.parametrize( @@ -319,8 +407,7 @@ def test_prediction_service_client_client_options_scopes( credentials_file=None, host=client.DEFAULT_ENDPOINT, scopes=["1", "2"], - api_mtls_endpoint=client.DEFAULT_ENDPOINT, - client_cert_source=None, + ssl_channel_credentials=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -350,8 +437,7 @@ def test_prediction_service_client_client_options_credentials_file( credentials_file="credentials.json", host=client.DEFAULT_ENDPOINT, scopes=None, - api_mtls_endpoint=client.DEFAULT_ENDPOINT, - client_cert_source=None, + ssl_channel_credentials=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -370,8 +456,7 @@ def test_prediction_service_client_client_options_from_dict(): credentials_file=None, host="squid.clam.whelk", scopes=None, - api_mtls_endpoint="squid.clam.whelk", - client_cert_source=None, + ssl_channel_credentials=None, quota_project_id=None, client_info=transports.base.DEFAULT_CLIENT_INFO, ) @@ -907,6 +992,21 @@ def test_transport_get_channel(): assert channel +@pytest.mark.parametrize( + "transport_class", + [ + transports.PredictionServiceGrpcTransport, + transports.PredictionServiceGrpcAsyncIOTransport, + ], +) +def test_transport_adc(transport_class): + # Test default credentials are used if not provided. + with mock.patch.object(auth, "default") as adc: + adc.return_value = (credentials.AnonymousCredentials(), None) + transport_class() + adc.assert_called_once() + + def test_transport_grpc_default(): # A client should use the gRPC transport by default. client = PredictionServiceClient(credentials=credentials.AnonymousCredentials(),) @@ -967,6 +1067,17 @@ def test_prediction_service_base_transport_with_credentials_file(): ) +def test_prediction_service_base_transport_with_adc(): + # Test the default credentials are used if credentials and credentials_file are None. + with mock.patch.object(auth, "default") as adc, mock.patch( + "google.cloud.automl_v1beta1.services.prediction_service.transports.PredictionServiceTransport._prep_wrapped_messages" + ) as Transport: + Transport.return_value = None + adc.return_value = (credentials.AnonymousCredentials(), None) + transport = transports.PredictionServiceTransport() + adc.assert_called_once() + + def test_prediction_service_auth_adc(): # If no credentials are provided, we should use ADC credentials. with mock.patch.object(auth, "default") as adc: @@ -1015,179 +1126,110 @@ def test_prediction_service_host_with_port(): def test_prediction_service_grpc_transport_channel(): channel = grpc.insecure_channel("http://localhost/") - # Check that if channel is provided, mtls endpoint and client_cert_source - # won't be used. - callback = mock.MagicMock() + # Check that channel is used if provided. transport = transports.PredictionServiceGrpcTransport( - host="squid.clam.whelk", - channel=channel, - api_mtls_endpoint="mtls.squid.clam.whelk", - client_cert_source=callback, + host="squid.clam.whelk", channel=channel, ) assert transport.grpc_channel == channel assert transport._host == "squid.clam.whelk:443" - assert not callback.called def test_prediction_service_grpc_asyncio_transport_channel(): channel = aio.insecure_channel("http://localhost/") - # Check that if channel is provided, mtls endpoint and client_cert_source - # won't be used. - callback = mock.MagicMock() + # Check that channel is used if provided. transport = transports.PredictionServiceGrpcAsyncIOTransport( - host="squid.clam.whelk", - channel=channel, - api_mtls_endpoint="mtls.squid.clam.whelk", - client_cert_source=callback, + host="squid.clam.whelk", channel=channel, ) assert transport.grpc_channel == channel assert transport._host == "squid.clam.whelk:443" - assert not callback.called - - -@mock.patch("grpc.ssl_channel_credentials", autospec=True) -@mock.patch("google.api_core.grpc_helpers.create_channel", autospec=True) -def test_prediction_service_grpc_transport_channel_mtls_with_client_cert_source( - grpc_create_channel, grpc_ssl_channel_cred -): - # Check that if channel is None, but api_mtls_endpoint and client_cert_source - # are provided, then a mTLS channel will be created. - mock_cred = mock.Mock() - - mock_ssl_cred = mock.Mock() - grpc_ssl_channel_cred.return_value = mock_ssl_cred - - mock_grpc_channel = mock.Mock() - grpc_create_channel.return_value = mock_grpc_channel - - transport = transports.PredictionServiceGrpcTransport( - host="squid.clam.whelk", - credentials=mock_cred, - api_mtls_endpoint="mtls.squid.clam.whelk", - client_cert_source=client_cert_source_callback, - ) - grpc_ssl_channel_cred.assert_called_once_with( - certificate_chain=b"cert bytes", private_key=b"key bytes" - ) - grpc_create_channel.assert_called_once_with( - "mtls.squid.clam.whelk:443", - credentials=mock_cred, - credentials_file=None, - scopes=("https://www.googleapis.com/auth/cloud-platform",), - ssl_credentials=mock_ssl_cred, - quota_project_id=None, - ) - assert transport.grpc_channel == mock_grpc_channel - - -@mock.patch("grpc.ssl_channel_credentials", autospec=True) -@mock.patch("google.api_core.grpc_helpers_async.create_channel", autospec=True) -def test_prediction_service_grpc_asyncio_transport_channel_mtls_with_client_cert_source( - grpc_create_channel, grpc_ssl_channel_cred -): - # Check that if channel is None, but api_mtls_endpoint and client_cert_source - # are provided, then a mTLS channel will be created. - mock_cred = mock.Mock() - - mock_ssl_cred = mock.Mock() - grpc_ssl_channel_cred.return_value = mock_ssl_cred - - mock_grpc_channel = mock.Mock() - grpc_create_channel.return_value = mock_grpc_channel - - transport = transports.PredictionServiceGrpcAsyncIOTransport( - host="squid.clam.whelk", - credentials=mock_cred, - api_mtls_endpoint="mtls.squid.clam.whelk", - client_cert_source=client_cert_source_callback, - ) - grpc_ssl_channel_cred.assert_called_once_with( - certificate_chain=b"cert bytes", private_key=b"key bytes" - ) - grpc_create_channel.assert_called_once_with( - "mtls.squid.clam.whelk:443", - credentials=mock_cred, - credentials_file=None, - scopes=("https://www.googleapis.com/auth/cloud-platform",), - ssl_credentials=mock_ssl_cred, - quota_project_id=None, - ) - assert transport.grpc_channel == mock_grpc_channel @pytest.mark.parametrize( - "api_mtls_endpoint", ["mtls.squid.clam.whelk", "mtls.squid.clam.whelk:443"] + "transport_class", + [ + transports.PredictionServiceGrpcTransport, + transports.PredictionServiceGrpcAsyncIOTransport, + ], ) -@mock.patch("google.api_core.grpc_helpers.create_channel", autospec=True) -def test_prediction_service_grpc_transport_channel_mtls_with_adc( - grpc_create_channel, api_mtls_endpoint +def test_prediction_service_transport_channel_mtls_with_client_cert_source( + transport_class, ): - # Check that if channel and client_cert_source are None, but api_mtls_endpoint - # is provided, then a mTLS channel will be created with SSL ADC. - mock_grpc_channel = mock.Mock() - grpc_create_channel.return_value = mock_grpc_channel - - # Mock google.auth.transport.grpc.SslCredentials class. - mock_ssl_cred = mock.Mock() - with mock.patch.multiple( - "google.auth.transport.grpc.SslCredentials", - __init__=mock.Mock(return_value=None), - ssl_credentials=mock.PropertyMock(return_value=mock_ssl_cred), - ): - mock_cred = mock.Mock() - transport = transports.PredictionServiceGrpcTransport( - host="squid.clam.whelk", - credentials=mock_cred, - api_mtls_endpoint=api_mtls_endpoint, - client_cert_source=None, - ) - grpc_create_channel.assert_called_once_with( - "mtls.squid.clam.whelk:443", - credentials=mock_cred, - credentials_file=None, - scopes=("https://www.googleapis.com/auth/cloud-platform",), - ssl_credentials=mock_ssl_cred, - quota_project_id=None, - ) - assert transport.grpc_channel == mock_grpc_channel + with mock.patch( + "grpc.ssl_channel_credentials", autospec=True + ) as grpc_ssl_channel_cred: + with mock.patch.object( + transport_class, "create_channel", autospec=True + ) as grpc_create_channel: + mock_ssl_cred = mock.Mock() + grpc_ssl_channel_cred.return_value = mock_ssl_cred + + mock_grpc_channel = mock.Mock() + grpc_create_channel.return_value = mock_grpc_channel + + cred = credentials.AnonymousCredentials() + with pytest.warns(DeprecationWarning): + with mock.patch.object(auth, "default") as adc: + adc.return_value = (cred, None) + transport = transport_class( + host="squid.clam.whelk", + api_mtls_endpoint="mtls.squid.clam.whelk", + client_cert_source=client_cert_source_callback, + ) + adc.assert_called_once() + + grpc_ssl_channel_cred.assert_called_once_with( + certificate_chain=b"cert bytes", private_key=b"key bytes" + ) + grpc_create_channel.assert_called_once_with( + "mtls.squid.clam.whelk:443", + credentials=cred, + credentials_file=None, + scopes=("https://www.googleapis.com/auth/cloud-platform",), + ssl_credentials=mock_ssl_cred, + quota_project_id=None, + ) + assert transport.grpc_channel == mock_grpc_channel @pytest.mark.parametrize( - "api_mtls_endpoint", ["mtls.squid.clam.whelk", "mtls.squid.clam.whelk:443"] + "transport_class", + [ + transports.PredictionServiceGrpcTransport, + transports.PredictionServiceGrpcAsyncIOTransport, + ], ) -@mock.patch("google.api_core.grpc_helpers_async.create_channel", autospec=True) -def test_prediction_service_grpc_asyncio_transport_channel_mtls_with_adc( - grpc_create_channel, api_mtls_endpoint -): - # Check that if channel and client_cert_source are None, but api_mtls_endpoint - # is provided, then a mTLS channel will be created with SSL ADC. - mock_grpc_channel = mock.Mock() - grpc_create_channel.return_value = mock_grpc_channel - - # Mock google.auth.transport.grpc.SslCredentials class. +def test_prediction_service_transport_channel_mtls_with_adc(transport_class): mock_ssl_cred = mock.Mock() with mock.patch.multiple( "google.auth.transport.grpc.SslCredentials", __init__=mock.Mock(return_value=None), ssl_credentials=mock.PropertyMock(return_value=mock_ssl_cred), ): - mock_cred = mock.Mock() - transport = transports.PredictionServiceGrpcAsyncIOTransport( - host="squid.clam.whelk", - credentials=mock_cred, - api_mtls_endpoint=api_mtls_endpoint, - client_cert_source=None, - ) - grpc_create_channel.assert_called_once_with( - "mtls.squid.clam.whelk:443", - credentials=mock_cred, - credentials_file=None, - scopes=("https://www.googleapis.com/auth/cloud-platform",), - ssl_credentials=mock_ssl_cred, - quota_project_id=None, - ) - assert transport.grpc_channel == mock_grpc_channel + with mock.patch.object( + transport_class, "create_channel", autospec=True + ) as grpc_create_channel: + mock_grpc_channel = mock.Mock() + grpc_create_channel.return_value = mock_grpc_channel + mock_cred = mock.Mock() + + with pytest.warns(DeprecationWarning): + transport = transport_class( + host="squid.clam.whelk", + credentials=mock_cred, + api_mtls_endpoint="mtls.squid.clam.whelk", + client_cert_source=None, + ) + + grpc_create_channel.assert_called_once_with( + "mtls.squid.clam.whelk:443", + credentials=mock_cred, + credentials_file=None, + scopes=("https://www.googleapis.com/auth/cloud-platform",), + ssl_credentials=mock_ssl_cred, + quota_project_id=None, + ) + assert transport.grpc_channel == mock_grpc_channel def test_prediction_service_grpc_lro_client():