From abb0ac0e062f1032ca2b3d5e5053847846769b59 Mon Sep 17 00:00:00 2001 From: Jon Wayne Parrott Date: Thu, 21 Sep 2017 14:30:12 -0700 Subject: [PATCH 1/3] Add google.api.core.gapic_v1.config --- core/google/api/core/gapic_v1/__init__.py | 0 core/google/api/core/gapic_v1/config.py | 139 ++++++++++++++++++ core/tests/unit/api_core/gapic/test_config.py | 92 ++++++++++++ 3 files changed, 231 insertions(+) create mode 100644 core/google/api/core/gapic_v1/__init__.py create mode 100644 core/google/api/core/gapic_v1/config.py create mode 100644 core/tests/unit/api_core/gapic/test_config.py diff --git a/core/google/api/core/gapic_v1/__init__.py b/core/google/api/core/gapic_v1/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/core/google/api/core/gapic_v1/config.py b/core/google/api/core/gapic_v1/config.py new file mode 100644 index 000000000000..21856ae1a9c6 --- /dev/null +++ b/core/google/api/core/gapic_v1/config.py @@ -0,0 +1,139 @@ +# Copyright 2017 Google Inc. +# +# 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. + +"""Helpers for loading gapic configuration data. + +The Google API generator creates supplementary configuration for each RPC +method to tell the client library how to deal with retries and timeouts. +""" + +import collections + +import grpc +import six + +from google.api.core import exceptions + + +_MILLIS_PER_SECOND = 1000.0 + + +MethodConfig = collections.namedtuple('MethodConfig', [ + 'timeout', +]) + +RetryableMethodConfig = collections.namedtuple('RetryableMethodConfig', [ + # Retry settings + 'retry_exceptions', + 'initial_delay', + 'delay_multiplier', + 'max_delay', + 'deadline', + # Timeout settings + 'initial_timeout', + 'timeout_multiplier', + 'max_timeout', +]) + + +def _exception_class_for_grpc_status_name(name): + """Returns the Google API exception class for a gRPC error code name.""" + return exceptions.exception_class_for_grpc_status( + getattr(grpc.StatusCode, name)) + + +def _make_retryable_config(retry_params, retry_codes): + """Creates a retryable method configuration. + + Args: + retry_params (dict): The retry parameter values, for example:: + + { + "initial_retry_delay_millis": 1000, + "retry_delay_multiplier": 2.5, + "max_retry_delay_millis": 120000, + "initial_rpc_timeout_millis": 120000, + "rpc_timeout_multiplier": 1.0, + "max_rpc_timeout_millis": 120000, + "total_timeout_millis": 600000 + } + + retry_codes (sequence[str]): The list of retryable gRPC error code + names. + + Returns: + RetryableMethodConfig: Configuration for the method. + """ + return RetryableMethodConfig( + retry_exceptions=[ + _exception_class_for_grpc_status_name(code) + for code in retry_codes], + initial_delay=( + retry_params['initial_retry_delay_millis'] / _MILLIS_PER_SECOND), + delay_multiplier=retry_params['retry_delay_multiplier'], + max_delay=( + retry_params['max_retry_delay_millis'] / _MILLIS_PER_SECOND), + deadline=( + retry_params['total_timeout_millis'] / _MILLIS_PER_SECOND), + initial_timeout=( + retry_params['initial_rpc_timeout_millis'] / _MILLIS_PER_SECOND), + timeout_multiplier=retry_params['rpc_timeout_multiplier'], + max_timeout=( + retry_params['max_rpc_timeout_millis'] / _MILLIS_PER_SECOND), + ) + + +def create_method_configs(interface_config): + """Creates method configs for each method in a gapic interface config. + + Args: + interface_config (Mapping): The interface config section of the full + gapic library config. For example, + ``gapic_config['interfaces']['google.example.v1.ExampleService']``. + + Returns: + Mapping[str, Union[MethodConfig, RetryableMethodConfig]]: A mapping + of RPC method names to their associated parsed configuration. + """ + # Grab all the retry codes + retry_codes_map = { + name: retry_codes + for name, retry_codes + in six.iteritems(interface_config.get('retry_codes', {})) + } + + # Grab all of the retry params + retry_params_map = { + name: retry_params + for name, retry_params + in six.iteritems(interface_config.get('retry_params', {})) + } + + # Iterate through all the API methods and create a flat MethodConfig + # instance for each one. + method_configs = {} + for method_name, method_params in six.iteritems( + interface_config.get('methods', {})): + retry_params_name = method_params.get('retry_params_name') + if retry_params_name is not None: + config = _make_retryable_config( + retry_params_map[retry_params_name], + retry_codes_map[method_params['retry_codes_name']]) + else: + config = MethodConfig( + timeout=method_params['timeout_millis'] / _MILLIS_PER_SECOND) + + method_configs[method_name] = config + + return method_configs diff --git a/core/tests/unit/api_core/gapic/test_config.py b/core/tests/unit/api_core/gapic/test_config.py new file mode 100644 index 000000000000..78c3f4980537 --- /dev/null +++ b/core/tests/unit/api_core/gapic/test_config.py @@ -0,0 +1,92 @@ +# Copyright 2017 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from google.api.core import exceptions +from google.api.core.gapic_v1 import config + + +INTERFACE_CONFIG = { + 'retry_codes': { + 'idempotent': ['DEADLINE_EXCEEDED', 'UNAVAILABLE'], + 'other': ['FAILED_PRECONDITION'], + 'non_idempotent': [] + }, + 'retry_params': { + 'default': { + 'initial_retry_delay_millis': 1000, + 'retry_delay_multiplier': 2.5, + 'max_retry_delay_millis': 120000, + 'initial_rpc_timeout_millis': 120000, + 'rpc_timeout_multiplier': 1.0, + 'max_rpc_timeout_millis': 120000, + 'total_timeout_millis': 600000 + }, + 'other': { + 'initial_retry_delay_millis': 1000, + 'retry_delay_multiplier': 1, + 'max_retry_delay_millis': 1000, + 'initial_rpc_timeout_millis': 1000, + 'rpc_timeout_multiplier': 1, + 'max_rpc_timeout_millis': 1000, + 'total_timeout_millis': 1000 + }, + }, + 'methods': { + 'AnnotateVideo': { + 'timeout_millis': 60000, + 'retry_codes_name': 'idempotent', + 'retry_params_name': 'default' + }, + 'Other': { + 'timeout_millis': 60000, + 'retry_codes_name': 'other', + 'retry_params_name': 'other' + }, + 'Plain': { + 'timeout_millis': 30000 + } + } +} + + +def test_create_method_configs(): + method_configs = config.create_method_configs(INTERFACE_CONFIG) + + annotate_video_config = method_configs['AnnotateVideo'] + assert isinstance(annotate_video_config, config.RetryableMethodConfig) + assert annotate_video_config.retry_exceptions == [ + exceptions.DeadlineExceeded, exceptions.ServiceUnavailable] + assert annotate_video_config.initial_delay == 1.0 + assert annotate_video_config.delay_multiplier == 2.5 + assert annotate_video_config.max_delay == 120.0 + assert annotate_video_config.deadline == 600.0 + assert annotate_video_config.initial_timeout == 120.0 + assert annotate_video_config.timeout_multiplier == 1.0 + assert annotate_video_config.max_timeout == 120.0 + + other_config = method_configs['Other'] + assert isinstance(annotate_video_config, config.RetryableMethodConfig) + assert other_config.retry_exceptions == [ + exceptions.FailedPrecondition] + assert other_config.initial_delay == 1.0 + assert other_config.delay_multiplier == 1.0 + assert other_config.max_delay == 1.0 + assert other_config.deadline == 1.0 + assert other_config.initial_timeout == 1.0 + assert other_config.timeout_multiplier == 1.0 + assert other_config.max_timeout == 1.0 + + plain_config = method_configs['Plain'] + assert isinstance(plain_config, config.MethodConfig) + assert plain_config.timeout == 30.0 From 3fa982b72dc1ddbfd1ed6538b9c7ed0fa6119761 Mon Sep 17 00:00:00 2001 From: Jon Wayne Parrott Date: Thu, 21 Sep 2017 15:07:27 -0700 Subject: [PATCH 2/3] Just return full objects --- core/google/api/core/gapic_v1/config.py | 118 +++++++++++------- core/tests/unit/api_core/gapic/test_config.py | 49 ++++---- .../video_intelligence_service_client.py | 92 +++++++------- 3 files changed, 147 insertions(+), 112 deletions(-) diff --git a/core/google/api/core/gapic_v1/config.py b/core/google/api/core/gapic_v1/config.py index 21856ae1a9c6..06d089e67407 100644 --- a/core/google/api/core/gapic_v1/config.py +++ b/core/google/api/core/gapic_v1/config.py @@ -24,37 +24,30 @@ import six from google.api.core import exceptions +from google.api.core import retry +from google.api.core import timeout _MILLIS_PER_SECOND = 1000.0 -MethodConfig = collections.namedtuple('MethodConfig', [ - 'timeout', -]) - -RetryableMethodConfig = collections.namedtuple('RetryableMethodConfig', [ - # Retry settings - 'retry_exceptions', - 'initial_delay', - 'delay_multiplier', - 'max_delay', - 'deadline', - # Timeout settings - 'initial_timeout', - 'timeout_multiplier', - 'max_timeout', -]) +def _exception_class_for_grpc_status_name(name): + """Returns the Google API exception class for a gRPC error code name. + Args: + name (str): The name of the gRPC status code, for example, + ``UNAVAILABLE``. -def _exception_class_for_grpc_status_name(name): - """Returns the Google API exception class for a gRPC error code name.""" + Returns: + type: The appropriate subclass of + :class:`google.api.core.exceptions.GoogleAPICallError`. + """ return exceptions.exception_class_for_grpc_status( getattr(grpc.StatusCode, name)) -def _make_retryable_config(retry_params, retry_codes): - """Creates a retryable method configuration. +def _retry_from_retry_config(retry_params, retry_codes): + """Creates a Retry object given a gapic retry configuration. Args: retry_params (dict): The retry parameter values, for example:: @@ -73,38 +66,67 @@ def _make_retryable_config(retry_params, retry_codes): names. Returns: - RetryableMethodConfig: Configuration for the method. + google.api.core.retry.Retry: The default retry object for the method. """ - return RetryableMethodConfig( - retry_exceptions=[ - _exception_class_for_grpc_status_name(code) - for code in retry_codes], - initial_delay=( + exception_classes = [ + _exception_class_for_grpc_status_name(code) for code in retry_codes] + return retry.Retry( + retry.if_exception_type(*exception_classes), + initial=( retry_params['initial_retry_delay_millis'] / _MILLIS_PER_SECOND), - delay_multiplier=retry_params['retry_delay_multiplier'], - max_delay=( + maximum=( retry_params['max_retry_delay_millis'] / _MILLIS_PER_SECOND), - deadline=( - retry_params['total_timeout_millis'] / _MILLIS_PER_SECOND), - initial_timeout=( + multiplier=retry_params['retry_delay_multiplier'], + deadline=retry_params['total_timeout_millis'] / _MILLIS_PER_SECOND) + + +def _timeout_from_retry_config(retry_params): + """Creates a ExponentialTimeout object given a gapic retry configuration. + + Args: + retry_params (dict): The retry parameter values, for example:: + + { + "initial_retry_delay_millis": 1000, + "retry_delay_multiplier": 2.5, + "max_retry_delay_millis": 120000, + "initial_rpc_timeout_millis": 120000, + "rpc_timeout_multiplier": 1.0, + "max_rpc_timeout_millis": 120000, + "total_timeout_millis": 600000 + } + + Returns: + google.api.core.retry.ExponentialTimeout: The default time object for + the method. + """ + return timeout.ExponentialTimeout( + initial=( retry_params['initial_rpc_timeout_millis'] / _MILLIS_PER_SECOND), - timeout_multiplier=retry_params['rpc_timeout_multiplier'], - max_timeout=( + maximum=( retry_params['max_rpc_timeout_millis'] / _MILLIS_PER_SECOND), - ) + multiplier=retry_params['rpc_timeout_multiplier'], + deadline=( + retry_params['total_timeout_millis'] / _MILLIS_PER_SECOND)) + + +MethodConfig = collections.namedtuple('MethodConfig', ['retry', 'timeout']) -def create_method_configs(interface_config): - """Creates method configs for each method in a gapic interface config. +def parse_method_configs(interface_config): + """Creates default retry and timeout objects for each method in a gapic + interface config. Args: interface_config (Mapping): The interface config section of the full - gapic library config. For example, + gapic library config. For example, If the full configuration has + an interface named ``google.example.v1.ExampleService`` you would + pass in just that interface's configuration, for example ``gapic_config['interfaces']['google.example.v1.ExampleService']``. Returns: - Mapping[str, Union[MethodConfig, RetryableMethodConfig]]: A mapping - of RPC method names to their associated parsed configuration. + Mapping[str, MethodConfig]: A mapping of RPC method names to their + configuration. """ # Grab all the retry codes retry_codes_map = { @@ -123,17 +145,25 @@ def create_method_configs(interface_config): # Iterate through all the API methods and create a flat MethodConfig # instance for each one. method_configs = {} + for method_name, method_params in six.iteritems( interface_config.get('methods', {})): retry_params_name = method_params.get('retry_params_name') + if retry_params_name is not None: - config = _make_retryable_config( - retry_params_map[retry_params_name], + retry_params = retry_params_map[retry_params_name] + retry_ = _retry_from_retry_config( + retry_params, retry_codes_map[method_params['retry_codes_name']]) + timeout_ = _timeout_from_retry_config(retry_params) + + # No retry config, so this is a non-retryable method. else: - config = MethodConfig( - timeout=method_params['timeout_millis'] / _MILLIS_PER_SECOND) + retry_ = None + timeout_ = timeout.ConstantTimeout( + method_params['timeout_millis'] / _MILLIS_PER_SECOND) - method_configs[method_name] = config + method_configs[method_name] = MethodConfig( + retry=retry_, timeout=timeout_) return method_configs diff --git a/core/tests/unit/api_core/gapic/test_config.py b/core/tests/unit/api_core/gapic/test_config.py index 78c3f4980537..ece5dd6344de 100644 --- a/core/tests/unit/api_core/gapic/test_config.py +++ b/core/tests/unit/api_core/gapic/test_config.py @@ -61,32 +61,29 @@ def test_create_method_configs(): - method_configs = config.create_method_configs(INTERFACE_CONFIG) + method_configs = config.parse_method_configs(INTERFACE_CONFIG) - annotate_video_config = method_configs['AnnotateVideo'] - assert isinstance(annotate_video_config, config.RetryableMethodConfig) - assert annotate_video_config.retry_exceptions == [ - exceptions.DeadlineExceeded, exceptions.ServiceUnavailable] - assert annotate_video_config.initial_delay == 1.0 - assert annotate_video_config.delay_multiplier == 2.5 - assert annotate_video_config.max_delay == 120.0 - assert annotate_video_config.deadline == 600.0 - assert annotate_video_config.initial_timeout == 120.0 - assert annotate_video_config.timeout_multiplier == 1.0 - assert annotate_video_config.max_timeout == 120.0 + retry, timeout = method_configs['AnnotateVideo'] + assert retry._predicate(exceptions.DeadlineExceeded(None)) + assert retry._predicate(exceptions.ServiceUnavailable(None)) + assert retry._initial == 1.0 + assert retry._multiplier == 2.5 + assert retry._maximum == 120.0 + assert retry._deadline == 600.0 + assert timeout._initial == 120.0 + assert timeout._multiplier == 1.0 + assert timeout._maximum == 120.0 - other_config = method_configs['Other'] - assert isinstance(annotate_video_config, config.RetryableMethodConfig) - assert other_config.retry_exceptions == [ - exceptions.FailedPrecondition] - assert other_config.initial_delay == 1.0 - assert other_config.delay_multiplier == 1.0 - assert other_config.max_delay == 1.0 - assert other_config.deadline == 1.0 - assert other_config.initial_timeout == 1.0 - assert other_config.timeout_multiplier == 1.0 - assert other_config.max_timeout == 1.0 + retry, timeout = method_configs['Other'] + assert retry._predicate(exceptions.FailedPrecondition(None)) + assert retry._initial == 1.0 + assert retry._multiplier == 1.0 + assert retry._maximum == 1.0 + assert retry._deadline == 1.0 + assert timeout._initial == 1.0 + assert timeout._multiplier == 1.0 + assert timeout._maximum == 1.0 - plain_config = method_configs['Plain'] - assert isinstance(plain_config, config.MethodConfig) - assert plain_config.timeout == 30.0 + retry, timeout = method_configs['Plain'] + assert retry is None + assert timeout._timeout == 30.0 diff --git a/videointelligence/google/cloud/videointelligence_v1beta2/gapic/video_intelligence_service_client.py b/videointelligence/google/cloud/videointelligence_v1beta2/gapic/video_intelligence_service_client.py index 74df899bb2bd..8c948f5a3cc0 100644 --- a/videointelligence/google/cloud/videointelligence_v1beta2/gapic/video_intelligence_service_client.py +++ b/videointelligence/google/cloud/videointelligence_v1beta2/gapic/video_intelligence_service_client.py @@ -31,13 +31,19 @@ from google.gapic.longrunning import operations_client from google.gax import api_callable from google.gax import config -from google.gax import path_template import google.gax +import google.api.core.gapic_v1.config +import google.api.core.gapic_v1.method +import google.api.core.operation + from google.cloud.videointelligence_v1beta2.gapic import enums from google.cloud.videointelligence_v1beta2.gapic import video_intelligence_service_client_config from google.cloud.videointelligence_v1beta2.proto import video_intelligence_pb2 +_GAPIC_LIBRARY_VERSION = pkg_resources.get_distribution( + 'google-cloud-videointelligence').version + class VideoIntelligenceServiceClient(object): """Service that implements Google Cloud Video Intelligence API.""" @@ -57,10 +63,9 @@ def __init__(self, credentials=None, ssl_credentials=None, scopes=None, - client_config=None, + client_config=video_intelligence_service_client_config.config, lib_name=None, - lib_version='', - metrics_headers=()): + lib_version=''): """Constructor. Args: @@ -74,20 +79,14 @@ def __init__(self, channel. scopes (Sequence[str]): A list of OAuth2 scopes to attach to requests. client_config (dict): - A dictionary for call options for each method. See - :func:`google.gax.construct_settings` for the structure of - this data. Falls back to the default config if not specified - or the specified config is missing data points. + A dictionary of call options for each method. If not specified + the default configuration is used. lib_name (str): The API library software used for calling the service. (Unless you are writing an API client itself, leave this as default.) lib_version (str): The API library software version used for calling the service. (Unless you are writing an API client itself, leave this as default.) - metrics_headers (dict): A dictionary of values for tracking - client library metrics. Ultimately serializes to a string - (e.g. 'foo/1.2.3 bar/3.14.1'). This argument should be - considered private. """ # Unless the calling application specifically requested # OAuth scopes, request everything. @@ -98,28 +97,6 @@ def __init__(self, if client_config is None: client_config = {} - # Initialize metrics_headers as an ordered dictionary - # (cuts down on cardinality of the resulting string slightly). - metrics_headers = collections.OrderedDict(metrics_headers) - metrics_headers['gl-python'] = platform.python_version() - - # The library may or may not be set, depending on what is - # calling this client. Newer client libraries set the library name - # and version. - if lib_name: - metrics_headers[lib_name] = lib_version - - # Finally, track the GAPIC package version. - metrics_headers['gapic'] = pkg_resources.get_distribution( - 'google-cloud-videointelligence', ).version - - # Load the configuration defaults. - defaults = api_callable.construct_settings( - 'google.cloud.videointelligence.v1beta2.VideoIntelligenceService', - video_intelligence_service_client_config.config, - client_config, - config.STATUS_CODE_NAMES, - metrics_headers=metrics_headers, ) self.video_intelligence_service_stub = config.create_stub( video_intelligence_pb2.VideoIntelligenceServiceStub, channel=channel, @@ -135,12 +112,40 @@ def __init__(self, credentials=credentials, ssl_credentials=ssl_credentials, scopes=scopes, - client_config=client_config, - metrics_headers=metrics_headers, ) + client_config=client_config) - self._annotate_video = api_callable.create_api_call( + # -------------------------------- + + # Metrics are used to track API client usage. Prepare headers for + # this particular client library. + + metrics_data = 'gapic/{}'.format(_GAPIC_LIBRARY_VERSION) + + # If the library name is set, include that in the headers. + if lib_name: + metrics_data = '{} {}/{}'.format( + metrics_data, lib_name, lib_version) + + metadata = { + google.api.core.gapic_v1.method.METRICS_METADATA_KEY: metrics_data + } + + # The interface config contains all of the default settings for retry + # and timeout for each RPC method. + interface_config = ( + client_config + ['interfaces'] + ['google.cloud.videointelligence.v1beta2.VideoIntelligenceService'] + ) + # TODO: Merge client config and interface config + method_configs = google.api.core.gapic_v1.config.create_method_configs( + interface_config) + + # Create the wrapped gRPC methods for each RPC method. + self._annotate_video = google.api.core.gapic_v1.method.create_method( self.video_intelligence_service_stub.AnnotateVideo, - settings=defaults['annotate_video']) + method_configs['AnnotateVideo'], + metadata=metadata) # Service calls def annotate_video(self, @@ -150,7 +155,8 @@ def annotate_video(self, video_context=None, output_uri=None, location_id=None, - options=None): + retry=None, + timeout=None): """ Performs asynchronous video annotation. Progress and results can be retrieved through the ``google.longrunning.Operations`` interface. @@ -220,7 +226,9 @@ def annotate_video(self, video_context=video_context, output_uri=output_uri, location_id=location_id) - return google.gax._OperationFuture( - self._annotate_video(request, options), self.operations_client, + operation = self._annotate_video(request, retry=retry, timeout=timeout) + return google.api.core.operation.from_grpc( + operation, + self.operations_client.operations_stub, video_intelligence_pb2.AnnotateVideoResponse, - video_intelligence_pb2.AnnotateVideoProgress, options) + metadata_type=video_intelligence_pb2.AnnotateVideoProgress) From 67e81c31341210c9382e82d1d0ac2fb642c761d1 Mon Sep 17 00:00:00 2001 From: Jon Wayne Parrott Date: Thu, 21 Sep 2017 15:08:44 -0700 Subject: [PATCH 3/3] Revert videointellegence changes --- .../video_intelligence_service_client.py | 92 +++++++++---------- 1 file changed, 42 insertions(+), 50 deletions(-) diff --git a/videointelligence/google/cloud/videointelligence_v1beta2/gapic/video_intelligence_service_client.py b/videointelligence/google/cloud/videointelligence_v1beta2/gapic/video_intelligence_service_client.py index 8c948f5a3cc0..74df899bb2bd 100644 --- a/videointelligence/google/cloud/videointelligence_v1beta2/gapic/video_intelligence_service_client.py +++ b/videointelligence/google/cloud/videointelligence_v1beta2/gapic/video_intelligence_service_client.py @@ -31,19 +31,13 @@ from google.gapic.longrunning import operations_client from google.gax import api_callable from google.gax import config +from google.gax import path_template import google.gax -import google.api.core.gapic_v1.config -import google.api.core.gapic_v1.method -import google.api.core.operation - from google.cloud.videointelligence_v1beta2.gapic import enums from google.cloud.videointelligence_v1beta2.gapic import video_intelligence_service_client_config from google.cloud.videointelligence_v1beta2.proto import video_intelligence_pb2 -_GAPIC_LIBRARY_VERSION = pkg_resources.get_distribution( - 'google-cloud-videointelligence').version - class VideoIntelligenceServiceClient(object): """Service that implements Google Cloud Video Intelligence API.""" @@ -63,9 +57,10 @@ def __init__(self, credentials=None, ssl_credentials=None, scopes=None, - client_config=video_intelligence_service_client_config.config, + client_config=None, lib_name=None, - lib_version=''): + lib_version='', + metrics_headers=()): """Constructor. Args: @@ -79,14 +74,20 @@ def __init__(self, channel. scopes (Sequence[str]): A list of OAuth2 scopes to attach to requests. client_config (dict): - A dictionary of call options for each method. If not specified - the default configuration is used. + A dictionary for call options for each method. See + :func:`google.gax.construct_settings` for the structure of + this data. Falls back to the default config if not specified + or the specified config is missing data points. lib_name (str): The API library software used for calling the service. (Unless you are writing an API client itself, leave this as default.) lib_version (str): The API library software version used for calling the service. (Unless you are writing an API client itself, leave this as default.) + metrics_headers (dict): A dictionary of values for tracking + client library metrics. Ultimately serializes to a string + (e.g. 'foo/1.2.3 bar/3.14.1'). This argument should be + considered private. """ # Unless the calling application specifically requested # OAuth scopes, request everything. @@ -97,6 +98,28 @@ def __init__(self, if client_config is None: client_config = {} + # Initialize metrics_headers as an ordered dictionary + # (cuts down on cardinality of the resulting string slightly). + metrics_headers = collections.OrderedDict(metrics_headers) + metrics_headers['gl-python'] = platform.python_version() + + # The library may or may not be set, depending on what is + # calling this client. Newer client libraries set the library name + # and version. + if lib_name: + metrics_headers[lib_name] = lib_version + + # Finally, track the GAPIC package version. + metrics_headers['gapic'] = pkg_resources.get_distribution( + 'google-cloud-videointelligence', ).version + + # Load the configuration defaults. + defaults = api_callable.construct_settings( + 'google.cloud.videointelligence.v1beta2.VideoIntelligenceService', + video_intelligence_service_client_config.config, + client_config, + config.STATUS_CODE_NAMES, + metrics_headers=metrics_headers, ) self.video_intelligence_service_stub = config.create_stub( video_intelligence_pb2.VideoIntelligenceServiceStub, channel=channel, @@ -112,40 +135,12 @@ def __init__(self, credentials=credentials, ssl_credentials=ssl_credentials, scopes=scopes, - client_config=client_config) + client_config=client_config, + metrics_headers=metrics_headers, ) - # -------------------------------- - - # Metrics are used to track API client usage. Prepare headers for - # this particular client library. - - metrics_data = 'gapic/{}'.format(_GAPIC_LIBRARY_VERSION) - - # If the library name is set, include that in the headers. - if lib_name: - metrics_data = '{} {}/{}'.format( - metrics_data, lib_name, lib_version) - - metadata = { - google.api.core.gapic_v1.method.METRICS_METADATA_KEY: metrics_data - } - - # The interface config contains all of the default settings for retry - # and timeout for each RPC method. - interface_config = ( - client_config - ['interfaces'] - ['google.cloud.videointelligence.v1beta2.VideoIntelligenceService'] - ) - # TODO: Merge client config and interface config - method_configs = google.api.core.gapic_v1.config.create_method_configs( - interface_config) - - # Create the wrapped gRPC methods for each RPC method. - self._annotate_video = google.api.core.gapic_v1.method.create_method( + self._annotate_video = api_callable.create_api_call( self.video_intelligence_service_stub.AnnotateVideo, - method_configs['AnnotateVideo'], - metadata=metadata) + settings=defaults['annotate_video']) # Service calls def annotate_video(self, @@ -155,8 +150,7 @@ def annotate_video(self, video_context=None, output_uri=None, location_id=None, - retry=None, - timeout=None): + options=None): """ Performs asynchronous video annotation. Progress and results can be retrieved through the ``google.longrunning.Operations`` interface. @@ -226,9 +220,7 @@ def annotate_video(self, video_context=video_context, output_uri=output_uri, location_id=location_id) - operation = self._annotate_video(request, retry=retry, timeout=timeout) - return google.api.core.operation.from_grpc( - operation, - self.operations_client.operations_stub, + return google.gax._OperationFuture( + self._annotate_video(request, options), self.operations_client, video_intelligence_pb2.AnnotateVideoResponse, - metadata_type=video_intelligence_pb2.AnnotateVideoProgress) + video_intelligence_pb2.AnnotateVideoProgress, options)