diff --git a/spanner/google/__init__.py b/spanner/google/__init__.py index e338417ca8c8..d2547b8d952f 100644 --- a/spanner/google/__init__.py +++ b/spanner/google/__init__.py @@ -1,22 +1,6 @@ -# Copyright 2016 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. - -"""Google namespace package.""" - try: import pkg_resources pkg_resources.declare_namespace(__name__) except ImportError: import pkgutil - __path__ = pkgutil.extend_path(__path__, __name__) + __path__ = pkgutil.extend_path(__path__, __name__) \ No newline at end of file diff --git a/spanner/google/cloud/__init__.py b/spanner/google/cloud/__init__.py index 9af27e143b80..d2547b8d952f 100644 --- a/spanner/google/cloud/__init__.py +++ b/spanner/google/cloud/__init__.py @@ -1,22 +1,6 @@ -# Copyright 2016 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. - -"""Google Cloud namespace package.""" - try: import pkg_resources pkg_resources.declare_namespace(__name__) except ImportError: import pkgutil - __path__ = pkgutil.extend_path(__path__, __name__) + __path__ = pkgutil.extend_path(__path__, __name__) \ No newline at end of file diff --git a/spanner/google/cloud/spanner_admin_database_v1/__init__.py b/spanner/google/cloud/spanner_admin_database_v1/__init__.py index 4c6556515176..24c369f5f785 100644 --- a/spanner/google/cloud/spanner_admin_database_v1/__init__.py +++ b/spanner/google/cloud/spanner_admin_database_v1/__init__.py @@ -1,10 +1,10 @@ -# Copyright 2017, Google LLC All rights reserved. +# Copyright 2017 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 +# https://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, @@ -27,4 +27,5 @@ class DatabaseAdminClient(database_admin_client.DatabaseAdminClient): __all__ = ( 'enums', 'types', - 'DatabaseAdminClient', ) + 'DatabaseAdminClient', +) diff --git a/spanner/google/cloud/spanner_admin_database_v1/gapic/database_admin_client.py b/spanner/google/cloud/spanner_admin_database_v1/gapic/database_admin_client.py index 0bbf0ba7ee6e..f1cc599243a9 100644 --- a/spanner/google/cloud/spanner_admin_database_v1/gapic/database_admin_client.py +++ b/spanner/google/cloud/spanner_admin_database_v1/gapic/database_admin_client.py @@ -1,38 +1,29 @@ -# Copyright 2017, Google LLC All rights reserved. +# Copyright 2017 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 +# https://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. -# -# EDITING INSTRUCTIONS -# This file was generated from the file -# https://github.com/google/googleapis/blob/master/google/spanner/admin/database/v1/spanner_database_admin.proto, -# and updates to that file get reflected here through a refresh process. -# For the short term, the refresh process will only be runnable by Google engineers. -# -# The only allowed edits are to method and file documentation. A 3-way -# merge preserves those additions if the generated source changes. """Accesses the google.spanner.admin.database.v1 DatabaseAdmin API.""" -import collections -import json -import os +import functools import pkg_resources -import platform -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.client_info +import google.api_core.gapic_v1.config +import google.api_core.gapic_v1.method +import google.api_core.grpc_helpers +import google.api_core.operation +import google.api_core.operations_v1 +import google.api_core.page_iterator +import google.api_core.path_template from google.cloud.spanner_admin_database_v1.gapic import database_admin_client_config from google.cloud.spanner_admin_database_v1.gapic import enums @@ -41,7 +32,8 @@ from google.iam.v1 import policy_pb2 from google.protobuf import empty_pb2 -_PageDesc = google.gax.PageDescriptor +_GAPIC_LIBRARY_VERSION = pkg_resources.get_distribution( + 'google-cloud-spanner', ).version class DatabaseAdminClient(object): @@ -53,233 +45,170 @@ class DatabaseAdminClient(object): databases. """ - SERVICE_ADDRESS = 'spanner.googleapis.com' + SERVICE_ADDRESS = 'spanner.googleapis.com:443' """The default address of the service.""" - DEFAULT_SERVICE_PORT = 443 - """The default port of the service.""" - - _PAGE_DESCRIPTORS = { - 'list_databases': _PageDesc('page_token', 'next_page_token', - 'databases') - } - # The scopes needed to make gRPC calls to all of the methods defined in # this service - _ALL_SCOPES = ( + _DEFAULT_SCOPES = ( 'https://www.googleapis.com/auth/cloud-platform', - 'https://www.googleapis.com/auth/spanner.admin', ) + 'https://www.googleapis.com/auth/spanner.admin', + ) - _INSTANCE_PATH_TEMPLATE = path_template.PathTemplate( - 'projects/{project}/instances/{instance}') - _DATABASE_PATH_TEMPLATE = path_template.PathTemplate( - 'projects/{project}/instances/{instance}/databases/{database}') + # The name of the interface for this client. This is the key used to find + # method configuration in the client_config dictionary. + _INTERFACE_NAME = 'google.spanner.admin.database.v1.DatabaseAdmin' @classmethod def instance_path(cls, project, instance): - """Returns a fully-qualified instance resource name string.""" - return cls._INSTANCE_PATH_TEMPLATE.render({ - 'project': project, - 'instance': instance, - }) + """Return a fully-qualified instance string.""" + return google.api_core.path_template.expand( + 'projects/{project}/instances/{instance}', + project=project, + instance=instance, + ) @classmethod def database_path(cls, project, instance, database): - """Returns a fully-qualified database resource name string.""" - return cls._DATABASE_PATH_TEMPLATE.render({ - 'project': project, - 'instance': instance, - 'database': database, - }) - - @classmethod - def match_project_from_instance_name(cls, instance_name): - """Parses the project from a instance resource. - - Args: - instance_name (str): A fully-qualified path representing a instance - resource. - - Returns: - A string representing the project. - """ - return cls._INSTANCE_PATH_TEMPLATE.match(instance_name).get('project') - - @classmethod - def match_instance_from_instance_name(cls, instance_name): - """Parses the instance from a instance resource. - - Args: - instance_name (str): A fully-qualified path representing a instance - resource. - - Returns: - A string representing the instance. - """ - return cls._INSTANCE_PATH_TEMPLATE.match(instance_name).get('instance') - - @classmethod - def match_project_from_database_name(cls, database_name): - """Parses the project from a database resource. - - Args: - database_name (str): A fully-qualified path representing a database - resource. - - Returns: - A string representing the project. - """ - return cls._DATABASE_PATH_TEMPLATE.match(database_name).get('project') - - @classmethod - def match_instance_from_database_name(cls, database_name): - """Parses the instance from a database resource. - - Args: - database_name (str): A fully-qualified path representing a database - resource. - - Returns: - A string representing the instance. - """ - return cls._DATABASE_PATH_TEMPLATE.match(database_name).get('instance') - - @classmethod - def match_database_from_database_name(cls, database_name): - """Parses the database from a database resource. - - Args: - database_name (str): A fully-qualified path representing a database - resource. - - Returns: - A string representing the database. - """ - return cls._DATABASE_PATH_TEMPLATE.match(database_name).get('database') + """Return a fully-qualified database string.""" + return google.api_core.path_template.expand( + 'projects/{project}/instances/{instance}/databases/{database}', + project=project, + instance=instance, + database=database, + ) def __init__(self, channel=None, credentials=None, - ssl_credentials=None, - scopes=None, - client_config=None, - lib_name=None, - lib_version='', - metrics_headers=()): + client_config=database_admin_client_config.config, + client_info=None): """Constructor. Args: - channel (~grpc.Channel): A ``Channel`` instance through - which to make calls. - credentials (~google.auth.credentials.Credentials): The authorization - credentials to attach to requests. These credentials identify this - application to the service. - ssl_credentials (~grpc.ChannelCredentials): A - ``ChannelCredentials`` instance for use with an SSL-enabled - 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. - 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. + channel (grpc.Channel): A ``Channel`` instance through + which to make calls. This argument is mutually exclusive + with ``credentials``; providing both will raise an exception. + credentials (google.auth.credentials.Credentials): The + authorization credentials to attach to requests. These + credentials identify this application to the service. If none + are specified, the client will attempt to ascertain the + credentials from the environment. + client_config (dict): A dictionary of call options for each + method. If not specified, the default configuration is used. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. """ - # Unless the calling application specifically requested - # OAuth scopes, request everything. - if scopes is None: - scopes = self._ALL_SCOPES - - # Initialize an empty client config, if none is set. - 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-spanner', ).version - - # Load the configuration defaults. - defaults = api_callable.construct_settings( - 'google.spanner.admin.database.v1.DatabaseAdmin', - database_admin_client_config.config, - client_config, - config.STATUS_CODE_NAMES, - metrics_headers=metrics_headers, - page_descriptors=self._PAGE_DESCRIPTORS, ) - self.database_admin_stub = config.create_stub( - spanner_database_admin_pb2.DatabaseAdminStub, - channel=channel, - service_path=self.SERVICE_ADDRESS, - service_port=self.DEFAULT_SERVICE_PORT, - credentials=credentials, - scopes=scopes, - ssl_credentials=ssl_credentials) - - self.operations_client = operations_client.OperationsClient( - service_path=self.SERVICE_ADDRESS, - channel=channel, - credentials=credentials, - ssl_credentials=ssl_credentials, - scopes=scopes, - client_config=client_config, - metrics_headers=metrics_headers, ) - - self._list_databases = api_callable.create_api_call( + # If both `channel` and `credentials` are specified, raise an + # exception (channels come with credentials baked in already). + if channel is not None and credentials is not None: + raise ValueError( + 'The `channel` and `credentials` arguments to {} are mutually ' + 'exclusive.'.format(self.__class__.__name__), ) + + # Create the channel. + if channel is None: + channel = google.api_core.grpc_helpers.create_channel( + self.SERVICE_ADDRESS, + credentials=credentials, + scopes=self._DEFAULT_SCOPES, + ) + + # Create the gRPC stubs. + self.database_admin_stub = ( + spanner_database_admin_pb2.DatabaseAdminStub(channel)) + + # Operations client for methods that return long-running operations + # futures. + self.operations_client = ( + google.api_core.operations_v1.OperationsClient(channel)) + + if client_info is None: + client_info = ( + google.api_core.gapic_v1.client_info.DEFAULT_CLIENT_INFO) + client_info.gapic_version = _GAPIC_LIBRARY_VERSION + + # Parse out the default settings for retry and timeout for each RPC + # from the client configuration. + # (Ordinarily, these are the defaults specified in the `*_config.py` + # file next to this one.) + method_configs = google.api_core.gapic_v1.config.parse_method_configs( + client_config['interfaces'][self._INTERFACE_NAME], ) + + # Write the "inner API call" methods to the class. + # These are wrapped versions of the gRPC stub methods, with retry and + # timeout configuration applied, called by the public methods on + # this class. + self._list_databases = google.api_core.gapic_v1.method.wrap_method( self.database_admin_stub.ListDatabases, - settings=defaults['list_databases']) - self._create_database = api_callable.create_api_call( + default_retry=method_configs['ListDatabases'].retry, + default_timeout=method_configs['ListDatabases'].timeout, + client_info=client_info, + ) + self._create_database = google.api_core.gapic_v1.method.wrap_method( self.database_admin_stub.CreateDatabase, - settings=defaults['create_database']) - self._get_database = api_callable.create_api_call( + default_retry=method_configs['CreateDatabase'].retry, + default_timeout=method_configs['CreateDatabase'].timeout, + client_info=client_info, + ) + self._get_database = google.api_core.gapic_v1.method.wrap_method( self.database_admin_stub.GetDatabase, - settings=defaults['get_database']) - self._update_database_ddl = api_callable.create_api_call( + default_retry=method_configs['GetDatabase'].retry, + default_timeout=method_configs['GetDatabase'].timeout, + client_info=client_info, + ) + self._update_database_ddl = google.api_core.gapic_v1.method.wrap_method( self.database_admin_stub.UpdateDatabaseDdl, - settings=defaults['update_database_ddl']) - self._drop_database = api_callable.create_api_call( + default_retry=method_configs['UpdateDatabaseDdl'].retry, + default_timeout=method_configs['UpdateDatabaseDdl'].timeout, + client_info=client_info, + ) + self._drop_database = google.api_core.gapic_v1.method.wrap_method( self.database_admin_stub.DropDatabase, - settings=defaults['drop_database']) - self._get_database_ddl = api_callable.create_api_call( + default_retry=method_configs['DropDatabase'].retry, + default_timeout=method_configs['DropDatabase'].timeout, + client_info=client_info, + ) + self._get_database_ddl = google.api_core.gapic_v1.method.wrap_method( self.database_admin_stub.GetDatabaseDdl, - settings=defaults['get_database_ddl']) - self._set_iam_policy = api_callable.create_api_call( + default_retry=method_configs['GetDatabaseDdl'].retry, + default_timeout=method_configs['GetDatabaseDdl'].timeout, + client_info=client_info, + ) + self._set_iam_policy = google.api_core.gapic_v1.method.wrap_method( self.database_admin_stub.SetIamPolicy, - settings=defaults['set_iam_policy']) - self._get_iam_policy = api_callable.create_api_call( + default_retry=method_configs['SetIamPolicy'].retry, + default_timeout=method_configs['SetIamPolicy'].timeout, + client_info=client_info, + ) + self._get_iam_policy = google.api_core.gapic_v1.method.wrap_method( self.database_admin_stub.GetIamPolicy, - settings=defaults['get_iam_policy']) - self._test_iam_permissions = api_callable.create_api_call( + default_retry=method_configs['GetIamPolicy'].retry, + default_timeout=method_configs['GetIamPolicy'].timeout, + client_info=client_info, + ) + self._test_iam_permissions = google.api_core.gapic_v1.method.wrap_method( self.database_admin_stub.TestIamPermissions, - settings=defaults['test_iam_permissions']) + default_retry=method_configs['TestIamPermissions'].retry, + default_timeout=method_configs['TestIamPermissions'].timeout, + client_info=client_info, + ) # Service calls - def list_databases(self, parent, page_size=None, options=None): + def list_databases(self, + parent, + page_size=None, + retry=google.api_core.gapic_v1.method.DEFAULT, + timeout=google.api_core.gapic_v1.method.DEFAULT, + metadata=None): """ Lists Cloud Spanner databases. Example: >>> from google.cloud import spanner_admin_database_v1 - >>> from google.gax import CallOptions, INITIAL_PAGE >>> >>> client = spanner_admin_database_v1.DatabaseAdminClient() >>> @@ -305,8 +234,12 @@ def list_databases(self, parent, page_size=None, options=None): resource, this parameter does not affect the return value. If page streaming is performed per-page, this determines the maximum number of resources in a page. - options (~google.gax.CallOptions): Overrides the default - settings for this call, e.g, timeout, retries etc. + retry (Optional[google.api_core.retry.Retry]): A retry object used + to retry requests. If ``None`` is specified, requests will not + be retried. + timeout (Optional[float]): The amount of time, in seconds, to wait + for the request to complete. Note that if ``retry`` is + specified, the timeout applies to each individual attempt. Returns: A :class:`~google.gax.PageIterator` instance. By default, this @@ -315,18 +248,35 @@ def list_databases(self, parent, page_size=None, options=None): of the response through the `options` parameter. Raises: - :exc:`google.gax.errors.GaxError` if the RPC is aborted. - :exc:`ValueError` if the parameters are invalid. + google.api_core.exceptions.GoogleAPICallError: If the request + failed for any reason. + google.api_core.exceptions.RetryError: If the request failed due + to a retryable error and retry attempts failed. + ValueError: If the parameters are invalid. """ request = spanner_database_admin_pb2.ListDatabasesRequest( - parent=parent, page_size=page_size) - return self._list_databases(request, options) + parent=parent, + page_size=page_size, + ) + iterator = google.api_core.page_iterator.GRPCIterator( + client=None, + method=functools.partial( + self._list_databases, retry=retry, timeout=timeout, + metadata=metadata), + request=request, + items_field='databases', + request_token_field='page_token', + response_token_field='next_page_token', + ) + return iterator def create_database(self, parent, create_statement, extra_statements=None, - options=None): + retry=google.api_core.gapic_v1.method.DEFAULT, + timeout=google.api_core.gapic_v1.method.DEFAULT, + metadata=None): """ Creates a new Cloud Spanner database and starts to prepare it for serving. The returned ``long-running operation`` will @@ -362,30 +312,48 @@ def create_database(self, create_statement (str): Required. A ``CREATE DATABASE`` statement, which specifies the ID of the new database. The database ID must conform to the regular expression ``[a-z][a-z0-9_\-]*[a-z0-9]`` and be between 2 and 30 characters in length. + If the database ID is a reserved word or if it contains a hyphen, the + database ID must be enclosed in backticks ("`"). extra_statements (list[str]): An optional list of DDL statements to run inside the newly created database. Statements can create tables, indexes, etc. These statements execute atomically with the creation of the database: if there is an error in any statement, the database is not created. - options (~google.gax.CallOptions): Overrides the default - settings for this call, e.g, timeout, retries etc. + retry (Optional[google.api_core.retry.Retry]): A retry object used + to retry requests. If ``None`` is specified, requests will not + be retried. + timeout (Optional[float]): The amount of time, in seconds, to wait + for the request to complete. Note that if ``retry`` is + specified, the timeout applies to each individual attempt. Returns: A :class:`~google.cloud.spanner_admin_database_v1.types._OperationFuture` instance. Raises: - :exc:`google.gax.errors.GaxError` if the RPC is aborted. - :exc:`ValueError` if the parameters are invalid. + google.api_core.exceptions.GoogleAPICallError: If the request + failed for any reason. + google.api_core.exceptions.RetryError: If the request failed due + to a retryable error and retry attempts failed. + ValueError: If the parameters are invalid. """ request = spanner_database_admin_pb2.CreateDatabaseRequest( parent=parent, create_statement=create_statement, - extra_statements=extra_statements) - return google.gax._OperationFuture( - self._create_database(request, options), self.operations_client, + extra_statements=extra_statements, + ) + operation = self._create_database( + request, retry=retry, timeout=timeout, metadata=metadata) + return google.api_core.operation.from_gapic( + operation, + self.operations_client, spanner_database_admin_pb2.Database, - spanner_database_admin_pb2.CreateDatabaseMetadata, options) - - def get_database(self, name, options=None): + metadata_type=spanner_database_admin_pb2.CreateDatabaseMetadata, + ) + + def get_database(self, + name, + retry=google.api_core.gapic_v1.method.DEFAULT, + timeout=google.api_core.gapic_v1.method.DEFAULT, + metadata=None): """ Gets the state of a Cloud Spanner database. @@ -401,24 +369,34 @@ def get_database(self, name, options=None): Args: name (str): Required. The name of the requested database. Values are of the form ``projects//instances//databases/``. - options (~google.gax.CallOptions): Overrides the default - settings for this call, e.g, timeout, retries etc. + retry (Optional[google.api_core.retry.Retry]): A retry object used + to retry requests. If ``None`` is specified, requests will not + be retried. + timeout (Optional[float]): The amount of time, in seconds, to wait + for the request to complete. Note that if ``retry`` is + specified, the timeout applies to each individual attempt. Returns: A :class:`~google.cloud.spanner_admin_database_v1.types.Database` instance. Raises: - :exc:`google.gax.errors.GaxError` if the RPC is aborted. - :exc:`ValueError` if the parameters are invalid. + google.api_core.exceptions.GoogleAPICallError: If the request + failed for any reason. + google.api_core.exceptions.RetryError: If the request failed due + to a retryable error and retry attempts failed. + ValueError: If the parameters are invalid. """ - request = spanner_database_admin_pb2.GetDatabaseRequest(name=name) - return self._get_database(request, options) + request = spanner_database_admin_pb2.GetDatabaseRequest(name=name, ) + return self._get_database( + request, retry=retry, timeout=timeout, metadata=metadata) def update_database_ddl(self, database, statements, operation_id=None, - options=None): + retry=google.api_core.gapic_v1.method.DEFAULT, + timeout=google.api_core.gapic_v1.method.DEFAULT, + metadata=None): """ Updates the schema of a Cloud Spanner database by creating/altering/dropping tables, columns, indexes, etc. The returned @@ -469,26 +447,42 @@ def update_database_ddl(self, underscore. If the named operation already exists, ``UpdateDatabaseDdl`` returns ``ALREADY_EXISTS``. - options (~google.gax.CallOptions): Overrides the default - settings for this call, e.g, timeout, retries etc. + retry (Optional[google.api_core.retry.Retry]): A retry object used + to retry requests. If ``None`` is specified, requests will not + be retried. + timeout (Optional[float]): The amount of time, in seconds, to wait + for the request to complete. Note that if ``retry`` is + specified, the timeout applies to each individual attempt. Returns: A :class:`~google.cloud.spanner_admin_database_v1.types._OperationFuture` instance. Raises: - :exc:`google.gax.errors.GaxError` if the RPC is aborted. - :exc:`ValueError` if the parameters are invalid. + google.api_core.exceptions.GoogleAPICallError: If the request + failed for any reason. + google.api_core.exceptions.RetryError: If the request failed due + to a retryable error and retry attempts failed. + ValueError: If the parameters are invalid. """ request = spanner_database_admin_pb2.UpdateDatabaseDdlRequest( database=database, statements=statements, - operation_id=operation_id) - return google.gax._OperationFuture( - self._update_database_ddl(request, options), - self.operations_client, empty_pb2.Empty, - spanner_database_admin_pb2.UpdateDatabaseDdlMetadata, options) - - def drop_database(self, database, options=None): + operation_id=operation_id, + ) + operation = self._update_database_ddl( + request, retry=retry, timeout=timeout, metadata=metadata) + return google.api_core.operation.from_gapic( + operation, + self.operations_client, + empty_pb2.Empty, + metadata_type=spanner_database_admin_pb2.UpdateDatabaseDdlMetadata, + ) + + def drop_database(self, + database, + retry=google.api_core.gapic_v1.method.DEFAULT, + timeout=google.api_core.gapic_v1.method.DEFAULT, + metadata=None): """ Drops (aka deletes) a Cloud Spanner database. @@ -503,18 +497,30 @@ def drop_database(self, database, options=None): Args: database (str): Required. The database to be dropped. - options (~google.gax.CallOptions): Overrides the default - settings for this call, e.g, timeout, retries etc. + retry (Optional[google.api_core.retry.Retry]): A retry object used + to retry requests. If ``None`` is specified, requests will not + be retried. + timeout (Optional[float]): The amount of time, in seconds, to wait + for the request to complete. Note that if ``retry`` is + specified, the timeout applies to each individual attempt. Raises: - :exc:`google.gax.errors.GaxError` if the RPC is aborted. - :exc:`ValueError` if the parameters are invalid. + google.api_core.exceptions.GoogleAPICallError: If the request + failed for any reason. + google.api_core.exceptions.RetryError: If the request failed due + to a retryable error and retry attempts failed. + ValueError: If the parameters are invalid. """ request = spanner_database_admin_pb2.DropDatabaseRequest( - database=database) - self._drop_database(request, options) - - def get_database_ddl(self, database, options=None): + database=database, ) + self._drop_database( + request, retry=retry, timeout=timeout, metadata=metadata) + + def get_database_ddl(self, + database, + retry=google.api_core.gapic_v1.method.DEFAULT, + timeout=google.api_core.gapic_v1.method.DEFAULT, + metadata=None): """ Returns the schema of a Cloud Spanner database as a list of formatted DDL statements. This method does not show pending schema updates, those may @@ -531,21 +537,34 @@ def get_database_ddl(self, database, options=None): Args: database (str): Required. The database whose schema we wish to get. - options (~google.gax.CallOptions): Overrides the default - settings for this call, e.g, timeout, retries etc. + retry (Optional[google.api_core.retry.Retry]): A retry object used + to retry requests. If ``None`` is specified, requests will not + be retried. + timeout (Optional[float]): The amount of time, in seconds, to wait + for the request to complete. Note that if ``retry`` is + specified, the timeout applies to each individual attempt. Returns: A :class:`~google.cloud.spanner_admin_database_v1.types.GetDatabaseDdlResponse` instance. Raises: - :exc:`google.gax.errors.GaxError` if the RPC is aborted. - :exc:`ValueError` if the parameters are invalid. + google.api_core.exceptions.GoogleAPICallError: If the request + failed for any reason. + google.api_core.exceptions.RetryError: If the request failed due + to a retryable error and retry attempts failed. + ValueError: If the parameters are invalid. """ request = spanner_database_admin_pb2.GetDatabaseDdlRequest( - database=database) - return self._get_database_ddl(request, options) - - def set_iam_policy(self, resource, policy, options=None): + database=database, ) + return self._get_database_ddl( + request, retry=retry, timeout=timeout, metadata=metadata) + + def set_iam_policy(self, + resource, + policy, + retry=google.api_core.gapic_v1.method.DEFAULT, + timeout=google.api_core.gapic_v1.method.DEFAULT, + metadata=None): """ Sets the access control policy on a database resource. Replaces any existing policy. @@ -573,21 +592,35 @@ def set_iam_policy(self, resource, policy, options=None): might reject them. If a dict is provided, it must be of the same form as the protobuf message :class:`~google.cloud.spanner_admin_database_v1.types.Policy` - options (~google.gax.CallOptions): Overrides the default - settings for this call, e.g, timeout, retries etc. + retry (Optional[google.api_core.retry.Retry]): A retry object used + to retry requests. If ``None`` is specified, requests will not + be retried. + timeout (Optional[float]): The amount of time, in seconds, to wait + for the request to complete. Note that if ``retry`` is + specified, the timeout applies to each individual attempt. Returns: A :class:`~google.cloud.spanner_admin_database_v1.types.Policy` instance. Raises: - :exc:`google.gax.errors.GaxError` if the RPC is aborted. - :exc:`ValueError` if the parameters are invalid. + google.api_core.exceptions.GoogleAPICallError: If the request + failed for any reason. + google.api_core.exceptions.RetryError: If the request failed due + to a retryable error and retry attempts failed. + ValueError: If the parameters are invalid. """ request = iam_policy_pb2.SetIamPolicyRequest( - resource=resource, policy=policy) - return self._set_iam_policy(request, options) - - def get_iam_policy(self, resource, options=None): + resource=resource, + policy=policy, + ) + return self._set_iam_policy( + request, retry=retry, timeout=timeout, metadata=metadata) + + def get_iam_policy(self, + resource, + retry=google.api_core.gapic_v1.method.DEFAULT, + timeout=google.api_core.gapic_v1.method.DEFAULT, + metadata=None): """ Gets the access control policy for a database resource. Returns an empty policy if a database exists but does not have a policy set. @@ -608,20 +641,33 @@ def get_iam_policy(self, resource, options=None): resource (str): REQUIRED: The resource for which the policy is being requested. ``resource`` is usually specified as a path. For example, a Project resource is specified as ``projects/{project}``. - options (~google.gax.CallOptions): Overrides the default - settings for this call, e.g, timeout, retries etc. + retry (Optional[google.api_core.retry.Retry]): A retry object used + to retry requests. If ``None`` is specified, requests will not + be retried. + timeout (Optional[float]): The amount of time, in seconds, to wait + for the request to complete. Note that if ``retry`` is + specified, the timeout applies to each individual attempt. Returns: A :class:`~google.cloud.spanner_admin_database_v1.types.Policy` instance. Raises: - :exc:`google.gax.errors.GaxError` if the RPC is aborted. - :exc:`ValueError` if the parameters are invalid. + google.api_core.exceptions.GoogleAPICallError: If the request + failed for any reason. + google.api_core.exceptions.RetryError: If the request failed due + to a retryable error and retry attempts failed. + ValueError: If the parameters are invalid. """ - request = iam_policy_pb2.GetIamPolicyRequest(resource=resource) - return self._get_iam_policy(request, options) - - def test_iam_permissions(self, resource, permissions, options=None): + request = iam_policy_pb2.GetIamPolicyRequest(resource=resource, ) + return self._get_iam_policy( + request, retry=retry, timeout=timeout, metadata=metadata) + + def test_iam_permissions(self, + resource, + permissions, + retry=google.api_core.gapic_v1.method.DEFAULT, + timeout=google.api_core.gapic_v1.method.DEFAULT, + metadata=None): """ Returns permissions that the caller has on the specified database resource. @@ -648,16 +694,26 @@ def test_iam_permissions(self, resource, permissions, options=None): wildcards (such as '*' or 'storage.*') are not allowed. For more information see `IAM Overview `_. - options (~google.gax.CallOptions): Overrides the default - settings for this call, e.g, timeout, retries etc. + retry (Optional[google.api_core.retry.Retry]): A retry object used + to retry requests. If ``None`` is specified, requests will not + be retried. + timeout (Optional[float]): The amount of time, in seconds, to wait + for the request to complete. Note that if ``retry`` is + specified, the timeout applies to each individual attempt. Returns: A :class:`~google.cloud.spanner_admin_database_v1.types.TestIamPermissionsResponse` instance. Raises: - :exc:`google.gax.errors.GaxError` if the RPC is aborted. - :exc:`ValueError` if the parameters are invalid. + google.api_core.exceptions.GoogleAPICallError: If the request + failed for any reason. + google.api_core.exceptions.RetryError: If the request failed due + to a retryable error and retry attempts failed. + ValueError: If the parameters are invalid. """ request = iam_policy_pb2.TestIamPermissionsRequest( - resource=resource, permissions=permissions) - return self._test_iam_permissions(request, options) + resource=resource, + permissions=permissions, + ) + return self._test_iam_permissions( + request, retry=retry, timeout=timeout, metadata=metadata) diff --git a/spanner/google/cloud/spanner_admin_database_v1/gapic/enums.py b/spanner/google/cloud/spanner_admin_database_v1/gapic/enums.py index bdd3844fe5e2..7a3efc133934 100644 --- a/spanner/google/cloud/spanner_admin_database_v1/gapic/enums.py +++ b/spanner/google/cloud/spanner_admin_database_v1/gapic/enums.py @@ -1,10 +1,10 @@ -# Copyright 2017, Google LLC All rights reserved. +# Copyright 2017 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 +# https://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, diff --git a/spanner/google/cloud/spanner_admin_database_v1/proto/spanner_database_admin_pb2.py b/spanner/google/cloud/spanner_admin_database_v1/proto/spanner_database_admin_pb2.py index e0199e551cfd..99e31abd901e 100644 --- a/spanner/google/cloud/spanner_admin_database_v1/proto/spanner_database_admin_pb2.py +++ b/spanner/google/cloud/spanner_admin_database_v1/proto/spanner_database_admin_pb2.py @@ -14,7 +14,6 @@ from google.api import annotations_pb2 as google_dot_api_dot_annotations__pb2 -from google.api import auth_pb2 as google_dot_api_dot_auth__pb2 from google.iam.v1 import iam_policy_pb2 as google_dot_iam_dot_v1_dot_iam__policy__pb2 from google.iam.v1 import policy_pb2 as google_dot_iam_dot_v1_dot_policy__pb2 from google.longrunning import operations_pb2 as google_dot_longrunning_dot_operations__pb2 @@ -26,9 +25,9 @@ name='google/cloud/spanner/admin/database_v1/proto/spanner_database_admin.proto', package='google.spanner.admin.database.v1', syntax='proto3', - serialized_pb=_b('\nIgoogle/cloud/spanner/admin/database_v1/proto/spanner_database_admin.proto\x12 google.spanner.admin.database.v1\x1a\x1cgoogle/api/annotations.proto\x1a\x15google/api/auth.proto\x1a\x1egoogle/iam/v1/iam_policy.proto\x1a\x1agoogle/iam/v1/policy.proto\x1a#google/longrunning/operations.proto\x1a\x1bgoogle/protobuf/empty.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\x92\x01\n\x08\x44\x61tabase\x12\x0c\n\x04name\x18\x01 \x01(\t\x12?\n\x05state\x18\x02 \x01(\x0e\x32\x30.google.spanner.admin.database.v1.Database.State\"7\n\x05State\x12\x15\n\x11STATE_UNSPECIFIED\x10\x00\x12\x0c\n\x08\x43REATING\x10\x01\x12\t\n\x05READY\x10\x02\"M\n\x14ListDatabasesRequest\x12\x0e\n\x06parent\x18\x01 \x01(\t\x12\x11\n\tpage_size\x18\x03 \x01(\x05\x12\x12\n\npage_token\x18\x04 \x01(\t\"o\n\x15ListDatabasesResponse\x12=\n\tdatabases\x18\x01 \x03(\x0b\x32*.google.spanner.admin.database.v1.Database\x12\x17\n\x0fnext_page_token\x18\x02 \x01(\t\"[\n\x15\x43reateDatabaseRequest\x12\x0e\n\x06parent\x18\x01 \x01(\t\x12\x18\n\x10\x63reate_statement\x18\x02 \x01(\t\x12\x18\n\x10\x65xtra_statements\x18\x03 \x03(\t\"*\n\x16\x43reateDatabaseMetadata\x12\x10\n\x08\x64\x61tabase\x18\x01 \x01(\t\"\"\n\x12GetDatabaseRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"V\n\x18UpdateDatabaseDdlRequest\x12\x10\n\x08\x64\x61tabase\x18\x01 \x01(\t\x12\x12\n\nstatements\x18\x02 \x03(\t\x12\x14\n\x0coperation_id\x18\x03 \x01(\t\"x\n\x19UpdateDatabaseDdlMetadata\x12\x10\n\x08\x64\x61tabase\x18\x01 \x01(\t\x12\x12\n\nstatements\x18\x02 \x03(\t\x12\x35\n\x11\x63ommit_timestamps\x18\x03 \x03(\x0b\x32\x1a.google.protobuf.Timestamp\"\'\n\x13\x44ropDatabaseRequest\x12\x10\n\x08\x64\x61tabase\x18\x01 \x01(\t\")\n\x15GetDatabaseDdlRequest\x12\x10\n\x08\x64\x61tabase\x18\x01 \x01(\t\",\n\x16GetDatabaseDdlResponse\x12\x12\n\nstatements\x18\x01 \x03(\t2\x95\x0c\n\rDatabaseAdmin\x12\xb7\x01\n\rListDatabases\x12\x36.google.spanner.admin.database.v1.ListDatabasesRequest\x1a\x37.google.spanner.admin.database.v1.ListDatabasesResponse\"5\x82\xd3\xe4\x93\x02/\x12-/v1/{parent=projects/*/instances/*}/databases\x12\xa2\x01\n\x0e\x43reateDatabase\x12\x37.google.spanner.admin.database.v1.CreateDatabaseRequest\x1a\x1d.google.longrunning.Operation\"8\x82\xd3\xe4\x93\x02\x32\"-/v1/{parent=projects/*/instances/*}/databases:\x01*\x12\xa6\x01\n\x0bGetDatabase\x12\x34.google.spanner.admin.database.v1.GetDatabaseRequest\x1a*.google.spanner.admin.database.v1.Database\"5\x82\xd3\xe4\x93\x02/\x12-/v1/{name=projects/*/instances/*/databases/*}\x12\xb0\x01\n\x11UpdateDatabaseDdl\x12:.google.spanner.admin.database.v1.UpdateDatabaseDdlRequest\x1a\x1d.google.longrunning.Operation\"@\x82\xd3\xe4\x93\x02:25/v1/{database=projects/*/instances/*/databases/*}/ddl:\x01*\x12\x98\x01\n\x0c\x44ropDatabase\x12\x35.google.spanner.admin.database.v1.DropDatabaseRequest\x1a\x16.google.protobuf.Empty\"9\x82\xd3\xe4\x93\x02\x33*1/v1/{database=projects/*/instances/*/databases/*}\x12\xc2\x01\n\x0eGetDatabaseDdl\x12\x37.google.spanner.admin.database.v1.GetDatabaseDdlRequest\x1a\x38.google.spanner.admin.database.v1.GetDatabaseDdlResponse\"=\x82\xd3\xe4\x93\x02\x37\x12\x35/v1/{database=projects/*/instances/*/databases/*}/ddl\x12\x94\x01\n\x0cSetIamPolicy\x12\".google.iam.v1.SetIamPolicyRequest\x1a\x15.google.iam.v1.Policy\"I\x82\xd3\xe4\x93\x02\x43\">/v1/{resource=projects/*/instances/*/databases/*}:setIamPolicy:\x01*\x12\x94\x01\n\x0cGetIamPolicy\x12\".google.iam.v1.GetIamPolicyRequest\x1a\x15.google.iam.v1.Policy\"I\x82\xd3\xe4\x93\x02\x43\">/v1/{resource=projects/*/instances/*/databases/*}:getIamPolicy:\x01*\x12\xba\x01\n\x12TestIamPermissions\x12(.google.iam.v1.TestIamPermissionsRequest\x1a).google.iam.v1.TestIamPermissionsResponse\"O\x82\xd3\xe4\x93\x02I\"D/v1/{resource=projects/*/instances/*/databases/*}:testIamPermissions:\x01*B\xb6\x01\n$com.google.spanner.admin.database.v1B\x19SpannerDatabaseAdminProtoP\x01ZHgoogle.golang.org/genproto/googleapis/spanner/admin/database/v1;database\xaa\x02&Google.Cloud.Spanner.Admin.Database.V1b\x06proto3') + serialized_pb=_b('\nIgoogle/cloud/spanner/admin/database_v1/proto/spanner_database_admin.proto\x12 google.spanner.admin.database.v1\x1a\x1cgoogle/api/annotations.proto\x1a\x1egoogle/iam/v1/iam_policy.proto\x1a\x1agoogle/iam/v1/policy.proto\x1a#google/longrunning/operations.proto\x1a\x1bgoogle/protobuf/empty.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\x92\x01\n\x08\x44\x61tabase\x12\x0c\n\x04name\x18\x01 \x01(\t\x12?\n\x05state\x18\x02 \x01(\x0e\x32\x30.google.spanner.admin.database.v1.Database.State\"7\n\x05State\x12\x15\n\x11STATE_UNSPECIFIED\x10\x00\x12\x0c\n\x08\x43REATING\x10\x01\x12\t\n\x05READY\x10\x02\"M\n\x14ListDatabasesRequest\x12\x0e\n\x06parent\x18\x01 \x01(\t\x12\x11\n\tpage_size\x18\x03 \x01(\x05\x12\x12\n\npage_token\x18\x04 \x01(\t\"o\n\x15ListDatabasesResponse\x12=\n\tdatabases\x18\x01 \x03(\x0b\x32*.google.spanner.admin.database.v1.Database\x12\x17\n\x0fnext_page_token\x18\x02 \x01(\t\"[\n\x15\x43reateDatabaseRequest\x12\x0e\n\x06parent\x18\x01 \x01(\t\x12\x18\n\x10\x63reate_statement\x18\x02 \x01(\t\x12\x18\n\x10\x65xtra_statements\x18\x03 \x03(\t\"*\n\x16\x43reateDatabaseMetadata\x12\x10\n\x08\x64\x61tabase\x18\x01 \x01(\t\"\"\n\x12GetDatabaseRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"V\n\x18UpdateDatabaseDdlRequest\x12\x10\n\x08\x64\x61tabase\x18\x01 \x01(\t\x12\x12\n\nstatements\x18\x02 \x03(\t\x12\x14\n\x0coperation_id\x18\x03 \x01(\t\"x\n\x19UpdateDatabaseDdlMetadata\x12\x10\n\x08\x64\x61tabase\x18\x01 \x01(\t\x12\x12\n\nstatements\x18\x02 \x03(\t\x12\x35\n\x11\x63ommit_timestamps\x18\x03 \x03(\x0b\x32\x1a.google.protobuf.Timestamp\"\'\n\x13\x44ropDatabaseRequest\x12\x10\n\x08\x64\x61tabase\x18\x01 \x01(\t\")\n\x15GetDatabaseDdlRequest\x12\x10\n\x08\x64\x61tabase\x18\x01 \x01(\t\",\n\x16GetDatabaseDdlResponse\x12\x12\n\nstatements\x18\x01 \x03(\t2\x95\x0c\n\rDatabaseAdmin\x12\xb7\x01\n\rListDatabases\x12\x36.google.spanner.admin.database.v1.ListDatabasesRequest\x1a\x37.google.spanner.admin.database.v1.ListDatabasesResponse\"5\x82\xd3\xe4\x93\x02/\x12-/v1/{parent=projects/*/instances/*}/databases\x12\xa2\x01\n\x0e\x43reateDatabase\x12\x37.google.spanner.admin.database.v1.CreateDatabaseRequest\x1a\x1d.google.longrunning.Operation\"8\x82\xd3\xe4\x93\x02\x32\"-/v1/{parent=projects/*/instances/*}/databases:\x01*\x12\xa6\x01\n\x0bGetDatabase\x12\x34.google.spanner.admin.database.v1.GetDatabaseRequest\x1a*.google.spanner.admin.database.v1.Database\"5\x82\xd3\xe4\x93\x02/\x12-/v1/{name=projects/*/instances/*/databases/*}\x12\xb0\x01\n\x11UpdateDatabaseDdl\x12:.google.spanner.admin.database.v1.UpdateDatabaseDdlRequest\x1a\x1d.google.longrunning.Operation\"@\x82\xd3\xe4\x93\x02:25/v1/{database=projects/*/instances/*/databases/*}/ddl:\x01*\x12\x98\x01\n\x0c\x44ropDatabase\x12\x35.google.spanner.admin.database.v1.DropDatabaseRequest\x1a\x16.google.protobuf.Empty\"9\x82\xd3\xe4\x93\x02\x33*1/v1/{database=projects/*/instances/*/databases/*}\x12\xc2\x01\n\x0eGetDatabaseDdl\x12\x37.google.spanner.admin.database.v1.GetDatabaseDdlRequest\x1a\x38.google.spanner.admin.database.v1.GetDatabaseDdlResponse\"=\x82\xd3\xe4\x93\x02\x37\x12\x35/v1/{database=projects/*/instances/*/databases/*}/ddl\x12\x94\x01\n\x0cSetIamPolicy\x12\".google.iam.v1.SetIamPolicyRequest\x1a\x15.google.iam.v1.Policy\"I\x82\xd3\xe4\x93\x02\x43\">/v1/{resource=projects/*/instances/*/databases/*}:setIamPolicy:\x01*\x12\x94\x01\n\x0cGetIamPolicy\x12\".google.iam.v1.GetIamPolicyRequest\x1a\x15.google.iam.v1.Policy\"I\x82\xd3\xe4\x93\x02\x43\">/v1/{resource=projects/*/instances/*/databases/*}:getIamPolicy:\x01*\x12\xba\x01\n\x12TestIamPermissions\x12(.google.iam.v1.TestIamPermissionsRequest\x1a).google.iam.v1.TestIamPermissionsResponse\"O\x82\xd3\xe4\x93\x02I\"D/v1/{resource=projects/*/instances/*/databases/*}:testIamPermissions:\x01*B\xdf\x01\n$com.google.spanner.admin.database.v1B\x19SpannerDatabaseAdminProtoP\x01ZHgoogle.golang.org/genproto/googleapis/spanner/admin/database/v1;database\xaa\x02&Google.Cloud.Spanner.Admin.Database.V1\xca\x02&Google\\Cloud\\Spanner\\Admin\\Database\\V1b\x06proto3') , - dependencies=[google_dot_api_dot_annotations__pb2.DESCRIPTOR,google_dot_api_dot_auth__pb2.DESCRIPTOR,google_dot_iam_dot_v1_dot_iam__policy__pb2.DESCRIPTOR,google_dot_iam_dot_v1_dot_policy__pb2.DESCRIPTOR,google_dot_longrunning_dot_operations__pb2.DESCRIPTOR,google_dot_protobuf_dot_empty__pb2.DESCRIPTOR,google_dot_protobuf_dot_timestamp__pb2.DESCRIPTOR,]) + dependencies=[google_dot_api_dot_annotations__pb2.DESCRIPTOR,google_dot_iam_dot_v1_dot_iam__policy__pb2.DESCRIPTOR,google_dot_iam_dot_v1_dot_policy__pb2.DESCRIPTOR,google_dot_longrunning_dot_operations__pb2.DESCRIPTOR,google_dot_protobuf_dot_empty__pb2.DESCRIPTOR,google_dot_protobuf_dot_timestamp__pb2.DESCRIPTOR,]) _sym_db.RegisterFileDescriptor(DESCRIPTOR) @@ -54,8 +53,8 @@ ], containing_type=None, options=None, - serialized_start=415, - serialized_end=470, + serialized_start=392, + serialized_end=447, ) _sym_db.RegisterEnumDescriptor(_DATABASE_STATE) @@ -94,8 +93,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=324, - serialized_end=470, + serialized_start=301, + serialized_end=447, ) @@ -139,8 +138,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=472, - serialized_end=549, + serialized_start=449, + serialized_end=526, ) @@ -177,8 +176,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=551, - serialized_end=662, + serialized_start=528, + serialized_end=639, ) @@ -222,8 +221,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=664, - serialized_end=755, + serialized_start=641, + serialized_end=732, ) @@ -253,8 +252,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=757, - serialized_end=799, + serialized_start=734, + serialized_end=776, ) @@ -284,8 +283,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=801, - serialized_end=835, + serialized_start=778, + serialized_end=812, ) @@ -329,8 +328,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=837, - serialized_end=923, + serialized_start=814, + serialized_end=900, ) @@ -374,8 +373,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=925, - serialized_end=1045, + serialized_start=902, + serialized_end=1022, ) @@ -405,8 +404,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1047, - serialized_end=1086, + serialized_start=1024, + serialized_end=1063, ) @@ -436,8 +435,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1088, - serialized_end=1129, + serialized_start=1065, + serialized_end=1106, ) @@ -467,8 +466,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1131, - serialized_end=1175, + serialized_start=1108, + serialized_end=1152, ) _DATABASE.fields_by_name['state'].enum_type = _DATABASE_STATE @@ -571,7 +570,9 @@ Required. A ``CREATE DATABASE`` statement, which specifies the ID of the new database. The database ID must conform to the regular expression ``[a-z][a-z0-9_\-]*[a-z0-9]`` and be - between 2 and 30 characters in length. + between 2 and 30 characters in length. If the database ID is a + reserved word or if it contains a hyphen, the database ID must + be enclosed in backticks (`````). extra_statements: An optional list of DDL statements to run inside the newly created database. Statements can create tables, indexes, etc. @@ -744,7 +745,7 @@ DESCRIPTOR.has_options = True -DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n$com.google.spanner.admin.database.v1B\031SpannerDatabaseAdminProtoP\001ZHgoogle.golang.org/genproto/googleapis/spanner/admin/database/v1;database\252\002&Google.Cloud.Spanner.Admin.Database.V1')) +DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n$com.google.spanner.admin.database.v1B\031SpannerDatabaseAdminProtoP\001ZHgoogle.golang.org/genproto/googleapis/spanner/admin/database/v1;database\252\002&Google.Cloud.Spanner.Admin.Database.V1\312\002&Google\\Cloud\\Spanner\\Admin\\Database\\V1')) try: # THESE ELEMENTS WILL BE DEPRECATED. # Please use the generated *_pb2_grpc.py files instead. diff --git a/spanner/google/cloud/spanner_admin_database_v1/types.py b/spanner/google/cloud/spanner_admin_database_v1/types.py index a0a70ad70d8a..29d4e3aaf3b4 100644 --- a/spanner/google/cloud/spanner_admin_database_v1/types.py +++ b/spanner/google/cloud/spanner_admin_database_v1/types.py @@ -1,10 +1,10 @@ -# Copyright 2017, Google LLC All rights reserved. +# Copyright 2017 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 +# https://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, @@ -15,9 +15,8 @@ from __future__ import absolute_import import sys -from google.gax.utils.messages import get_messages +from google.api_core.protobuf_helpers import get_messages -from google.api import auth_pb2 from google.api import http_pb2 from google.cloud.spanner_admin_database_v1.proto import spanner_database_admin_pb2 from google.iam.v1 import iam_policy_pb2 @@ -32,7 +31,6 @@ names = [] for module in ( - auth_pb2, http_pb2, spanner_database_admin_pb2, iam_policy_pb2, @@ -43,7 +41,8 @@ descriptor_pb2, empty_pb2, timestamp_pb2, - status_pb2, ): + status_pb2, +): for name, message in get_messages(module).items(): message.__module__ = 'google.cloud.spanner_admin_database_v1.types' setattr(sys.modules[__name__], name, message) diff --git a/spanner/google/cloud/spanner_admin_instance_v1/__init__.py b/spanner/google/cloud/spanner_admin_instance_v1/__init__.py index faf6c4519ab1..4bc788f6a392 100644 --- a/spanner/google/cloud/spanner_admin_instance_v1/__init__.py +++ b/spanner/google/cloud/spanner_admin_instance_v1/__init__.py @@ -1,10 +1,10 @@ -# Copyright 2017, Google LLC All rights reserved. +# Copyright 2017 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 +# https://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, @@ -27,4 +27,5 @@ class InstanceAdminClient(instance_admin_client.InstanceAdminClient): __all__ = ( 'enums', 'types', - 'InstanceAdminClient', ) + 'InstanceAdminClient', +) diff --git a/spanner/google/cloud/spanner_admin_instance_v1/gapic/enums.py b/spanner/google/cloud/spanner_admin_instance_v1/gapic/enums.py index c2712c4c32be..7c8b014a4d67 100644 --- a/spanner/google/cloud/spanner_admin_instance_v1/gapic/enums.py +++ b/spanner/google/cloud/spanner_admin_instance_v1/gapic/enums.py @@ -1,10 +1,10 @@ -# Copyright 2017, Google LLC All rights reserved. +# Copyright 2017 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 +# https://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, diff --git a/spanner/google/cloud/spanner_admin_instance_v1/gapic/instance_admin_client.py b/spanner/google/cloud/spanner_admin_instance_v1/gapic/instance_admin_client.py index 3ea27acd34c7..4080492a1ab6 100644 --- a/spanner/google/cloud/spanner_admin_instance_v1/gapic/instance_admin_client.py +++ b/spanner/google/cloud/spanner_admin_instance_v1/gapic/instance_admin_client.py @@ -1,38 +1,29 @@ -# Copyright 2017, Google LLC All rights reserved. +# Copyright 2017 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 +# https://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. -# -# EDITING INSTRUCTIONS -# This file was generated from the file -# https://github.com/google/googleapis/blob/master/google/spanner/admin/instance/v1/spanner_instance_admin.proto, -# and updates to that file get reflected here through a refresh process. -# For the short term, the refresh process will only be runnable by Google engineers. -# -# The only allowed edits are to method and file documentation. A 3-way -# merge preserves those additions if the generated source changes. """Accesses the google.spanner.admin.instance.v1 InstanceAdmin API.""" -import collections -import json -import os +import functools import pkg_resources -import platform -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.client_info +import google.api_core.gapic_v1.config +import google.api_core.gapic_v1.method +import google.api_core.grpc_helpers +import google.api_core.operation +import google.api_core.operations_v1 +import google.api_core.page_iterator +import google.api_core.path_template from google.cloud.spanner_admin_instance_v1.gapic import enums from google.cloud.spanner_admin_instance_v1.gapic import instance_admin_client_config @@ -41,7 +32,8 @@ from google.iam.v1 import policy_pb2 from google.protobuf import field_mask_pb2 -_PageDesc = google.gax.PageDescriptor +_GAPIC_LIBRARY_VERSION = pkg_resources.get_distribution( + 'google-cloud-spanner', ).version class InstanceAdminClient(object): @@ -69,250 +61,183 @@ class InstanceAdminClient(object): databases in that instance, and their performance may suffer. """ - SERVICE_ADDRESS = 'spanner.googleapis.com' + SERVICE_ADDRESS = 'spanner.googleapis.com:443' """The default address of the service.""" - DEFAULT_SERVICE_PORT = 443 - """The default port of the service.""" - - _PAGE_DESCRIPTORS = { - 'list_instance_configs': - _PageDesc('page_token', 'next_page_token', 'instance_configs'), - 'list_instances': - _PageDesc('page_token', 'next_page_token', 'instances') - } - # The scopes needed to make gRPC calls to all of the methods defined in # this service - _ALL_SCOPES = ( + _DEFAULT_SCOPES = ( 'https://www.googleapis.com/auth/cloud-platform', - 'https://www.googleapis.com/auth/spanner.admin', ) + 'https://www.googleapis.com/auth/spanner.admin', + ) - _PROJECT_PATH_TEMPLATE = path_template.PathTemplate('projects/{project}') - _INSTANCE_CONFIG_PATH_TEMPLATE = path_template.PathTemplate( - 'projects/{project}/instanceConfigs/{instance_config}') - _INSTANCE_PATH_TEMPLATE = path_template.PathTemplate( - 'projects/{project}/instances/{instance}') + # The name of the interface for this client. This is the key used to find + # method configuration in the client_config dictionary. + _INTERFACE_NAME = 'google.spanner.admin.instance.v1.InstanceAdmin' @classmethod def project_path(cls, project): - """Returns a fully-qualified project resource name string.""" - return cls._PROJECT_PATH_TEMPLATE.render({ - 'project': project, - }) + """Return a fully-qualified project string.""" + return google.api_core.path_template.expand( + 'projects/{project}', + project=project, + ) @classmethod def instance_config_path(cls, project, instance_config): - """Returns a fully-qualified instance_config resource name string.""" - return cls._INSTANCE_CONFIG_PATH_TEMPLATE.render({ - 'project': - project, - 'instance_config': - instance_config, - }) + """Return a fully-qualified instance_config string.""" + return google.api_core.path_template.expand( + 'projects/{project}/instanceConfigs/{instance_config}', + project=project, + instance_config=instance_config, + ) @classmethod def instance_path(cls, project, instance): - """Returns a fully-qualified instance resource name string.""" - return cls._INSTANCE_PATH_TEMPLATE.render({ - 'project': project, - 'instance': instance, - }) - - @classmethod - def match_project_from_project_name(cls, project_name): - """Parses the project from a project resource. - - Args: - project_name (str): A fully-qualified path representing a project - resource. - - Returns: - A string representing the project. - """ - return cls._PROJECT_PATH_TEMPLATE.match(project_name).get('project') - - @classmethod - def match_project_from_instance_config_name(cls, instance_config_name): - """Parses the project from a instance_config resource. - - Args: - instance_config_name (str): A fully-qualified path representing a instance_config - resource. - - Returns: - A string representing the project. - """ - return cls._INSTANCE_CONFIG_PATH_TEMPLATE.match( - instance_config_name).get('project') - - @classmethod - def match_instance_config_from_instance_config_name( - cls, instance_config_name): - """Parses the instance_config from a instance_config resource. - - Args: - instance_config_name (str): A fully-qualified path representing a instance_config - resource. - - Returns: - A string representing the instance_config. - """ - return cls._INSTANCE_CONFIG_PATH_TEMPLATE.match( - instance_config_name).get('instance_config') - - @classmethod - def match_project_from_instance_name(cls, instance_name): - """Parses the project from a instance resource. - - Args: - instance_name (str): A fully-qualified path representing a instance - resource. - - Returns: - A string representing the project. - """ - return cls._INSTANCE_PATH_TEMPLATE.match(instance_name).get('project') - - @classmethod - def match_instance_from_instance_name(cls, instance_name): - """Parses the instance from a instance resource. - - Args: - instance_name (str): A fully-qualified path representing a instance - resource. - - Returns: - A string representing the instance. - """ - return cls._INSTANCE_PATH_TEMPLATE.match(instance_name).get('instance') + """Return a fully-qualified instance string.""" + return google.api_core.path_template.expand( + 'projects/{project}/instances/{instance}', + project=project, + instance=instance, + ) def __init__(self, channel=None, credentials=None, - ssl_credentials=None, - scopes=None, - client_config=None, - lib_name=None, - lib_version='', - metrics_headers=()): + client_config=instance_admin_client_config.config, + client_info=None): """Constructor. Args: - channel (~grpc.Channel): A ``Channel`` instance through - which to make calls. - credentials (~google.auth.credentials.Credentials): The authorization - credentials to attach to requests. These credentials identify this - application to the service. - ssl_credentials (~grpc.ChannelCredentials): A - ``ChannelCredentials`` instance for use with an SSL-enabled - 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. - 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. + channel (grpc.Channel): A ``Channel`` instance through + which to make calls. This argument is mutually exclusive + with ``credentials``; providing both will raise an exception. + credentials (google.auth.credentials.Credentials): The + authorization credentials to attach to requests. These + credentials identify this application to the service. If none + are specified, the client will attempt to ascertain the + credentials from the environment. + client_config (dict): A dictionary of call options for each + method. If not specified, the default configuration is used. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. """ - # Unless the calling application specifically requested - # OAuth scopes, request everything. - if scopes is None: - scopes = self._ALL_SCOPES - - # Initialize an empty client config, if none is set. - 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-spanner', ).version - - # Load the configuration defaults. - defaults = api_callable.construct_settings( - 'google.spanner.admin.instance.v1.InstanceAdmin', - instance_admin_client_config.config, - client_config, - config.STATUS_CODE_NAMES, - metrics_headers=metrics_headers, - page_descriptors=self._PAGE_DESCRIPTORS, ) - self.instance_admin_stub = config.create_stub( - spanner_instance_admin_pb2.InstanceAdminStub, - channel=channel, - service_path=self.SERVICE_ADDRESS, - service_port=self.DEFAULT_SERVICE_PORT, - credentials=credentials, - scopes=scopes, - ssl_credentials=ssl_credentials) - - self.operations_client = operations_client.OperationsClient( - service_path=self.SERVICE_ADDRESS, - channel=channel, - credentials=credentials, - ssl_credentials=ssl_credentials, - scopes=scopes, - client_config=client_config, - metrics_headers=metrics_headers, ) - - self._list_instance_configs = api_callable.create_api_call( + # If both `channel` and `credentials` are specified, raise an + # exception (channels come with credentials baked in already). + if channel is not None and credentials is not None: + raise ValueError( + 'The `channel` and `credentials` arguments to {} are mutually ' + 'exclusive.'.format(self.__class__.__name__), ) + + # Create the channel. + if channel is None: + channel = google.api_core.grpc_helpers.create_channel( + self.SERVICE_ADDRESS, + credentials=credentials, + scopes=self._DEFAULT_SCOPES, + ) + + # Create the gRPC stubs. + self.instance_admin_stub = ( + spanner_instance_admin_pb2.InstanceAdminStub(channel)) + + # Operations client for methods that return long-running operations + # futures. + self.operations_client = ( + google.api_core.operations_v1.OperationsClient(channel)) + + if client_info is None: + client_info = ( + google.api_core.gapic_v1.client_info.DEFAULT_CLIENT_INFO) + client_info.gapic_version = _GAPIC_LIBRARY_VERSION + + # Parse out the default settings for retry and timeout for each RPC + # from the client configuration. + # (Ordinarily, these are the defaults specified in the `*_config.py` + # file next to this one.) + method_configs = google.api_core.gapic_v1.config.parse_method_configs( + client_config['interfaces'][self._INTERFACE_NAME], ) + + # Write the "inner API call" methods to the class. + # These are wrapped versions of the gRPC stub methods, with retry and + # timeout configuration applied, called by the public methods on + # this class. + self._list_instance_configs = google.api_core.gapic_v1.method.wrap_method( self.instance_admin_stub.ListInstanceConfigs, - settings=defaults['list_instance_configs']) - self._get_instance_config = api_callable.create_api_call( + default_retry=method_configs['ListInstanceConfigs'].retry, + default_timeout=method_configs['ListInstanceConfigs'].timeout, + client_info=client_info, + ) + self._get_instance_config = google.api_core.gapic_v1.method.wrap_method( self.instance_admin_stub.GetInstanceConfig, - settings=defaults['get_instance_config']) - self._list_instances = api_callable.create_api_call( + default_retry=method_configs['GetInstanceConfig'].retry, + default_timeout=method_configs['GetInstanceConfig'].timeout, + client_info=client_info, + ) + self._list_instances = google.api_core.gapic_v1.method.wrap_method( self.instance_admin_stub.ListInstances, - settings=defaults['list_instances']) - self._get_instance = api_callable.create_api_call( + default_retry=method_configs['ListInstances'].retry, + default_timeout=method_configs['ListInstances'].timeout, + client_info=client_info, + ) + self._get_instance = google.api_core.gapic_v1.method.wrap_method( self.instance_admin_stub.GetInstance, - settings=defaults['get_instance']) - self._create_instance = api_callable.create_api_call( + default_retry=method_configs['GetInstance'].retry, + default_timeout=method_configs['GetInstance'].timeout, + client_info=client_info, + ) + self._create_instance = google.api_core.gapic_v1.method.wrap_method( self.instance_admin_stub.CreateInstance, - settings=defaults['create_instance']) - self._update_instance = api_callable.create_api_call( + default_retry=method_configs['CreateInstance'].retry, + default_timeout=method_configs['CreateInstance'].timeout, + client_info=client_info, + ) + self._update_instance = google.api_core.gapic_v1.method.wrap_method( self.instance_admin_stub.UpdateInstance, - settings=defaults['update_instance']) - self._delete_instance = api_callable.create_api_call( + default_retry=method_configs['UpdateInstance'].retry, + default_timeout=method_configs['UpdateInstance'].timeout, + client_info=client_info, + ) + self._delete_instance = google.api_core.gapic_v1.method.wrap_method( self.instance_admin_stub.DeleteInstance, - settings=defaults['delete_instance']) - self._set_iam_policy = api_callable.create_api_call( + default_retry=method_configs['DeleteInstance'].retry, + default_timeout=method_configs['DeleteInstance'].timeout, + client_info=client_info, + ) + self._set_iam_policy = google.api_core.gapic_v1.method.wrap_method( self.instance_admin_stub.SetIamPolicy, - settings=defaults['set_iam_policy']) - self._get_iam_policy = api_callable.create_api_call( + default_retry=method_configs['SetIamPolicy'].retry, + default_timeout=method_configs['SetIamPolicy'].timeout, + client_info=client_info, + ) + self._get_iam_policy = google.api_core.gapic_v1.method.wrap_method( self.instance_admin_stub.GetIamPolicy, - settings=defaults['get_iam_policy']) - self._test_iam_permissions = api_callable.create_api_call( + default_retry=method_configs['GetIamPolicy'].retry, + default_timeout=method_configs['GetIamPolicy'].timeout, + client_info=client_info, + ) + self._test_iam_permissions = google.api_core.gapic_v1.method.wrap_method( self.instance_admin_stub.TestIamPermissions, - settings=defaults['test_iam_permissions']) + default_retry=method_configs['TestIamPermissions'].retry, + default_timeout=method_configs['TestIamPermissions'].timeout, + client_info=client_info, + ) # Service calls - def list_instance_configs(self, parent, page_size=None, options=None): + def list_instance_configs(self, + parent, + page_size=None, + retry=google.api_core.gapic_v1.method.DEFAULT, + timeout=google.api_core.gapic_v1.method.DEFAULT, + metadata=None): """ Lists the supported instance configurations for a given project. Example: >>> from google.cloud import spanner_admin_instance_v1 - >>> from google.gax import CallOptions, INITIAL_PAGE >>> >>> client = spanner_admin_instance_v1.InstanceAdminClient() >>> @@ -339,8 +264,12 @@ def list_instance_configs(self, parent, page_size=None, options=None): resource, this parameter does not affect the return value. If page streaming is performed per-page, this determines the maximum number of resources in a page. - options (~google.gax.CallOptions): Overrides the default - settings for this call, e.g, timeout, retries etc. + retry (Optional[google.api_core.retry.Retry]): A retry object used + to retry requests. If ``None`` is specified, requests will not + be retried. + timeout (Optional[float]): The amount of time, in seconds, to wait + for the request to complete. Note that if ``retry`` is + specified, the timeout applies to each individual attempt. Returns: A :class:`~google.gax.PageIterator` instance. By default, this @@ -349,14 +278,33 @@ def list_instance_configs(self, parent, page_size=None, options=None): of the response through the `options` parameter. Raises: - :exc:`google.gax.errors.GaxError` if the RPC is aborted. - :exc:`ValueError` if the parameters are invalid. + google.api_core.exceptions.GoogleAPICallError: If the request + failed for any reason. + google.api_core.exceptions.RetryError: If the request failed due + to a retryable error and retry attempts failed. + ValueError: If the parameters are invalid. """ request = spanner_instance_admin_pb2.ListInstanceConfigsRequest( - parent=parent, page_size=page_size) - return self._list_instance_configs(request, options) - - def get_instance_config(self, name, options=None): + parent=parent, + page_size=page_size, + ) + iterator = google.api_core.page_iterator.GRPCIterator( + client=None, + method=functools.partial( + self._list_instance_configs, retry=retry, timeout=timeout, + metadata=metadata), + request=request, + items_field='instance_configs', + request_token_field='page_token', + response_token_field='next_page_token', + ) + return iterator + + def get_instance_config(self, + name, + retry=google.api_core.gapic_v1.method.DEFAULT, + timeout=google.api_core.gapic_v1.method.DEFAULT, + metadata=None): """ Gets information about a particular instance configuration. @@ -372,31 +320,40 @@ def get_instance_config(self, name, options=None): Args: name (str): Required. The name of the requested instance configuration. Values are of the form ``projects//instanceConfigs/``. - options (~google.gax.CallOptions): Overrides the default - settings for this call, e.g, timeout, retries etc. + retry (Optional[google.api_core.retry.Retry]): A retry object used + to retry requests. If ``None`` is specified, requests will not + be retried. + timeout (Optional[float]): The amount of time, in seconds, to wait + for the request to complete. Note that if ``retry`` is + specified, the timeout applies to each individual attempt. Returns: A :class:`~google.cloud.spanner_admin_instance_v1.types.InstanceConfig` instance. Raises: - :exc:`google.gax.errors.GaxError` if the RPC is aborted. - :exc:`ValueError` if the parameters are invalid. + google.api_core.exceptions.GoogleAPICallError: If the request + failed for any reason. + google.api_core.exceptions.RetryError: If the request failed due + to a retryable error and retry attempts failed. + ValueError: If the parameters are invalid. """ request = spanner_instance_admin_pb2.GetInstanceConfigRequest( - name=name) - return self._get_instance_config(request, options) + name=name, ) + return self._get_instance_config( + request, retry=retry, timeout=timeout, metadata=metadata) def list_instances(self, parent, page_size=None, filter_=None, - options=None): + retry=google.api_core.gapic_v1.method.DEFAULT, + timeout=google.api_core.gapic_v1.method.DEFAULT, + metadata=None): """ Lists all instances in the given project. Example: >>> from google.cloud import spanner_admin_instance_v1 - >>> from google.gax import CallOptions, INITIAL_PAGE >>> >>> client = spanner_admin_instance_v1.InstanceAdminClient() >>> @@ -425,24 +382,26 @@ def list_instances(self, filter_ (str): An expression for filtering the results of the request. Filter rules are case insensitive. The fields eligible for filtering are: - * name - * display_name - * labels.key where key is the name of a label + * ``name`` + * ``display_name`` + * ``labels.key`` where key is the name of a label Some examples of using filters are: - * name:* --> The instance has a name. - * name:Howl --> The instance's name contains the string \"howl\". - * name:HOWL --> Equivalent to above. - * NAME:howl --> Equivalent to above. - * labels.env:* --> The instance has the label \"env\". - * labels.env:dev --> The instance has the label \"env\" and the value of - the label contains the string \"dev\". - * name:howl labels.env:dev --> The instance's name contains \"howl\" and - it has the label \"env\" with its value containing \"dev\". - - options (~google.gax.CallOptions): Overrides the default - settings for this call, e.g, timeout, retries etc. + * ``name:*`` --> The instance has a name. + * ``name:Howl`` --> The instance's name contains the string \"howl\". + * ``name:HOWL`` --> Equivalent to above. + * ``NAME:howl`` --> Equivalent to above. + * ``labels.env:*`` --> The instance has the label \"env\". + * ``labels.env:dev`` --> The instance has the label \"env\" and the value of the label contains the string \"dev\". + * ``name:howl labels.env:dev`` --> The instance's name contains \"howl\" and it has the label \"env\" with its value containing \"dev\". + + retry (Optional[google.api_core.retry.Retry]): A retry object used + to retry requests. If ``None`` is specified, requests will not + be retried. + timeout (Optional[float]): The amount of time, in seconds, to wait + for the request to complete. Note that if ``retry`` is + specified, the timeout applies to each individual attempt. Returns: A :class:`~google.gax.PageIterator` instance. By default, this @@ -451,14 +410,34 @@ def list_instances(self, of the response through the `options` parameter. Raises: - :exc:`google.gax.errors.GaxError` if the RPC is aborted. - :exc:`ValueError` if the parameters are invalid. + google.api_core.exceptions.GoogleAPICallError: If the request + failed for any reason. + google.api_core.exceptions.RetryError: If the request failed due + to a retryable error and retry attempts failed. + ValueError: If the parameters are invalid. """ request = spanner_instance_admin_pb2.ListInstancesRequest( - parent=parent, page_size=page_size, filter=filter_) - return self._list_instances(request, options) - - def get_instance(self, name, options=None): + parent=parent, + page_size=page_size, + filter=filter_, + ) + iterator = google.api_core.page_iterator.GRPCIterator( + client=None, + method=functools.partial( + self._list_instances, retry=retry, timeout=timeout, + metadata=metadata), + request=request, + items_field='instances', + request_token_field='page_token', + response_token_field='next_page_token', + ) + return iterator + + def get_instance(self, + name, + retry=google.api_core.gapic_v1.method.DEFAULT, + timeout=google.api_core.gapic_v1.method.DEFAULT, + metadata=None): """ Gets information about a particular instance. @@ -474,20 +453,34 @@ def get_instance(self, name, options=None): Args: name (str): Required. The name of the requested instance. Values are of the form ``projects//instances/``. - options (~google.gax.CallOptions): Overrides the default - settings for this call, e.g, timeout, retries etc. + retry (Optional[google.api_core.retry.Retry]): A retry object used + to retry requests. If ``None`` is specified, requests will not + be retried. + timeout (Optional[float]): The amount of time, in seconds, to wait + for the request to complete. Note that if ``retry`` is + specified, the timeout applies to each individual attempt. Returns: A :class:`~google.cloud.spanner_admin_instance_v1.types.Instance` instance. Raises: - :exc:`google.gax.errors.GaxError` if the RPC is aborted. - :exc:`ValueError` if the parameters are invalid. + google.api_core.exceptions.GoogleAPICallError: If the request + failed for any reason. + google.api_core.exceptions.RetryError: If the request failed due + to a retryable error and retry attempts failed. + ValueError: If the parameters are invalid. """ - request = spanner_instance_admin_pb2.GetInstanceRequest(name=name) - return self._get_instance(request, options) - - def create_instance(self, parent, instance_id, instance, options=None): + request = spanner_instance_admin_pb2.GetInstanceRequest(name=name, ) + return self._get_instance( + request, retry=retry, timeout=timeout, metadata=metadata) + + def create_instance(self, + parent, + instance_id, + instance, + retry=google.api_core.gapic_v1.method.DEFAULT, + timeout=google.api_core.gapic_v1.method.DEFAULT, + metadata=None): """ Creates an instance and begins preparing it to begin serving. The returned ``long-running operation`` @@ -554,24 +547,43 @@ def create_instance(self, parent, instance_id, instance, options=None): specified must be ``/instances/``. If a dict is provided, it must be of the same form as the protobuf message :class:`~google.cloud.spanner_admin_instance_v1.types.Instance` - options (~google.gax.CallOptions): Overrides the default - settings for this call, e.g, timeout, retries etc. + retry (Optional[google.api_core.retry.Retry]): A retry object used + to retry requests. If ``None`` is specified, requests will not + be retried. + timeout (Optional[float]): The amount of time, in seconds, to wait + for the request to complete. Note that if ``retry`` is + specified, the timeout applies to each individual attempt. Returns: A :class:`~google.cloud.spanner_admin_instance_v1.types._OperationFuture` instance. Raises: - :exc:`google.gax.errors.GaxError` if the RPC is aborted. - :exc:`ValueError` if the parameters are invalid. + google.api_core.exceptions.GoogleAPICallError: If the request + failed for any reason. + google.api_core.exceptions.RetryError: If the request failed due + to a retryable error and retry attempts failed. + ValueError: If the parameters are invalid. """ request = spanner_instance_admin_pb2.CreateInstanceRequest( - parent=parent, instance_id=instance_id, instance=instance) - return google.gax._OperationFuture( - self._create_instance(request, options), self.operations_client, + parent=parent, + instance_id=instance_id, + instance=instance, + ) + operation = self._create_instance( + request, retry=retry, timeout=timeout, metadata=metadata) + return google.api_core.operation.from_gapic( + operation, + self.operations_client, spanner_instance_admin_pb2.Instance, - spanner_instance_admin_pb2.CreateInstanceMetadata, options) - - def update_instance(self, instance, field_mask, options=None): + metadata_type=spanner_instance_admin_pb2.CreateInstanceMetadata, + ) + + def update_instance(self, + instance, + field_mask, + retry=google.api_core.gapic_v1.method.DEFAULT, + timeout=google.api_core.gapic_v1.method.DEFAULT, + metadata=None): """ Updates an instance, and begins allocating or releasing resources as requested. The returned [long-running @@ -644,24 +656,41 @@ def update_instance(self, instance, field_mask, options=None): about them. If a dict is provided, it must be of the same form as the protobuf message :class:`~google.cloud.spanner_admin_instance_v1.types.FieldMask` - options (~google.gax.CallOptions): Overrides the default - settings for this call, e.g, timeout, retries etc. + retry (Optional[google.api_core.retry.Retry]): A retry object used + to retry requests. If ``None`` is specified, requests will not + be retried. + timeout (Optional[float]): The amount of time, in seconds, to wait + for the request to complete. Note that if ``retry`` is + specified, the timeout applies to each individual attempt. Returns: A :class:`~google.cloud.spanner_admin_instance_v1.types._OperationFuture` instance. Raises: - :exc:`google.gax.errors.GaxError` if the RPC is aborted. - :exc:`ValueError` if the parameters are invalid. + google.api_core.exceptions.GoogleAPICallError: If the request + failed for any reason. + google.api_core.exceptions.RetryError: If the request failed due + to a retryable error and retry attempts failed. + ValueError: If the parameters are invalid. """ request = spanner_instance_admin_pb2.UpdateInstanceRequest( - instance=instance, field_mask=field_mask) - return google.gax._OperationFuture( - self._update_instance(request, options), self.operations_client, + instance=instance, + field_mask=field_mask, + ) + operation = self._update_instance( + request, retry=retry, timeout=timeout, metadata=metadata) + return google.api_core.operation.from_gapic( + operation, + self.operations_client, spanner_instance_admin_pb2.Instance, - spanner_instance_admin_pb2.UpdateInstanceMetadata, options) - - def delete_instance(self, name, options=None): + metadata_type=spanner_instance_admin_pb2.UpdateInstanceMetadata, + ) + + def delete_instance(self, + name, + retry=google.api_core.gapic_v1.method.DEFAULT, + timeout=google.api_core.gapic_v1.method.DEFAULT, + metadata=None): """ Deletes an instance. @@ -687,17 +716,30 @@ def delete_instance(self, name, options=None): Args: name (str): Required. The name of the instance to be deleted. Values are of the form ``projects//instances/`` - options (~google.gax.CallOptions): Overrides the default - settings for this call, e.g, timeout, retries etc. + retry (Optional[google.api_core.retry.Retry]): A retry object used + to retry requests. If ``None`` is specified, requests will not + be retried. + timeout (Optional[float]): The amount of time, in seconds, to wait + for the request to complete. Note that if ``retry`` is + specified, the timeout applies to each individual attempt. Raises: - :exc:`google.gax.errors.GaxError` if the RPC is aborted. - :exc:`ValueError` if the parameters are invalid. + google.api_core.exceptions.GoogleAPICallError: If the request + failed for any reason. + google.api_core.exceptions.RetryError: If the request failed due + to a retryable error and retry attempts failed. + ValueError: If the parameters are invalid. """ - request = spanner_instance_admin_pb2.DeleteInstanceRequest(name=name) - self._delete_instance(request, options) - - def set_iam_policy(self, resource, policy, options=None): + request = spanner_instance_admin_pb2.DeleteInstanceRequest(name=name, ) + self._delete_instance( + request, retry=retry, timeout=timeout, metadata=metadata) + + def set_iam_policy(self, + resource, + policy, + retry=google.api_core.gapic_v1.method.DEFAULT, + timeout=google.api_core.gapic_v1.method.DEFAULT, + metadata=None): """ Sets the access control policy on an instance resource. Replaces any existing policy. @@ -725,21 +767,35 @@ def set_iam_policy(self, resource, policy, options=None): might reject them. If a dict is provided, it must be of the same form as the protobuf message :class:`~google.cloud.spanner_admin_instance_v1.types.Policy` - options (~google.gax.CallOptions): Overrides the default - settings for this call, e.g, timeout, retries etc. + retry (Optional[google.api_core.retry.Retry]): A retry object used + to retry requests. If ``None`` is specified, requests will not + be retried. + timeout (Optional[float]): The amount of time, in seconds, to wait + for the request to complete. Note that if ``retry`` is + specified, the timeout applies to each individual attempt. Returns: A :class:`~google.cloud.spanner_admin_instance_v1.types.Policy` instance. Raises: - :exc:`google.gax.errors.GaxError` if the RPC is aborted. - :exc:`ValueError` if the parameters are invalid. + google.api_core.exceptions.GoogleAPICallError: If the request + failed for any reason. + google.api_core.exceptions.RetryError: If the request failed due + to a retryable error and retry attempts failed. + ValueError: If the parameters are invalid. """ request = iam_policy_pb2.SetIamPolicyRequest( - resource=resource, policy=policy) - return self._set_iam_policy(request, options) - - def get_iam_policy(self, resource, options=None): + resource=resource, + policy=policy, + ) + return self._set_iam_policy( + request, retry=retry, timeout=timeout, metadata=metadata) + + def get_iam_policy(self, + resource, + retry=google.api_core.gapic_v1.method.DEFAULT, + timeout=google.api_core.gapic_v1.method.DEFAULT, + metadata=None): """ Gets the access control policy for an instance resource. Returns an empty policy if an instance exists but does not have a policy set. @@ -760,20 +816,33 @@ def get_iam_policy(self, resource, options=None): resource (str): REQUIRED: The resource for which the policy is being requested. ``resource`` is usually specified as a path. For example, a Project resource is specified as ``projects/{project}``. - options (~google.gax.CallOptions): Overrides the default - settings for this call, e.g, timeout, retries etc. + retry (Optional[google.api_core.retry.Retry]): A retry object used + to retry requests. If ``None`` is specified, requests will not + be retried. + timeout (Optional[float]): The amount of time, in seconds, to wait + for the request to complete. Note that if ``retry`` is + specified, the timeout applies to each individual attempt. Returns: A :class:`~google.cloud.spanner_admin_instance_v1.types.Policy` instance. Raises: - :exc:`google.gax.errors.GaxError` if the RPC is aborted. - :exc:`ValueError` if the parameters are invalid. + google.api_core.exceptions.GoogleAPICallError: If the request + failed for any reason. + google.api_core.exceptions.RetryError: If the request failed due + to a retryable error and retry attempts failed. + ValueError: If the parameters are invalid. """ - request = iam_policy_pb2.GetIamPolicyRequest(resource=resource) - return self._get_iam_policy(request, options) - - def test_iam_permissions(self, resource, permissions, options=None): + request = iam_policy_pb2.GetIamPolicyRequest(resource=resource, ) + return self._get_iam_policy( + request, retry=retry, timeout=timeout, metadata=metadata) + + def test_iam_permissions(self, + resource, + permissions, + retry=google.api_core.gapic_v1.method.DEFAULT, + timeout=google.api_core.gapic_v1.method.DEFAULT, + metadata=None): """ Returns permissions that the caller has on the specified instance resource. @@ -800,16 +869,26 @@ def test_iam_permissions(self, resource, permissions, options=None): wildcards (such as '*' or 'storage.*') are not allowed. For more information see `IAM Overview `_. - options (~google.gax.CallOptions): Overrides the default - settings for this call, e.g, timeout, retries etc. + retry (Optional[google.api_core.retry.Retry]): A retry object used + to retry requests. If ``None`` is specified, requests will not + be retried. + timeout (Optional[float]): The amount of time, in seconds, to wait + for the request to complete. Note that if ``retry`` is + specified, the timeout applies to each individual attempt. Returns: A :class:`~google.cloud.spanner_admin_instance_v1.types.TestIamPermissionsResponse` instance. Raises: - :exc:`google.gax.errors.GaxError` if the RPC is aborted. - :exc:`ValueError` if the parameters are invalid. + google.api_core.exceptions.GoogleAPICallError: If the request + failed for any reason. + google.api_core.exceptions.RetryError: If the request failed due + to a retryable error and retry attempts failed. + ValueError: If the parameters are invalid. """ request = iam_policy_pb2.TestIamPermissionsRequest( - resource=resource, permissions=permissions) - return self._test_iam_permissions(request, options) + resource=resource, + permissions=permissions, + ) + return self._test_iam_permissions( + request, retry=retry, timeout=timeout, metadata=metadata) diff --git a/spanner/google/cloud/spanner_admin_instance_v1/proto/spanner_instance_admin_pb2.py b/spanner/google/cloud/spanner_admin_instance_v1/proto/spanner_instance_admin_pb2.py index 8861b428e855..1725a77abb3c 100644 --- a/spanner/google/cloud/spanner_admin_instance_v1/proto/spanner_instance_admin_pb2.py +++ b/spanner/google/cloud/spanner_admin_instance_v1/proto/spanner_instance_admin_pb2.py @@ -14,7 +14,6 @@ from google.api import annotations_pb2 as google_dot_api_dot_annotations__pb2 -from google.api import auth_pb2 as google_dot_api_dot_auth__pb2 from google.iam.v1 import iam_policy_pb2 as google_dot_iam_dot_v1_dot_iam__policy__pb2 from google.iam.v1 import policy_pb2 as google_dot_iam_dot_v1_dot_policy__pb2 from google.longrunning import operations_pb2 as google_dot_longrunning_dot_operations__pb2 @@ -27,9 +26,9 @@ name='google/cloud/spanner/admin/instance_v1/proto/spanner_instance_admin.proto', package='google.spanner.admin.instance.v1', syntax='proto3', - serialized_pb=_b('\nIgoogle/cloud/spanner/admin/instance_v1/proto/spanner_instance_admin.proto\x12 google.spanner.admin.instance.v1\x1a\x1cgoogle/api/annotations.proto\x1a\x15google/api/auth.proto\x1a\x1egoogle/iam/v1/iam_policy.proto\x1a\x1agoogle/iam/v1/policy.proto\x1a#google/longrunning/operations.proto\x1a\x1bgoogle/protobuf/empty.proto\x1a google/protobuf/field_mask.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"4\n\x0eInstanceConfig\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x14\n\x0c\x64isplay_name\x18\x02 \x01(\t\"\xc3\x02\n\x08Instance\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0e\n\x06\x63onfig\x18\x02 \x01(\t\x12\x14\n\x0c\x64isplay_name\x18\x03 \x01(\t\x12\x12\n\nnode_count\x18\x05 \x01(\x05\x12?\n\x05state\x18\x06 \x01(\x0e\x32\x30.google.spanner.admin.instance.v1.Instance.State\x12\x46\n\x06labels\x18\x07 \x03(\x0b\x32\x36.google.spanner.admin.instance.v1.Instance.LabelsEntry\x1a-\n\x0bLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"7\n\x05State\x12\x15\n\x11STATE_UNSPECIFIED\x10\x00\x12\x0c\n\x08\x43REATING\x10\x01\x12\t\n\x05READY\x10\x02\"S\n\x1aListInstanceConfigsRequest\x12\x0e\n\x06parent\x18\x01 \x01(\t\x12\x11\n\tpage_size\x18\x02 \x01(\x05\x12\x12\n\npage_token\x18\x03 \x01(\t\"\x82\x01\n\x1bListInstanceConfigsResponse\x12J\n\x10instance_configs\x18\x01 \x03(\x0b\x32\x30.google.spanner.admin.instance.v1.InstanceConfig\x12\x17\n\x0fnext_page_token\x18\x02 \x01(\t\"(\n\x18GetInstanceConfigRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"\"\n\x12GetInstanceRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"z\n\x15\x43reateInstanceRequest\x12\x0e\n\x06parent\x18\x01 \x01(\t\x12\x13\n\x0binstance_id\x18\x02 \x01(\t\x12<\n\x08instance\x18\x03 \x01(\x0b\x32*.google.spanner.admin.instance.v1.Instance\"]\n\x14ListInstancesRequest\x12\x0e\n\x06parent\x18\x01 \x01(\t\x12\x11\n\tpage_size\x18\x02 \x01(\x05\x12\x12\n\npage_token\x18\x03 \x01(\t\x12\x0e\n\x06\x66ilter\x18\x04 \x01(\t\"o\n\x15ListInstancesResponse\x12=\n\tinstances\x18\x01 \x03(\x0b\x32*.google.spanner.admin.instance.v1.Instance\x12\x17\n\x0fnext_page_token\x18\x02 \x01(\t\"\x85\x01\n\x15UpdateInstanceRequest\x12<\n\x08instance\x18\x01 \x01(\x0b\x32*.google.spanner.admin.instance.v1.Instance\x12.\n\nfield_mask\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.FieldMask\"%\n\x15\x44\x65leteInstanceRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"\xe5\x01\n\x16\x43reateInstanceMetadata\x12<\n\x08instance\x18\x01 \x01(\x0b\x32*.google.spanner.admin.instance.v1.Instance\x12.\n\nstart_time\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12/\n\x0b\x63\x61ncel_time\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12,\n\x08\x65nd_time\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\"\xe5\x01\n\x16UpdateInstanceMetadata\x12<\n\x08instance\x18\x01 \x01(\x0b\x32*.google.spanner.admin.instance.v1.Instance\x12.\n\nstart_time\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12/\n\x0b\x63\x61ncel_time\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12,\n\x08\x65nd_time\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.Timestamp2\xe6\x0c\n\rInstanceAdmin\x12\xc3\x01\n\x13ListInstanceConfigs\x12<.google.spanner.admin.instance.v1.ListInstanceConfigsRequest\x1a=.google.spanner.admin.instance.v1.ListInstanceConfigsResponse\"/\x82\xd3\xe4\x93\x02)\x12\'/v1/{parent=projects/*}/instanceConfigs\x12\xb2\x01\n\x11GetInstanceConfig\x12:.google.spanner.admin.instance.v1.GetInstanceConfigRequest\x1a\x30.google.spanner.admin.instance.v1.InstanceConfig\"/\x82\xd3\xe4\x93\x02)\x12\'/v1/{name=projects/*/instanceConfigs/*}\x12\xab\x01\n\rListInstances\x12\x36.google.spanner.admin.instance.v1.ListInstancesRequest\x1a\x37.google.spanner.admin.instance.v1.ListInstancesResponse\")\x82\xd3\xe4\x93\x02#\x12!/v1/{parent=projects/*}/instances\x12\x9a\x01\n\x0bGetInstance\x12\x34.google.spanner.admin.instance.v1.GetInstanceRequest\x1a*.google.spanner.admin.instance.v1.Instance\")\x82\xd3\xe4\x93\x02#\x12!/v1/{name=projects/*/instances/*}\x12\x96\x01\n\x0e\x43reateInstance\x12\x37.google.spanner.admin.instance.v1.CreateInstanceRequest\x1a\x1d.google.longrunning.Operation\",\x82\xd3\xe4\x93\x02&\"!/v1/{parent=projects/*}/instances:\x01*\x12\x9f\x01\n\x0eUpdateInstance\x12\x37.google.spanner.admin.instance.v1.UpdateInstanceRequest\x1a\x1d.google.longrunning.Operation\"5\x82\xd3\xe4\x93\x02/2*/v1/{instance.name=projects/*/instances/*}:\x01*\x12\x8c\x01\n\x0e\x44\x65leteInstance\x12\x37.google.spanner.admin.instance.v1.DeleteInstanceRequest\x1a\x16.google.protobuf.Empty\")\x82\xd3\xe4\x93\x02#*!/v1/{name=projects/*/instances/*}\x12\x88\x01\n\x0cSetIamPolicy\x12\".google.iam.v1.SetIamPolicyRequest\x1a\x15.google.iam.v1.Policy\"=\x82\xd3\xe4\x93\x02\x37\"2/v1/{resource=projects/*/instances/*}:setIamPolicy:\x01*\x12\x88\x01\n\x0cGetIamPolicy\x12\".google.iam.v1.GetIamPolicyRequest\x1a\x15.google.iam.v1.Policy\"=\x82\xd3\xe4\x93\x02\x37\"2/v1/{resource=projects/*/instances/*}:getIamPolicy:\x01*\x12\xae\x01\n\x12TestIamPermissions\x12(.google.iam.v1.TestIamPermissionsRequest\x1a).google.iam.v1.TestIamPermissionsResponse\"C\x82\xd3\xe4\x93\x02=\"8/v1/{resource=projects/*/instances/*}:testIamPermissions:\x01*B\xb6\x01\n$com.google.spanner.admin.instance.v1B\x19SpannerInstanceAdminProtoP\x01ZHgoogle.golang.org/genproto/googleapis/spanner/admin/instance/v1;instance\xaa\x02&Google.Cloud.Spanner.Admin.Instance.V1b\x06proto3') + serialized_pb=_b('\nIgoogle/cloud/spanner/admin/instance_v1/proto/spanner_instance_admin.proto\x12 google.spanner.admin.instance.v1\x1a\x1cgoogle/api/annotations.proto\x1a\x1egoogle/iam/v1/iam_policy.proto\x1a\x1agoogle/iam/v1/policy.proto\x1a#google/longrunning/operations.proto\x1a\x1bgoogle/protobuf/empty.proto\x1a google/protobuf/field_mask.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"4\n\x0eInstanceConfig\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x14\n\x0c\x64isplay_name\x18\x02 \x01(\t\"\xc3\x02\n\x08Instance\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0e\n\x06\x63onfig\x18\x02 \x01(\t\x12\x14\n\x0c\x64isplay_name\x18\x03 \x01(\t\x12\x12\n\nnode_count\x18\x05 \x01(\x05\x12?\n\x05state\x18\x06 \x01(\x0e\x32\x30.google.spanner.admin.instance.v1.Instance.State\x12\x46\n\x06labels\x18\x07 \x03(\x0b\x32\x36.google.spanner.admin.instance.v1.Instance.LabelsEntry\x1a-\n\x0bLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"7\n\x05State\x12\x15\n\x11STATE_UNSPECIFIED\x10\x00\x12\x0c\n\x08\x43REATING\x10\x01\x12\t\n\x05READY\x10\x02\"S\n\x1aListInstanceConfigsRequest\x12\x0e\n\x06parent\x18\x01 \x01(\t\x12\x11\n\tpage_size\x18\x02 \x01(\x05\x12\x12\n\npage_token\x18\x03 \x01(\t\"\x82\x01\n\x1bListInstanceConfigsResponse\x12J\n\x10instance_configs\x18\x01 \x03(\x0b\x32\x30.google.spanner.admin.instance.v1.InstanceConfig\x12\x17\n\x0fnext_page_token\x18\x02 \x01(\t\"(\n\x18GetInstanceConfigRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"\"\n\x12GetInstanceRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"z\n\x15\x43reateInstanceRequest\x12\x0e\n\x06parent\x18\x01 \x01(\t\x12\x13\n\x0binstance_id\x18\x02 \x01(\t\x12<\n\x08instance\x18\x03 \x01(\x0b\x32*.google.spanner.admin.instance.v1.Instance\"]\n\x14ListInstancesRequest\x12\x0e\n\x06parent\x18\x01 \x01(\t\x12\x11\n\tpage_size\x18\x02 \x01(\x05\x12\x12\n\npage_token\x18\x03 \x01(\t\x12\x0e\n\x06\x66ilter\x18\x04 \x01(\t\"o\n\x15ListInstancesResponse\x12=\n\tinstances\x18\x01 \x03(\x0b\x32*.google.spanner.admin.instance.v1.Instance\x12\x17\n\x0fnext_page_token\x18\x02 \x01(\t\"\x85\x01\n\x15UpdateInstanceRequest\x12<\n\x08instance\x18\x01 \x01(\x0b\x32*.google.spanner.admin.instance.v1.Instance\x12.\n\nfield_mask\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.FieldMask\"%\n\x15\x44\x65leteInstanceRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"\xe5\x01\n\x16\x43reateInstanceMetadata\x12<\n\x08instance\x18\x01 \x01(\x0b\x32*.google.spanner.admin.instance.v1.Instance\x12.\n\nstart_time\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12/\n\x0b\x63\x61ncel_time\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12,\n\x08\x65nd_time\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\"\xe5\x01\n\x16UpdateInstanceMetadata\x12<\n\x08instance\x18\x01 \x01(\x0b\x32*.google.spanner.admin.instance.v1.Instance\x12.\n\nstart_time\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12/\n\x0b\x63\x61ncel_time\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12,\n\x08\x65nd_time\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.Timestamp2\xe6\x0c\n\rInstanceAdmin\x12\xc3\x01\n\x13ListInstanceConfigs\x12<.google.spanner.admin.instance.v1.ListInstanceConfigsRequest\x1a=.google.spanner.admin.instance.v1.ListInstanceConfigsResponse\"/\x82\xd3\xe4\x93\x02)\x12\'/v1/{parent=projects/*}/instanceConfigs\x12\xb2\x01\n\x11GetInstanceConfig\x12:.google.spanner.admin.instance.v1.GetInstanceConfigRequest\x1a\x30.google.spanner.admin.instance.v1.InstanceConfig\"/\x82\xd3\xe4\x93\x02)\x12\'/v1/{name=projects/*/instanceConfigs/*}\x12\xab\x01\n\rListInstances\x12\x36.google.spanner.admin.instance.v1.ListInstancesRequest\x1a\x37.google.spanner.admin.instance.v1.ListInstancesResponse\")\x82\xd3\xe4\x93\x02#\x12!/v1/{parent=projects/*}/instances\x12\x9a\x01\n\x0bGetInstance\x12\x34.google.spanner.admin.instance.v1.GetInstanceRequest\x1a*.google.spanner.admin.instance.v1.Instance\")\x82\xd3\xe4\x93\x02#\x12!/v1/{name=projects/*/instances/*}\x12\x96\x01\n\x0e\x43reateInstance\x12\x37.google.spanner.admin.instance.v1.CreateInstanceRequest\x1a\x1d.google.longrunning.Operation\",\x82\xd3\xe4\x93\x02&\"!/v1/{parent=projects/*}/instances:\x01*\x12\x9f\x01\n\x0eUpdateInstance\x12\x37.google.spanner.admin.instance.v1.UpdateInstanceRequest\x1a\x1d.google.longrunning.Operation\"5\x82\xd3\xe4\x93\x02/2*/v1/{instance.name=projects/*/instances/*}:\x01*\x12\x8c\x01\n\x0e\x44\x65leteInstance\x12\x37.google.spanner.admin.instance.v1.DeleteInstanceRequest\x1a\x16.google.protobuf.Empty\")\x82\xd3\xe4\x93\x02#*!/v1/{name=projects/*/instances/*}\x12\x88\x01\n\x0cSetIamPolicy\x12\".google.iam.v1.SetIamPolicyRequest\x1a\x15.google.iam.v1.Policy\"=\x82\xd3\xe4\x93\x02\x37\"2/v1/{resource=projects/*/instances/*}:setIamPolicy:\x01*\x12\x88\x01\n\x0cGetIamPolicy\x12\".google.iam.v1.GetIamPolicyRequest\x1a\x15.google.iam.v1.Policy\"=\x82\xd3\xe4\x93\x02\x37\"2/v1/{resource=projects/*/instances/*}:getIamPolicy:\x01*\x12\xae\x01\n\x12TestIamPermissions\x12(.google.iam.v1.TestIamPermissionsRequest\x1a).google.iam.v1.TestIamPermissionsResponse\"C\x82\xd3\xe4\x93\x02=\"8/v1/{resource=projects/*/instances/*}:testIamPermissions:\x01*B\xdf\x01\n$com.google.spanner.admin.instance.v1B\x19SpannerInstanceAdminProtoP\x01ZHgoogle.golang.org/genproto/googleapis/spanner/admin/instance/v1;instance\xaa\x02&Google.Cloud.Spanner.Admin.Instance.V1\xca\x02&Google\\Cloud\\Spanner\\Admin\\Instance\\V1b\x06proto3') , - dependencies=[google_dot_api_dot_annotations__pb2.DESCRIPTOR,google_dot_api_dot_auth__pb2.DESCRIPTOR,google_dot_iam_dot_v1_dot_iam__policy__pb2.DESCRIPTOR,google_dot_iam_dot_v1_dot_policy__pb2.DESCRIPTOR,google_dot_longrunning_dot_operations__pb2.DESCRIPTOR,google_dot_protobuf_dot_empty__pb2.DESCRIPTOR,google_dot_protobuf_dot_field__mask__pb2.DESCRIPTOR,google_dot_protobuf_dot_timestamp__pb2.DESCRIPTOR,]) + dependencies=[google_dot_api_dot_annotations__pb2.DESCRIPTOR,google_dot_iam_dot_v1_dot_iam__policy__pb2.DESCRIPTOR,google_dot_iam_dot_v1_dot_policy__pb2.DESCRIPTOR,google_dot_longrunning_dot_operations__pb2.DESCRIPTOR,google_dot_protobuf_dot_empty__pb2.DESCRIPTOR,google_dot_protobuf_dot_field__mask__pb2.DESCRIPTOR,google_dot_protobuf_dot_timestamp__pb2.DESCRIPTOR,]) _sym_db.RegisterFileDescriptor(DESCRIPTOR) @@ -55,8 +54,8 @@ ], containing_type=None, options=None, - serialized_start=680, - serialized_end=735, + serialized_start=657, + serialized_end=712, ) _sym_db.RegisterEnumDescriptor(_INSTANCE_STATE) @@ -94,8 +93,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=357, - serialized_end=409, + serialized_start=334, + serialized_end=386, ) @@ -132,8 +131,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=633, - serialized_end=678, + serialized_start=610, + serialized_end=655, ) _INSTANCE = _descriptor.Descriptor( @@ -198,8 +197,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=412, - serialized_end=735, + serialized_start=389, + serialized_end=712, ) @@ -243,8 +242,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=737, - serialized_end=820, + serialized_start=714, + serialized_end=797, ) @@ -281,8 +280,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=823, - serialized_end=953, + serialized_start=800, + serialized_end=930, ) @@ -312,8 +311,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=955, - serialized_end=995, + serialized_start=932, + serialized_end=972, ) @@ -343,8 +342,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=997, - serialized_end=1031, + serialized_start=974, + serialized_end=1008, ) @@ -388,8 +387,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1033, - serialized_end=1155, + serialized_start=1010, + serialized_end=1132, ) @@ -440,8 +439,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1157, - serialized_end=1250, + serialized_start=1134, + serialized_end=1227, ) @@ -478,8 +477,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1252, - serialized_end=1363, + serialized_start=1229, + serialized_end=1340, ) @@ -516,8 +515,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1366, - serialized_end=1499, + serialized_start=1343, + serialized_end=1476, ) @@ -547,8 +546,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1501, - serialized_end=1538, + serialized_start=1478, + serialized_end=1515, ) @@ -599,8 +598,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1541, - serialized_end=1770, + serialized_start=1518, + serialized_end=1747, ) @@ -651,8 +650,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1773, - serialized_end=2002, + serialized_start=1750, + serialized_end=1979, ) _INSTANCE_LABELSENTRY.containing_type = _INSTANCE @@ -740,7 +739,11 @@ in UIs. Must be unique per project and between 4 and 30 characters in length. node_count: - Required. The number of nodes allocated to this instance. + Required. The number of nodes allocated to this instance. This + may be zero in API responses for instances that are not yet in + state ``READY``. See `the documentation `__ for more + information about nodes. state: Output only. The current instance state. For [CreateInstance][ google.spanner.admin.instance.v1.InstanceAdmin.CreateInstance] @@ -908,16 +911,17 @@ filter: An expression for filtering the results of the request. Filter rules are case insensitive. The fields eligible for filtering - are: - name - display\_name - labels.key where key is the - name of a label Some examples of using filters are: - - name:\* --> The instance has a name. - name:Howl --> The - instance's name contains the string "howl". - name:HOWL --> - Equivalent to above. - NAME:howl --> Equivalent to above. - - labels.env:\* --> The instance has the label "env". - - labels.env:dev --> The instance has the label "env" and the - value of the label contains the string "dev". - name:howl - labels.env:dev --> The instance's name contains "howl" and - it has the label "env" with its value containing "dev". + are: - ``name`` - ``display_name`` - ``labels.key`` where + key is the name of a label Some examples of using filters + are: - ``name:*`` --> The instance has a name. - + ``name:Howl`` --> The instance's name contains the string + "howl". - ``name:HOWL`` --> Equivalent to above. - + ``NAME:howl`` --> Equivalent to above. - ``labels.env:*`` --> + The instance has the label "env". - ``labels.env:dev`` --> + The instance has the label "env" and the value of the label + contains the string "dev". - ``name:howl labels.env:dev`` --> + The instance's name contains "howl" and it has the label + "env" with its value containing "dev". """, # @@protoc_insertion_point(class_scope:google.spanner.admin.instance.v1.ListInstancesRequest) )) @@ -1040,7 +1044,7 @@ DESCRIPTOR.has_options = True -DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n$com.google.spanner.admin.instance.v1B\031SpannerInstanceAdminProtoP\001ZHgoogle.golang.org/genproto/googleapis/spanner/admin/instance/v1;instance\252\002&Google.Cloud.Spanner.Admin.Instance.V1')) +DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n$com.google.spanner.admin.instance.v1B\031SpannerInstanceAdminProtoP\001ZHgoogle.golang.org/genproto/googleapis/spanner/admin/instance/v1;instance\252\002&Google.Cloud.Spanner.Admin.Instance.V1\312\002&Google\\Cloud\\Spanner\\Admin\\Instance\\V1')) _INSTANCE_LABELSENTRY.has_options = True _INSTANCE_LABELSENTRY._options = _descriptor._ParseOptions(descriptor_pb2.MessageOptions(), _b('8\001')) try: diff --git a/spanner/google/cloud/spanner_admin_instance_v1/types.py b/spanner/google/cloud/spanner_admin_instance_v1/types.py index ba3ab4a64179..60ab223d10d1 100644 --- a/spanner/google/cloud/spanner_admin_instance_v1/types.py +++ b/spanner/google/cloud/spanner_admin_instance_v1/types.py @@ -1,10 +1,10 @@ -# Copyright 2017, Google LLC All rights reserved. +# Copyright 2017 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 +# https://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, @@ -15,9 +15,8 @@ from __future__ import absolute_import import sys -from google.gax.utils.messages import get_messages +from google.api_core.protobuf_helpers import get_messages -from google.api import auth_pb2 from google.api import http_pb2 from google.cloud.spanner_admin_instance_v1.proto import spanner_instance_admin_pb2 from google.iam.v1 import iam_policy_pb2 @@ -33,7 +32,6 @@ names = [] for module in ( - auth_pb2, http_pb2, spanner_instance_admin_pb2, iam_policy_pb2, @@ -45,7 +43,8 @@ empty_pb2, field_mask_pb2, timestamp_pb2, - status_pb2, ): + status_pb2, +): for name, message in get_messages(module).items(): message.__module__ = 'google.cloud.spanner_admin_instance_v1.types' setattr(sys.modules[__name__], name, message) diff --git a/spanner/google/cloud/spanner_v1/_helpers.py b/spanner/google/cloud/spanner_v1/_helpers.py index f4d7ca949344..f07b8bb9ac38 100644 --- a/spanner/google/cloud/spanner_v1/_helpers.py +++ b/spanner/google/cloud/spanner_v1/_helpers.py @@ -19,7 +19,6 @@ import six -from google.gax import CallOptions from google.protobuf.struct_pb2 import ListValue from google.protobuf.struct_pb2 import Value from google.cloud.spanner_v1.proto import type_pb2 @@ -258,17 +257,13 @@ def __init__(self, session): self._session = session -def _options_with_prefix(prefix, **kw): - """Create GAPIC options w/ prefix. +def _metadata_with_prefix(prefix, **kw): + """Create RPC metadata containing a prefix. - :type prefix: str - :param prefix: appropriate resource path + Args: + prefix (str): appropriate resource path. - :type kw: dict - :param kw: other keyword arguments passed to the constructor - - :rtype: :class:`~google.gax.CallOptions` - :returns: GAPIC call options with supplied prefix + Returns: + List[Tuple[str, str]]: RPC metadata with supplied prefix """ - return CallOptions( - metadata=[('google-cloud-resource-prefix', prefix)], **kw) + return [('google-cloud-resource-prefix', prefix)] diff --git a/spanner/google/cloud/spanner_v1/batch.py b/spanner/google/cloud/spanner_v1/batch.py index aad2cc80b46f..59540f72502f 100644 --- a/spanner/google/cloud/spanner_v1/batch.py +++ b/spanner/google/cloud/spanner_v1/batch.py @@ -21,7 +21,7 @@ from google.cloud._helpers import _pb_timestamp_to_datetime from google.cloud.spanner_v1._helpers import _SessionWrapper from google.cloud.spanner_v1._helpers import _make_list_value_pbs -from google.cloud.spanner_v1._helpers import _options_with_prefix +from google.cloud.spanner_v1._helpers import _metadata_with_prefix # pylint: enable=ungrouped-imports @@ -148,12 +148,12 @@ def commit(self): self._check_state() database = self._session._database api = database.spanner_api - options = _options_with_prefix(database.name) + metadata = _metadata_with_prefix(database.name) txn_options = TransactionOptions( read_write=TransactionOptions.ReadWrite()) response = api.commit(self._session.name, self._mutations, single_use_transaction=txn_options, - options=options) + metadata=metadata) self.committed = _pb_timestamp_to_datetime( response.commit_timestamp) return self.committed diff --git a/spanner/google/cloud/spanner_v1/client.py b/spanner/google/cloud/spanner_v1/client.py index 07796aab0d54..b879e9e16463 100644 --- a/spanner/google/cloud/spanner_v1/client.py +++ b/spanner/google/cloud/spanner_v1/client.py @@ -24,8 +24,8 @@ :class:`~google.cloud.spanner_v1.database.Database` """ -from google.api_core import page_iterator -from google.gax import INITIAL_PAGE +from google.api_core.gapic_v1 import client_info + # pylint: disable=line-too-long from google.cloud.spanner_admin_database_v1.gapic.database_admin_client import ( # noqa DatabaseAdminClient) @@ -36,10 +36,12 @@ from google.cloud._http import DEFAULT_USER_AGENT from google.cloud.client import ClientWithProject from google.cloud.spanner_v1 import __version__ -from google.cloud.spanner_v1._helpers import _options_with_prefix +from google.cloud.spanner_v1._helpers import _metadata_with_prefix from google.cloud.spanner_v1.instance import DEFAULT_NODE_COUNT from google.cloud.spanner_v1.instance import Instance +_CLIENT_INFO = client_info.ClientInfo( + client_library_version=__version__) SPANNER_ADMIN_SCOPE = 'https://www.googleapis.com/auth/spanner.admin' @@ -148,8 +150,7 @@ def instance_admin_api(self): if self._instance_admin_api is None: self._instance_admin_api = InstanceAdminClient( credentials=self.credentials, - lib_name='gccl', - lib_version=__version__, + client_info=_CLIENT_INFO, ) return self._instance_admin_api @@ -159,8 +160,7 @@ def database_admin_api(self): if self._database_admin_api is None: self._database_admin_api = DatabaseAdminClient( credentials=self.credentials, - lib_name='gccl', - lib_version=__version__, + client_info=_CLIENT_INFO, ) return self._database_admin_api @@ -200,15 +200,13 @@ def list_instance_configs(self, page_size=None, page_token=None): :class:`~google.cloud.spanner_v1.instance.InstanceConfig` resources within the client's project. """ - if page_token is None: - page_token = INITIAL_PAGE - options = _options_with_prefix(self.project_name, - page_token=page_token) + metadata = _metadata_with_prefix(self.project_name) path = 'projects/%s' % (self.project,) page_iter = self.instance_admin_api.list_instance_configs( - path, page_size=page_size, options=options) - return page_iterator._GAXIterator( - self, page_iter, _item_to_instance_config) + path, page_size=page_size, metadata=metadata) + page_iter.next_page_token = page_token + page_iter.item_to_value = _item_to_instance_config + return page_iter def instance(self, instance_id, configuration_name=None, @@ -263,15 +261,27 @@ def list_instances(self, filter_='', page_size=None, page_token=None): Iterator of :class:`~google.cloud.spanner_v1.instance.Instance` resources within the client's project. """ - if page_token is None: - page_token = INITIAL_PAGE - options = _options_with_prefix(self.project_name, - page_token=page_token) + metadata = _metadata_with_prefix(self.project_name) path = 'projects/%s' % (self.project,) page_iter = self.instance_admin_api.list_instances( - path, filter_=filter_, page_size=page_size, options=options) - return page_iterator._GAXIterator( - self, page_iter, _item_to_instance) + path, page_size=page_size, metadata=metadata) + page_iter.item_to_value = self._item_to_instance + page_iter.next_page_token = page_token + return page_iter + + def _item_to_instance(self, iterator, instance_pb): + """Convert an instance protobuf to the native object. + + :type iterator: :class:`~google.api_core.page_iterator.Iterator` + :param iterator: The iterator that is currently in use. + + :type instance_pb: :class:`~google.spanner.admin.instance.v1.Instance` + :param instance_pb: An instance returned from the API. + + :rtype: :class:`~google.cloud.spanner_v1.instance.Instance` + :returns: The next instance in the page. + """ + return Instance.from_pb(instance_pb, self) def _item_to_instance_config( @@ -289,18 +299,3 @@ def _item_to_instance_config( :returns: The next instance config in the page. """ return InstanceConfig.from_pb(config_pb) - - -def _item_to_instance(iterator, instance_pb): - """Convert an instance protobuf to the native object. - - :type iterator: :class:`~google.api_core.page_iterator.Iterator` - :param iterator: The iterator that is currently in use. - - :type instance_pb: :class:`~google.spanner.admin.instance.v1.Instance` - :param instance_pb: An instance returned from the API. - - :rtype: :class:`~google.cloud.spanner_v1.instance.Instance` - :returns: The next instance in the page. - """ - return Instance.from_pb(instance_pb, iterator.client) diff --git a/spanner/google/cloud/spanner_v1/database.py b/spanner/google/cloud/spanner_v1/database.py index 381a88c39463..30f60323f8e8 100644 --- a/spanner/google/cloud/spanner_v1/database.py +++ b/spanner/google/cloud/spanner_v1/database.py @@ -17,18 +17,14 @@ import re import threading -from google.api_core import exceptions +from google.api_core.gapic_v1 import client_info import google.auth.credentials -from google.cloud.exceptions import Conflict from google.cloud.exceptions import NotFound -from google.gax.errors import GaxError -from google.gax.grpc import exc_to_code -from grpc import StatusCode import six # pylint: disable=ungrouped-imports from google.cloud.spanner_v1 import __version__ -from google.cloud.spanner_v1._helpers import _options_with_prefix +from google.cloud.spanner_v1._helpers import _metadata_with_prefix from google.cloud.spanner_v1.batch import Batch from google.cloud.spanner_v1.gapic.spanner_client import SpannerClient from google.cloud.spanner_v1.pool import BurstyPool @@ -38,6 +34,8 @@ # pylint: enable=ungrouped-imports +_CLIENT_INFO = client_info.ClientInfo( + client_library_version=__version__) SPANNER_DATA_SCOPE = 'https://www.googleapis.com/auth/spanner.data' @@ -165,9 +163,8 @@ def spanner_api(self): if isinstance(credentials, google.auth.credentials.Scoped): credentials = credentials.with_scopes((SPANNER_DATA_SCOPE,)) self._spanner_api = SpannerClient( - lib_name='gccl', - lib_version=__version__, credentials=credentials, + client_info=_CLIENT_INFO, ) return self._spanner_api @@ -192,24 +189,19 @@ def create(self): :returns: a future used to poll the status of the create request :raises Conflict: if the database already exists :raises NotFound: if the instance owning the database does not exist - :raises GaxError: - for errors other than ``ALREADY_EXISTS`` returned from the call """ api = self._instance._client.database_admin_api - options = _options_with_prefix(self.name) + metadata = _metadata_with_prefix(self.name) db_name = self.database_id if '-' in db_name: db_name = '`%s`' % (db_name,) - try: - future = api.create_database( - parent=self._instance.name, - create_statement='CREATE DATABASE %s' % (db_name,), - extra_statements=list(self._ddl_statements), - options=options, - ) - except GaxError as exc: - raise exceptions.from_grpc_error(exc.cause) + future = api.create_database( + parent=self._instance.name, + create_statement='CREATE DATABASE %s' % (db_name,), + extra_statements=list(self._ddl_statements), + metadata=metadata, + ) return future def exists(self): @@ -220,18 +212,14 @@ def exists(self): :rtype: bool :returns: True if the database exists, else false. - :raises GaxError: - for errors other than ``NOT_FOUND`` returned from the call """ api = self._instance._client.database_admin_api - options = _options_with_prefix(self.name) + metadata = _metadata_with_prefix(self.name) try: - api.get_database_ddl(self.name, options=options) - except GaxError as exc: - if exc_to_code(exc.cause) == StatusCode.NOT_FOUND: - return False - raise + api.get_database_ddl(self.name, metadata=metadata) + except NotFound: + return False return True def reload(self): @@ -243,18 +231,10 @@ def reload(self): https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.database.v1#google.spanner.admin.database.v1.DatabaseAdmin.GetDatabaseDDL :raises NotFound: if the database does not exist - :raises GaxError: - for errors other than ``NOT_FOUND`` returned from the call """ api = self._instance._client.database_admin_api - options = _options_with_prefix(self.name) - - try: - response = api.get_database_ddl(self.name, options=options) - except GaxError as exc: - if exc_to_code(exc.cause) == StatusCode.NOT_FOUND: - raise NotFound(self.name) - raise + metadata = _metadata_with_prefix(self.name) + response = api.get_database_ddl(self.name, metadata=metadata) self._ddl_statements = tuple(response.statements) def update_ddl(self, ddl_statements): @@ -268,21 +248,13 @@ def update_ddl(self, ddl_statements): :rtype: :class:`google.api_core.operation.Operation` :returns: an operation instance :raises NotFound: if the database does not exist - :raises GaxError: - for errors other than ``NOT_FOUND`` returned from the call """ client = self._instance._client api = client.database_admin_api - options = _options_with_prefix(self.name) - - try: - future = api.update_database_ddl( - self.name, ddl_statements, '', options=options) - except GaxError as exc: - if exc_to_code(exc.cause) == StatusCode.NOT_FOUND: - raise NotFound(self.name) - raise + metadata = _metadata_with_prefix(self.name) + future = api.update_database_ddl( + self.name, ddl_statements, '', metadata=metadata) return future def drop(self): @@ -292,14 +264,8 @@ def drop(self): https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.database.v1#google.spanner.admin.database.v1.DatabaseAdmin.DropDatabase """ api = self._instance._client.database_admin_api - options = _options_with_prefix(self.name) - - try: - api.drop_database(self.name, options=options) - except GaxError as exc: - if exc_to_code(exc.cause) == StatusCode.NOT_FOUND: - raise NotFound(self.name) - raise + metadata = _metadata_with_prefix(self.name) + api.drop_database(self.name, metadata=metadata) def session(self): """Factory to create a session for this database. diff --git a/spanner/google/cloud/spanner_v1/gapic/enums.py b/spanner/google/cloud/spanner_v1/gapic/enums.py index 8ce6e93b9a34..614df4e9b226 100644 --- a/spanner/google/cloud/spanner_v1/gapic/enums.py +++ b/spanner/google/cloud/spanner_v1/gapic/enums.py @@ -1,10 +1,10 @@ -# Copyright 2017, Google LLC All rights reserved. +# Copyright 2017 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 +# https://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, diff --git a/spanner/google/cloud/spanner_v1/gapic/spanner_client.py b/spanner/google/cloud/spanner_v1/gapic/spanner_client.py index 484999825bbd..4da896ffe720 100644 --- a/spanner/google/cloud/spanner_v1/gapic/spanner_client.py +++ b/spanner/google/cloud/spanner_v1/gapic/spanner_client.py @@ -1,38 +1,28 @@ -# Copyright 2017, Google LLC All rights reserved. +# Copyright 2017 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 +# https://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. -# -# EDITING INSTRUCTIONS -# This file was generated from the file -# https://github.com/google/googleapis/blob/master/google/spanner/v1/spanner.proto, -# and updates to that file get reflected here through a refresh process. -# For the short term, the refresh process will only be runnable by Google engineers. -# -# The only allowed edits are to method and file documentation. A 3-way -# merge preserves those additions if the generated source changes. """Accesses the google.spanner.v1 Spanner API.""" -import collections -import json -import os +import functools import pkg_resources -import platform -from google.gax import api_callable -from google.gax import config -from google.gax import path_template -from google.gax.utils import oneof -import google.gax +import google.api_core.gapic_v1.client_info +import google.api_core.gapic_v1.config +import google.api_core.gapic_v1.method +import google.api_core.grpc_helpers +import google.api_core.page_iterator +import google.api_core.path_template +import google.api_core.protobuf_helpers from google.cloud.spanner_v1.gapic import enums from google.cloud.spanner_v1.gapic import spanner_client_config @@ -42,6 +32,9 @@ from google.cloud.spanner_v1.proto import transaction_pb2 from google.protobuf import struct_pb2 +_GAPIC_LIBRARY_VERSION = pkg_resources.get_distribution( + 'google-cloud-spanner', ).version + class SpannerClient(object): """ @@ -51,239 +44,173 @@ class SpannerClient(object): transactions on data stored in Cloud Spanner databases. """ - SERVICE_ADDRESS = 'spanner.googleapis.com' + SERVICE_ADDRESS = 'spanner.googleapis.com:443' """The default address of the service.""" - DEFAULT_SERVICE_PORT = 443 - """The default port of the service.""" - # The scopes needed to make gRPC calls to all of the methods defined in # this service - _ALL_SCOPES = ( + _DEFAULT_SCOPES = ( 'https://www.googleapis.com/auth/cloud-platform', - 'https://www.googleapis.com/auth/spanner.data', ) - - _DATABASE_PATH_TEMPLATE = path_template.PathTemplate( - 'projects/{project}/instances/{instance}/databases/{database}') - _SESSION_PATH_TEMPLATE = path_template.PathTemplate( - 'projects/{project}/instances/{instance}/databases/{database}/sessions/{session}' + 'https://www.googleapis.com/auth/spanner.data', ) + # The name of the interface for this client. This is the key used to find + # method configuration in the client_config dictionary. + _INTERFACE_NAME = 'google.spanner.v1.Spanner' + @classmethod def database_path(cls, project, instance, database): - """Returns a fully-qualified database resource name string.""" - return cls._DATABASE_PATH_TEMPLATE.render({ - 'project': project, - 'instance': instance, - 'database': database, - }) + """Return a fully-qualified database string.""" + return google.api_core.path_template.expand( + 'projects/{project}/instances/{instance}/databases/{database}', + project=project, + instance=instance, + database=database, + ) @classmethod def session_path(cls, project, instance, database, session): - """Returns a fully-qualified session resource name string.""" - return cls._SESSION_PATH_TEMPLATE.render({ - 'project': project, - 'instance': instance, - 'database': database, - 'session': session, - }) - - @classmethod - def match_project_from_database_name(cls, database_name): - """Parses the project from a database resource. - - Args: - database_name (str): A fully-qualified path representing a database - resource. - - Returns: - A string representing the project. - """ - return cls._DATABASE_PATH_TEMPLATE.match(database_name).get('project') - - @classmethod - def match_instance_from_database_name(cls, database_name): - """Parses the instance from a database resource. - - Args: - database_name (str): A fully-qualified path representing a database - resource. - - Returns: - A string representing the instance. - """ - return cls._DATABASE_PATH_TEMPLATE.match(database_name).get('instance') - - @classmethod - def match_database_from_database_name(cls, database_name): - """Parses the database from a database resource. - - Args: - database_name (str): A fully-qualified path representing a database - resource. - - Returns: - A string representing the database. - """ - return cls._DATABASE_PATH_TEMPLATE.match(database_name).get('database') - - @classmethod - def match_project_from_session_name(cls, session_name): - """Parses the project from a session resource. - - Args: - session_name (str): A fully-qualified path representing a session - resource. - - Returns: - A string representing the project. - """ - return cls._SESSION_PATH_TEMPLATE.match(session_name).get('project') - - @classmethod - def match_instance_from_session_name(cls, session_name): - """Parses the instance from a session resource. - - Args: - session_name (str): A fully-qualified path representing a session - resource. - - Returns: - A string representing the instance. - """ - return cls._SESSION_PATH_TEMPLATE.match(session_name).get('instance') - - @classmethod - def match_database_from_session_name(cls, session_name): - """Parses the database from a session resource. - - Args: - session_name (str): A fully-qualified path representing a session - resource. - - Returns: - A string representing the database. - """ - return cls._SESSION_PATH_TEMPLATE.match(session_name).get('database') - - @classmethod - def match_session_from_session_name(cls, session_name): - """Parses the session from a session resource. - - Args: - session_name (str): A fully-qualified path representing a session - resource. - - Returns: - A string representing the session. - """ - return cls._SESSION_PATH_TEMPLATE.match(session_name).get('session') + """Return a fully-qualified session string.""" + return google.api_core.path_template.expand( + 'projects/{project}/instances/{instance}/databases/{database}/sessions/{session}', + project=project, + instance=instance, + database=database, + session=session, + ) def __init__(self, channel=None, credentials=None, - ssl_credentials=None, - scopes=None, - client_config=None, - lib_name=None, - lib_version='', - metrics_headers=()): + client_config=spanner_client_config.config, + client_info=None): """Constructor. Args: - channel (~grpc.Channel): A ``Channel`` instance through - which to make calls. - credentials (~google.auth.credentials.Credentials): The authorization - credentials to attach to requests. These credentials identify this - application to the service. - ssl_credentials (~grpc.ChannelCredentials): A - ``ChannelCredentials`` instance for use with an SSL-enabled - 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. - 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. + channel (grpc.Channel): A ``Channel`` instance through + which to make calls. This argument is mutually exclusive + with ``credentials``; providing both will raise an exception. + credentials (google.auth.credentials.Credentials): The + authorization credentials to attach to requests. These + credentials identify this application to the service. If none + are specified, the client will attempt to ascertain the + credentials from the environment. + client_config (dict): A dictionary of call options for each + method. If not specified, the default configuration is used. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. """ - # Unless the calling application specifically requested - # OAuth scopes, request everything. - if scopes is None: - scopes = self._ALL_SCOPES - - # Initialize an empty client config, if none is set. - 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-spanner', ).version - - # Load the configuration defaults. - defaults = api_callable.construct_settings( - 'google.spanner.v1.Spanner', - spanner_client_config.config, - client_config, - config.STATUS_CODE_NAMES, - metrics_headers=metrics_headers, ) - self.spanner_stub = config.create_stub( - spanner_pb2.SpannerStub, - channel=channel, - service_path=self.SERVICE_ADDRESS, - service_port=self.DEFAULT_SERVICE_PORT, - credentials=credentials, - scopes=scopes, - ssl_credentials=ssl_credentials) - - self._create_session = api_callable.create_api_call( + # If both `channel` and `credentials` are specified, raise an + # exception (channels come with credentials baked in already). + if channel is not None and credentials is not None: + raise ValueError( + 'The `channel` and `credentials` arguments to {} are mutually ' + 'exclusive.'.format(self.__class__.__name__), ) + + # Create the channel. + if channel is None: + channel = google.api_core.grpc_helpers.create_channel( + self.SERVICE_ADDRESS, + credentials=credentials, + scopes=self._DEFAULT_SCOPES, + ) + + # Create the gRPC stubs. + self.spanner_stub = (spanner_pb2.SpannerStub(channel)) + + if client_info is None: + client_info = ( + google.api_core.gapic_v1.client_info.DEFAULT_CLIENT_INFO) + client_info.gapic_version = _GAPIC_LIBRARY_VERSION + + # Parse out the default settings for retry and timeout for each RPC + # from the client configuration. + # (Ordinarily, these are the defaults specified in the `*_config.py` + # file next to this one.) + method_configs = google.api_core.gapic_v1.config.parse_method_configs( + client_config['interfaces'][self._INTERFACE_NAME], ) + + # Write the "inner API call" methods to the class. + # These are wrapped versions of the gRPC stub methods, with retry and + # timeout configuration applied, called by the public methods on + # this class. + self._create_session = google.api_core.gapic_v1.method.wrap_method( self.spanner_stub.CreateSession, - settings=defaults['create_session']) - self._get_session = api_callable.create_api_call( - self.spanner_stub.GetSession, settings=defaults['get_session']) - self._delete_session = api_callable.create_api_call( + default_retry=method_configs['CreateSession'].retry, + default_timeout=method_configs['CreateSession'].timeout, + client_info=client_info, + ) + self._get_session = google.api_core.gapic_v1.method.wrap_method( + self.spanner_stub.GetSession, + default_retry=method_configs['GetSession'].retry, + default_timeout=method_configs['GetSession'].timeout, + client_info=client_info, + ) + self._list_sessions = google.api_core.gapic_v1.method.wrap_method( + self.spanner_stub.ListSessions, + default_retry=method_configs['ListSessions'].retry, + default_timeout=method_configs['ListSessions'].timeout, + client_info=client_info, + ) + self._delete_session = google.api_core.gapic_v1.method.wrap_method( self.spanner_stub.DeleteSession, - settings=defaults['delete_session']) - self._execute_sql = api_callable.create_api_call( - self.spanner_stub.ExecuteSql, settings=defaults['execute_sql']) - self._execute_streaming_sql = api_callable.create_api_call( + default_retry=method_configs['DeleteSession'].retry, + default_timeout=method_configs['DeleteSession'].timeout, + client_info=client_info, + ) + self._execute_sql = google.api_core.gapic_v1.method.wrap_method( + self.spanner_stub.ExecuteSql, + default_retry=method_configs['ExecuteSql'].retry, + default_timeout=method_configs['ExecuteSql'].timeout, + client_info=client_info, + ) + self._execute_streaming_sql = google.api_core.gapic_v1.method.wrap_method( self.spanner_stub.ExecuteStreamingSql, - settings=defaults['execute_streaming_sql']) - self._read = api_callable.create_api_call( - self.spanner_stub.Read, settings=defaults['read']) - self._streaming_read = api_callable.create_api_call( + default_retry=method_configs['ExecuteStreamingSql'].retry, + default_timeout=method_configs['ExecuteStreamingSql'].timeout, + client_info=client_info, + ) + self._read = google.api_core.gapic_v1.method.wrap_method( + self.spanner_stub.Read, + default_retry=method_configs['Read'].retry, + default_timeout=method_configs['Read'].timeout, + client_info=client_info, + ) + self._streaming_read = google.api_core.gapic_v1.method.wrap_method( self.spanner_stub.StreamingRead, - settings=defaults['streaming_read']) - self._begin_transaction = api_callable.create_api_call( + default_retry=method_configs['StreamingRead'].retry, + default_timeout=method_configs['StreamingRead'].timeout, + client_info=client_info, + ) + self._begin_transaction = google.api_core.gapic_v1.method.wrap_method( self.spanner_stub.BeginTransaction, - settings=defaults['begin_transaction']) - self._commit = api_callable.create_api_call( - self.spanner_stub.Commit, settings=defaults['commit']) - self._rollback = api_callable.create_api_call( - self.spanner_stub.Rollback, settings=defaults['rollback']) + default_retry=method_configs['BeginTransaction'].retry, + default_timeout=method_configs['BeginTransaction'].timeout, + client_info=client_info, + ) + self._commit = google.api_core.gapic_v1.method.wrap_method( + self.spanner_stub.Commit, + default_retry=method_configs['Commit'].retry, + default_timeout=method_configs['Commit'].timeout, + client_info=client_info, + ) + self._rollback = google.api_core.gapic_v1.method.wrap_method( + self.spanner_stub.Rollback, + default_retry=method_configs['Rollback'].retry, + default_timeout=method_configs['Rollback'].timeout, + client_info=client_info, + ) # Service calls - def create_session(self, database, options=None): + def create_session(self, + database, + session=None, + retry=google.api_core.gapic_v1.method.DEFAULT, + timeout=google.api_core.gapic_v1.method.DEFAULT, + metadata=None): """ Creates a new session. A session can be used to perform transactions that read and/or modify data in a Cloud Spanner database. @@ -316,20 +243,38 @@ def create_session(self, database, options=None): Args: database (str): Required. The database in which the new session is created. - options (~google.gax.CallOptions): Overrides the default - settings for this call, e.g, timeout, retries etc. + session (Union[dict, ~google.cloud.spanner_v1.types.Session]): The session to create. + If a dict is provided, it must be of the same form as the protobuf + message :class:`~google.cloud.spanner_v1.types.Session` + retry (Optional[google.api_core.retry.Retry]): A retry object used + to retry requests. If ``None`` is specified, requests will not + be retried. + timeout (Optional[float]): The amount of time, in seconds, to wait + for the request to complete. Note that if ``retry`` is + specified, the timeout applies to each individual attempt. Returns: A :class:`~google.cloud.spanner_v1.types.Session` instance. Raises: - :exc:`google.gax.errors.GaxError` if the RPC is aborted. - :exc:`ValueError` if the parameters are invalid. + google.api_core.exceptions.GoogleAPICallError: If the request + failed for any reason. + google.api_core.exceptions.RetryError: If the request failed due + to a retryable error and retry attempts failed. + ValueError: If the parameters are invalid. """ - request = spanner_pb2.CreateSessionRequest(database=database) - return self._create_session(request, options) - - def get_session(self, name, options=None): + request = spanner_pb2.CreateSessionRequest( + database=database, + session=session, + ) + return self._create_session( + request, retry=retry, timeout=timeout, metadata=metadata) + + def get_session(self, + name, + retry=google.api_core.gapic_v1.method.DEFAULT, + timeout=google.api_core.gapic_v1.method.DEFAULT, + metadata=None): """ Gets a session. Returns ``NOT_FOUND`` if the session does not exist. This is mainly useful for determining whether a session is still @@ -346,20 +291,117 @@ def get_session(self, name, options=None): Args: name (str): Required. The name of the session to retrieve. - options (~google.gax.CallOptions): Overrides the default - settings for this call, e.g, timeout, retries etc. + retry (Optional[google.api_core.retry.Retry]): A retry object used + to retry requests. If ``None`` is specified, requests will not + be retried. + timeout (Optional[float]): The amount of time, in seconds, to wait + for the request to complete. Note that if ``retry`` is + specified, the timeout applies to each individual attempt. Returns: A :class:`~google.cloud.spanner_v1.types.Session` instance. Raises: - :exc:`google.gax.errors.GaxError` if the RPC is aborted. - :exc:`ValueError` if the parameters are invalid. + google.api_core.exceptions.GoogleAPICallError: If the request + failed for any reason. + google.api_core.exceptions.RetryError: If the request failed due + to a retryable error and retry attempts failed. + ValueError: If the parameters are invalid. """ - request = spanner_pb2.GetSessionRequest(name=name) - return self._get_session(request, options) + request = spanner_pb2.GetSessionRequest(name=name, ) + return self._get_session( + request, retry=retry, timeout=timeout, metadata=metadata) + + def list_sessions(self, + database, + page_size=None, + filter_=None, + retry=google.api_core.gapic_v1.method.DEFAULT, + timeout=google.api_core.gapic_v1.method.DEFAULT, + metadata=None): + """ + Lists all sessions in a given database. + + Example: + >>> from google.cloud import spanner_v1 + >>> + >>> client = spanner_v1.SpannerClient() + >>> + >>> database = client.database_path('[PROJECT]', '[INSTANCE]', '[DATABASE]') + >>> + >>> + >>> # Iterate over all results + >>> for element in client.list_sessions(database): + ... # process element + ... pass + >>> + >>> # Or iterate over results one page at a time + >>> for page in client.list_sessions(database, options=CallOptions(page_token=INITIAL_PAGE)): + ... for element in page: + ... # process element + ... pass - def delete_session(self, name, options=None): + Args: + database (str): Required. The database in which to list sessions. + page_size (int): The maximum number of resources contained in the + underlying API response. If page streaming is performed per- + resource, this parameter does not affect the return value. If page + streaming is performed per-page, this determines the maximum number + of resources in a page. + filter_ (str): An expression for filtering the results of the request. Filter rules are + case insensitive. The fields eligible for filtering are: + + * ``labels.key`` where key is the name of a label + + Some examples of using filters are: + + * ``labels.env:*`` --> The session has the label \"env\". + * ``labels.env:dev`` --> The session has the label \"env\" and the value of + :: + + the label contains the string \"dev\". + retry (Optional[google.api_core.retry.Retry]): A retry object used + to retry requests. If ``None`` is specified, requests will not + be retried. + timeout (Optional[float]): The amount of time, in seconds, to wait + for the request to complete. Note that if ``retry`` is + specified, the timeout applies to each individual attempt. + + Returns: + A :class:`~google.gax.PageIterator` instance. By default, this + is an iterable of :class:`~google.cloud.spanner_v1.types.Session` instances. + This object can also be configured to iterate over the pages + of the response through the `options` parameter. + + Raises: + google.api_core.exceptions.GoogleAPICallError: If the request + failed for any reason. + google.api_core.exceptions.RetryError: If the request failed due + to a retryable error and retry attempts failed. + ValueError: If the parameters are invalid. + """ + request = spanner_pb2.ListSessionsRequest( + database=database, + page_size=page_size, + filter=filter_, + ) + iterator = google.api_core.page_iterator.GRPCIterator( + client=None, + method=functools.partial( + self._list_sessions, retry=retry, timeout=timeout, + metadata=metadata), + request=request, + items_field='sessions', + request_token_field='page_token', + response_token_field='next_page_token', + ) + return iterator + + def delete_session(self, + name, + retry=google.api_core.gapic_v1.method.DEFAULT, + timeout=google.api_core.gapic_v1.method.DEFAULT, + metadata=None): """ Ends a session, releasing server resources associated with it. @@ -374,15 +416,22 @@ def delete_session(self, name, options=None): Args: name (str): Required. The name of the session to delete. - options (~google.gax.CallOptions): Overrides the default - settings for this call, e.g, timeout, retries etc. + retry (Optional[google.api_core.retry.Retry]): A retry object used + to retry requests. If ``None`` is specified, requests will not + be retried. + timeout (Optional[float]): The amount of time, in seconds, to wait + for the request to complete. Note that if ``retry`` is + specified, the timeout applies to each individual attempt. Raises: - :exc:`google.gax.errors.GaxError` if the RPC is aborted. - :exc:`ValueError` if the parameters are invalid. + google.api_core.exceptions.GoogleAPICallError: If the request + failed for any reason. + google.api_core.exceptions.RetryError: If the request failed due + to a retryable error and retry attempts failed. + ValueError: If the parameters are invalid. """ - request = spanner_pb2.DeleteSessionRequest(name=name) - self._delete_session(request, options) + request = spanner_pb2.DeleteSessionRequest(name=name, ) + self._delete_session(request, retry=retry, timeout=timeout) def execute_sql(self, session, @@ -392,7 +441,9 @@ def execute_sql(self, param_types=None, resume_token=None, query_mode=None, - options=None): + retry=google.api_core.gapic_v1.method.DEFAULT, + timeout=google.api_core.gapic_v1.method.DEFAULT, + metadata=None): """ Executes an SQL query, returning all rows in a single reply. This method cannot be used to return a result set larger than 10 MiB; @@ -430,7 +481,7 @@ def execute_sql(self, Parameters can appear anywhere that a literal value is expected. The same parameter name can be used more than once, for example: - ``\"WHERE id > @msg_id AND id < @msg_id + 100\"`` + ``\"WHERE id > @msg_id AND id < @msg_id + 100\"`` It is an error to execute an SQL query with unbound parameters. @@ -457,15 +508,22 @@ def execute_sql(self, request that yielded this token. query_mode (~google.cloud.spanner_v1.types.QueryMode): Used to control the amount of debugging information returned in ``ResultSetStats``. - options (~google.gax.CallOptions): Overrides the default - settings for this call, e.g, timeout, retries etc. + retry (Optional[google.api_core.retry.Retry]): A retry object used + to retry requests. If ``None`` is specified, requests will not + be retried. + timeout (Optional[float]): The amount of time, in seconds, to wait + for the request to complete. Note that if ``retry`` is + specified, the timeout applies to each individual attempt. Returns: A :class:`~google.cloud.spanner_v1.types.ResultSet` instance. Raises: - :exc:`google.gax.errors.GaxError` if the RPC is aborted. - :exc:`ValueError` if the parameters are invalid. + google.api_core.exceptions.GoogleAPICallError: If the request + failed for any reason. + google.api_core.exceptions.RetryError: If the request failed due + to a retryable error and retry attempts failed. + ValueError: If the parameters are invalid. """ request = spanner_pb2.ExecuteSqlRequest( session=session, @@ -474,8 +532,10 @@ def execute_sql(self, params=params, param_types=param_types, resume_token=resume_token, - query_mode=query_mode) - return self._execute_sql(request, options) + query_mode=query_mode, + ) + return self._execute_sql( + request, retry=retry, timeout=timeout, metadata=metadata) def execute_streaming_sql(self, session, @@ -485,7 +545,9 @@ def execute_streaming_sql(self, param_types=None, resume_token=None, query_mode=None, - options=None): + retry=google.api_core.gapic_v1.method.DEFAULT, + timeout=google.api_core.gapic_v1.method.DEFAULT, + metadata=None): """ Like ``ExecuteSql``, except returns the result set as a stream. Unlike ``ExecuteSql``, there @@ -519,7 +581,7 @@ def execute_streaming_sql(self, Parameters can appear anywhere that a literal value is expected. The same parameter name can be used more than once, for example: - ``\"WHERE id > @msg_id AND id < @msg_id + 100\"`` + ``\"WHERE id > @msg_id AND id < @msg_id + 100\"`` It is an error to execute an SQL query with unbound parameters. @@ -546,15 +608,22 @@ def execute_streaming_sql(self, request that yielded this token. query_mode (~google.cloud.spanner_v1.types.QueryMode): Used to control the amount of debugging information returned in ``ResultSetStats``. - options (~google.gax.CallOptions): Overrides the default - settings for this call, e.g, timeout, retries etc. + retry (Optional[google.api_core.retry.Retry]): A retry object used + to retry requests. If ``None`` is specified, requests will not + be retried. + timeout (Optional[float]): The amount of time, in seconds, to wait + for the request to complete. Note that if ``retry`` is + specified, the timeout applies to each individual attempt. Returns: Iterable[~google.cloud.spanner_v1.types.PartialResultSet]. Raises: - :exc:`google.gax.errors.GaxError` if the RPC is aborted. - :exc:`ValueError` if the parameters are invalid. + google.api_core.exceptions.GoogleAPICallError: If the request + failed for any reason. + google.api_core.exceptions.RetryError: If the request failed due + to a retryable error and retry attempts failed. + ValueError: If the parameters are invalid. """ request = spanner_pb2.ExecuteSqlRequest( session=session, @@ -563,8 +632,10 @@ def execute_streaming_sql(self, params=params, param_types=param_types, resume_token=resume_token, - query_mode=query_mode) - return self._execute_streaming_sql(request, options) + query_mode=query_mode, + ) + return self._execute_streaming_sql( + request, retry=retry, timeout=timeout, metadata=metadata) def read(self, session, @@ -575,7 +646,9 @@ def read(self, index=None, limit=None, resume_token=None, - options=None): + retry=google.api_core.gapic_v1.method.DEFAULT, + timeout=google.api_core.gapic_v1.method.DEFAULT, + metadata=None): """ Reads rows from the database using key lookups and scans, as a simple key/value style alternative to @@ -635,15 +708,22 @@ def read(self, enables the new read to resume where the last read left off. The rest of the request parameters must exactly match the request that yielded this token. - options (~google.gax.CallOptions): Overrides the default - settings for this call, e.g, timeout, retries etc. + retry (Optional[google.api_core.retry.Retry]): A retry object used + to retry requests. If ``None`` is specified, requests will not + be retried. + timeout (Optional[float]): The amount of time, in seconds, to wait + for the request to complete. Note that if ``retry`` is + specified, the timeout applies to each individual attempt. Returns: A :class:`~google.cloud.spanner_v1.types.ResultSet` instance. Raises: - :exc:`google.gax.errors.GaxError` if the RPC is aborted. - :exc:`ValueError` if the parameters are invalid. + google.api_core.exceptions.GoogleAPICallError: If the request + failed for any reason. + google.api_core.exceptions.RetryError: If the request failed due + to a retryable error and retry attempts failed. + ValueError: If the parameters are invalid. """ request = spanner_pb2.ReadRequest( session=session, @@ -653,8 +733,10 @@ def read(self, transaction=transaction, index=index, limit=limit, - resume_token=resume_token) - return self._read(request, options) + resume_token=resume_token, + ) + return self._read( + request, retry=retry, timeout=timeout, metadata=metadata) def streaming_read(self, session, @@ -665,7 +747,9 @@ def streaming_read(self, index=None, limit=None, resume_token=None, - options=None): + retry=google.api_core.gapic_v1.method.DEFAULT, + timeout=google.api_core.gapic_v1.method.DEFAULT, + metadata=None): """ Like ``Read``, except returns the result set as a stream. Unlike ``Read``, there is no limit on the @@ -719,15 +803,22 @@ def streaming_read(self, enables the new read to resume where the last read left off. The rest of the request parameters must exactly match the request that yielded this token. - options (~google.gax.CallOptions): Overrides the default - settings for this call, e.g, timeout, retries etc. + retry (Optional[google.api_core.retry.Retry]): A retry object used + to retry requests. If ``None`` is specified, requests will not + be retried. + timeout (Optional[float]): The amount of time, in seconds, to wait + for the request to complete. Note that if ``retry`` is + specified, the timeout applies to each individual attempt. Returns: Iterable[~google.cloud.spanner_v1.types.PartialResultSet]. Raises: - :exc:`google.gax.errors.GaxError` if the RPC is aborted. - :exc:`ValueError` if the parameters are invalid. + google.api_core.exceptions.GoogleAPICallError: If the request + failed for any reason. + google.api_core.exceptions.RetryError: If the request failed due + to a retryable error and retry attempts failed. + ValueError: If the parameters are invalid. """ request = spanner_pb2.ReadRequest( session=session, @@ -737,10 +828,17 @@ def streaming_read(self, transaction=transaction, index=index, limit=limit, - resume_token=resume_token) - return self._streaming_read(request, options) - - def begin_transaction(self, session, options_, options=None): + resume_token=resume_token, + ) + return self._streaming_read( + request, retry=retry, timeout=timeout, metadata=metadata) + + def begin_transaction(self, + session, + options_, + retry=google.api_core.gapic_v1.method.DEFAULT, + timeout=google.api_core.gapic_v1.method.DEFAULT, + metadata=None): """ Begins a new transaction. This step can often be skipped: ``Read``, ``ExecuteSql`` and @@ -762,26 +860,38 @@ def begin_transaction(self, session, options_, options=None): options_ (Union[dict, ~google.cloud.spanner_v1.types.TransactionOptions]): Required. Options for the new transaction. If a dict is provided, it must be of the same form as the protobuf message :class:`~google.cloud.spanner_v1.types.TransactionOptions` - options (~google.gax.CallOptions): Overrides the default - settings for this call, e.g, timeout, retries etc. + retry (Optional[google.api_core.retry.Retry]): A retry object used + to retry requests. If ``None`` is specified, requests will not + be retried. + timeout (Optional[float]): The amount of time, in seconds, to wait + for the request to complete. Note that if ``retry`` is + specified, the timeout applies to each individual attempt. Returns: A :class:`~google.cloud.spanner_v1.types.Transaction` instance. Raises: - :exc:`google.gax.errors.GaxError` if the RPC is aborted. - :exc:`ValueError` if the parameters are invalid. + google.api_core.exceptions.GoogleAPICallError: If the request + failed for any reason. + google.api_core.exceptions.RetryError: If the request failed due + to a retryable error and retry attempts failed. + ValueError: If the parameters are invalid. """ request = spanner_pb2.BeginTransactionRequest( - session=session, options=options_) - return self._begin_transaction(request, options) + session=session, + options=options_, + ) + return self._begin_transaction( + request, metadata=metadata, retry=retry, timeout=timeout) def commit(self, session, mutations, transaction_id=None, single_use_transaction=None, - options=None): + retry=google.api_core.gapic_v1.method.DEFAULT, + timeout=google.api_core.gapic_v1.method.DEFAULT, + metadata=None): """ Commits a transaction. The request includes the mutations to be applied to rows in the database. @@ -821,30 +931,45 @@ def commit(self, ``Commit`` instead. If a dict is provided, it must be of the same form as the protobuf message :class:`~google.cloud.spanner_v1.types.TransactionOptions` - options (~google.gax.CallOptions): Overrides the default - settings for this call, e.g, timeout, retries etc. + retry (Optional[google.api_core.retry.Retry]): A retry object used + to retry requests. If ``None`` is specified, requests will not + be retried. + timeout (Optional[float]): The amount of time, in seconds, to wait + for the request to complete. Note that if ``retry`` is + specified, the timeout applies to each individual attempt. Returns: A :class:`~google.cloud.spanner_v1.types.CommitResponse` instance. Raises: - :exc:`google.gax.errors.GaxError` if the RPC is aborted. - :exc:`ValueError` if the parameters are invalid. + google.api_core.exceptions.GoogleAPICallError: If the request + failed for any reason. + google.api_core.exceptions.RetryError: If the request failed due + to a retryable error and retry attempts failed. + ValueError: If the parameters are invalid. """ # Sanity check: We have some fields which are mutually exclusive; # raise ValueError if more than one is sent. - oneof.check_oneof( + google.api_core.protobuf_helpers.check_oneof( transaction_id=transaction_id, - single_use_transaction=single_use_transaction, ) + single_use_transaction=single_use_transaction, + ) request = spanner_pb2.CommitRequest( session=session, mutations=mutations, transaction_id=transaction_id, - single_use_transaction=single_use_transaction) - return self._commit(request, options) - - def rollback(self, session, transaction_id, options=None): + single_use_transaction=single_use_transaction, + ) + return self._commit( + request, retry=retry, timeout=timeout, metadata=metadata) + + def rollback(self, + session, + transaction_id, + retry=google.api_core.gapic_v1.method.DEFAULT, + timeout=google.api_core.gapic_v1.method.DEFAULT, + metadata=None): """ Rolls back a transaction, releasing any locks it holds. It is a good idea to call this for any transaction that includes one or more @@ -868,13 +993,23 @@ def rollback(self, session, transaction_id, options=None): Args: session (str): Required. The session in which the transaction to roll back is running. transaction_id (bytes): Required. The transaction to roll back. - options (~google.gax.CallOptions): Overrides the default - settings for this call, e.g, timeout, retries etc. + retry (Optional[google.api_core.retry.Retry]): A retry object used + to retry requests. If ``None`` is specified, requests will not + be retried. + timeout (Optional[float]): The amount of time, in seconds, to wait + for the request to complete. Note that if ``retry`` is + specified, the timeout applies to each individual attempt. Raises: - :exc:`google.gax.errors.GaxError` if the RPC is aborted. - :exc:`ValueError` if the parameters are invalid. + google.api_core.exceptions.GoogleAPICallError: If the request + failed for any reason. + google.api_core.exceptions.RetryError: If the request failed due + to a retryable error and retry attempts failed. + ValueError: If the parameters are invalid. """ request = spanner_pb2.RollbackRequest( - session=session, transaction_id=transaction_id) - self._rollback(request, options) + session=session, + transaction_id=transaction_id, + ) + self._rollback( + request, retry=retry, timeout=timeout, metadata=metadata) diff --git a/spanner/google/cloud/spanner_v1/gapic/spanner_client_config.py b/spanner/google/cloud/spanner_v1/gapic/spanner_client_config.py index 5f38663a35f9..bc64a4331c7e 100644 --- a/spanner/google/cloud/spanner_v1/gapic/spanner_client_config.py +++ b/spanner/google/cloud/spanner_v1/gapic/spanner_client_config.py @@ -37,6 +37,11 @@ "retry_codes_name": "idempotent", "retry_params_name": "default" }, + "ListSessions": { + "timeout_millis": 30000, + "retry_codes_name": "idempotent", + "retry_params_name": "default" + }, "DeleteSession": { "timeout_millis": 30000, "retry_codes_name": "idempotent", diff --git a/spanner/google/cloud/spanner_v1/instance.py b/spanner/google/cloud/spanner_v1/instance.py index 6e5eb9c49c57..6f20704874fd 100644 --- a/spanner/google/cloud/spanner_v1/instance.py +++ b/spanner/google/cloud/spanner_v1/instance.py @@ -16,19 +16,13 @@ import re -from google.api_core import page_iterator -from google.gax import INITIAL_PAGE -from google.gax.errors import GaxError -from google.gax.grpc import exc_to_code from google.cloud.spanner_admin_instance_v1.proto import ( spanner_instance_admin_pb2 as admin_v1_pb2) from google.protobuf.field_mask_pb2 import FieldMask -from grpc import StatusCode # pylint: disable=ungrouped-imports -from google.cloud.exceptions import Conflict from google.cloud.exceptions import NotFound -from google.cloud.spanner_v1._helpers import _options_with_prefix +from google.cloud.spanner_v1._helpers import _metadata_with_prefix from google.cloud.spanner_v1.database import Database from google.cloud.spanner_v1.pool import BurstyPool # pylint: enable=ungrouped-imports @@ -201,8 +195,6 @@ def create(self): :rtype: :class:`google.api_core.operation.Operation` :returns: an operation instance :raises Conflict: if the instance already exists - :raises GaxError: - for errors other than ``ALREADY_EXISTS`` returned from the call """ api = self._client.instance_admin_api instance_pb = admin_v1_pb2.Instance( @@ -211,19 +203,14 @@ def create(self): display_name=self.display_name, node_count=self.node_count, ) - options = _options_with_prefix(self.name) + metadata = _metadata_with_prefix(self.name) - try: - future = api.create_instance( - parent=self._client.project_name, - instance_id=self.instance_id, - instance=instance_pb, - options=options, - ) - except GaxError as exc: - if exc_to_code(exc.cause) == StatusCode.ALREADY_EXISTS: - raise Conflict(self.name) - raise + future = api.create_instance( + parent=self._client.project_name, + instance_id=self.instance_id, + instance=instance_pb, + metadata=metadata, + ) return future @@ -235,18 +222,14 @@ def exists(self): :rtype: bool :returns: True if the instance exists, else false - :raises GaxError: - for errors other than ``NOT_FOUND`` returned from the call """ api = self._client.instance_admin_api - options = _options_with_prefix(self.name) + metadata = _metadata_with_prefix(self.name) try: - api.get_instance(self.name, options=options) - except GaxError as exc: - if exc_to_code(exc.cause) == StatusCode.NOT_FOUND: - return False - raise + api.get_instance(self.name, metadata=metadata) + except NotFound: + return False return True @@ -257,17 +240,11 @@ def reload(self): https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.instance.v1#google.spanner.admin.instance.v1.InstanceAdmin.GetInstanceConfig :raises NotFound: if the instance does not exist - :raises GaxError: for other errors returned from the call """ api = self._client.instance_admin_api - options = _options_with_prefix(self.name) + metadata = _metadata_with_prefix(self.name) - try: - instance_pb = api.get_instance(self.name, options=options) - except GaxError as exc: - if exc_to_code(exc.cause) == StatusCode.NOT_FOUND: - raise NotFound(self.name) - raise + instance_pb = api.get_instance(self.name, metadata=metadata) self._update_from_pb(instance_pb) @@ -292,7 +269,6 @@ def update(self): :rtype: :class:`google.api_core.operation.Operation` :returns: an operation instance :raises NotFound: if the instance does not exist - :raises GaxError: for other errors returned from the call """ api = self._client.instance_admin_api instance_pb = admin_v1_pb2.Instance( @@ -302,18 +278,13 @@ def update(self): node_count=self.node_count, ) field_mask = FieldMask(paths=['config', 'display_name', 'node_count']) - options = _options_with_prefix(self.name) + metadata = _metadata_with_prefix(self.name) - try: - future = api.update_instance( - instance=instance_pb, - field_mask=field_mask, - options=options, - ) - except GaxError as exc: - if exc_to_code(exc.cause) == StatusCode.NOT_FOUND: - raise NotFound(self.name) - raise + future = api.update_instance( + instance=instance_pb, + field_mask=field_mask, + metadata=metadata, + ) return future @@ -333,14 +304,9 @@ def delete(self): All data in the databases will be permanently deleted. """ api = self._client.instance_admin_api - options = _options_with_prefix(self.name) + metadata = _metadata_with_prefix(self.name) - try: - api.delete_instance(self.name, options=options) - except GaxError as exc: - if exc_to_code(exc.cause) == StatusCode.NOT_FOUND: - raise NotFound(self.name) - raise + api.delete_instance(self.name, metadata=metadata) def database(self, database_id, ddl_statements=(), pool=None): """Factory to create a database within this instance. @@ -379,27 +345,23 @@ def list_databases(self, page_size=None, page_token=None): Iterator of :class:`~google.cloud.spanner_v1.database.Database` resources within the current instance. """ - if page_token is None: - page_token = INITIAL_PAGE - options = _options_with_prefix(self.name, page_token=page_token) + metadata = _metadata_with_prefix(self.name) page_iter = self._client.database_admin_api.list_databases( - self.name, page_size=page_size, options=options) - iterator = page_iterator._GAXIterator( - self._client, page_iter, _item_to_database) - iterator.instance = self - return iterator - + self.name, page_size=page_size, metadata=metadata) + page_iter.next_page_token = page_token + page_iter.item_to_value = self._item_to_database + return page_iter -def _item_to_database(iterator, database_pb): - """Convert a database protobuf to the native object. + def _item_to_database(self, iterator, database_pb): + """Convert a database protobuf to the native object. - :type iterator: :class:`~google.api_core.page_iterator.Iterator` - :param iterator: The iterator that is currently in use. + :type iterator: :class:`~google.api_core.page_iterator.Iterator` + :param iterator: The iterator that is currently in use. - :type database_pb: :class:`~google.spanner.admin.database.v1.Database` - :param database_pb: A database returned from the API. + :type database_pb: :class:`~google.spanner.admin.database.v1.Database` + :param database_pb: A database returned from the API. - :rtype: :class:`~google.cloud.spanner_v1.database.Database` - :returns: The next database in the page. - """ - return Database.from_pb(database_pb, iterator.instance, pool=BurstyPool()) + :rtype: :class:`~google.cloud.spanner_v1.database.Database` + :returns: The next database in the page. + """ + return Database.from_pb(database_pb, self, pool=BurstyPool()) diff --git a/spanner/google/cloud/spanner_v1/proto/keys_pb2.py b/spanner/google/cloud/spanner_v1/proto/keys_pb2.py index c7f216240e96..b20d88dce2d4 100644 --- a/spanner/google/cloud/spanner_v1/proto/keys_pb2.py +++ b/spanner/google/cloud/spanner_v1/proto/keys_pb2.py @@ -21,7 +21,7 @@ name='google/cloud/spanner_v1/proto/keys.proto', package='google.spanner.v1', syntax='proto3', - serialized_pb=_b('\n(google/cloud/spanner_v1/proto/keys.proto\x12\x11google.spanner.v1\x1a\x1cgoogle/api/annotations.proto\x1a\x1cgoogle/protobuf/struct.proto\"\xf4\x01\n\x08KeyRange\x12\x32\n\x0cstart_closed\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.ListValueH\x00\x12\x30\n\nstart_open\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.ListValueH\x00\x12\x30\n\nend_closed\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.ListValueH\x01\x12.\n\x08\x65nd_open\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.ListValueH\x01\x42\x10\n\x0estart_key_typeB\x0e\n\x0c\x65nd_key_type\"l\n\x06KeySet\x12(\n\x04keys\x18\x01 \x03(\x0b\x32\x1a.google.protobuf.ListValue\x12+\n\x06ranges\x18\x02 \x03(\x0b\x32\x1b.google.spanner.v1.KeyRange\x12\x0b\n\x03\x61ll\x18\x03 \x01(\x08\x42x\n\x15\x63om.google.spanner.v1B\tKeysProtoP\x01Z8google.golang.org/genproto/googleapis/spanner/v1;spanner\xaa\x02\x17Google.Cloud.Spanner.V1b\x06proto3') + serialized_pb=_b('\n(google/cloud/spanner_v1/proto/keys.proto\x12\x11google.spanner.v1\x1a\x1cgoogle/api/annotations.proto\x1a\x1cgoogle/protobuf/struct.proto\"\xf4\x01\n\x08KeyRange\x12\x32\n\x0cstart_closed\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.ListValueH\x00\x12\x30\n\nstart_open\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.ListValueH\x00\x12\x30\n\nend_closed\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.ListValueH\x01\x12.\n\x08\x65nd_open\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.ListValueH\x01\x42\x10\n\x0estart_key_typeB\x0e\n\x0c\x65nd_key_type\"l\n\x06KeySet\x12(\n\x04keys\x18\x01 \x03(\x0b\x32\x1a.google.protobuf.ListValue\x12+\n\x06ranges\x18\x02 \x03(\x0b\x32\x1b.google.spanner.v1.KeyRange\x12\x0b\n\x03\x61ll\x18\x03 \x01(\x08\x42\x92\x01\n\x15\x63om.google.spanner.v1B\tKeysProtoP\x01Z8google.golang.org/genproto/googleapis/spanner/v1;spanner\xaa\x02\x17Google.Cloud.Spanner.V1\xca\x02\x17Google\\Cloud\\Spanner\\V1b\x06proto3') , dependencies=[google_dot_api_dot_annotations__pb2.DESCRIPTOR,google_dot_protobuf_dot_struct__pb2.DESCRIPTOR,]) _sym_db.RegisterFileDescriptor(DESCRIPTOR) @@ -329,7 +329,7 @@ DESCRIPTOR.has_options = True -DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\025com.google.spanner.v1B\tKeysProtoP\001Z8google.golang.org/genproto/googleapis/spanner/v1;spanner\252\002\027Google.Cloud.Spanner.V1')) +DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\025com.google.spanner.v1B\tKeysProtoP\001Z8google.golang.org/genproto/googleapis/spanner/v1;spanner\252\002\027Google.Cloud.Spanner.V1\312\002\027Google\\Cloud\\Spanner\\V1')) try: # THESE ELEMENTS WILL BE DEPRECATED. # Please use the generated *_pb2_grpc.py files instead. diff --git a/spanner/google/cloud/spanner_v1/proto/mutation_pb2.py b/spanner/google/cloud/spanner_v1/proto/mutation_pb2.py index b51344de6d41..afa738be6bca 100644 --- a/spanner/google/cloud/spanner_v1/proto/mutation_pb2.py +++ b/spanner/google/cloud/spanner_v1/proto/mutation_pb2.py @@ -22,7 +22,7 @@ name='google/cloud/spanner_v1/proto/mutation.proto', package='google.spanner.v1', syntax='proto3', - serialized_pb=_b('\n,google/cloud/spanner_v1/proto/mutation.proto\x12\x11google.spanner.v1\x1a\x1cgoogle/api/annotations.proto\x1a\x1cgoogle/protobuf/struct.proto\x1a(google/cloud/spanner_v1/proto/keys.proto\"\xc6\x03\n\x08Mutation\x12\x33\n\x06insert\x18\x01 \x01(\x0b\x32!.google.spanner.v1.Mutation.WriteH\x00\x12\x33\n\x06update\x18\x02 \x01(\x0b\x32!.google.spanner.v1.Mutation.WriteH\x00\x12=\n\x10insert_or_update\x18\x03 \x01(\x0b\x32!.google.spanner.v1.Mutation.WriteH\x00\x12\x34\n\x07replace\x18\x04 \x01(\x0b\x32!.google.spanner.v1.Mutation.WriteH\x00\x12\x34\n\x06\x64\x65lete\x18\x05 \x01(\x0b\x32\".google.spanner.v1.Mutation.DeleteH\x00\x1aS\n\x05Write\x12\r\n\x05table\x18\x01 \x01(\t\x12\x0f\n\x07\x63olumns\x18\x02 \x03(\t\x12*\n\x06values\x18\x03 \x03(\x0b\x32\x1a.google.protobuf.ListValue\x1a\x43\n\x06\x44\x65lete\x12\r\n\x05table\x18\x01 \x01(\t\x12*\n\x07key_set\x18\x02 \x01(\x0b\x32\x19.google.spanner.v1.KeySetB\x0b\n\toperationB|\n\x15\x63om.google.spanner.v1B\rMutationProtoP\x01Z8google.golang.org/genproto/googleapis/spanner/v1;spanner\xaa\x02\x17Google.Cloud.Spanner.V1b\x06proto3') + serialized_pb=_b('\n,google/cloud/spanner_v1/proto/mutation.proto\x12\x11google.spanner.v1\x1a\x1cgoogle/api/annotations.proto\x1a\x1cgoogle/protobuf/struct.proto\x1a(google/cloud/spanner_v1/proto/keys.proto\"\xc6\x03\n\x08Mutation\x12\x33\n\x06insert\x18\x01 \x01(\x0b\x32!.google.spanner.v1.Mutation.WriteH\x00\x12\x33\n\x06update\x18\x02 \x01(\x0b\x32!.google.spanner.v1.Mutation.WriteH\x00\x12=\n\x10insert_or_update\x18\x03 \x01(\x0b\x32!.google.spanner.v1.Mutation.WriteH\x00\x12\x34\n\x07replace\x18\x04 \x01(\x0b\x32!.google.spanner.v1.Mutation.WriteH\x00\x12\x34\n\x06\x64\x65lete\x18\x05 \x01(\x0b\x32\".google.spanner.v1.Mutation.DeleteH\x00\x1aS\n\x05Write\x12\r\n\x05table\x18\x01 \x01(\t\x12\x0f\n\x07\x63olumns\x18\x02 \x03(\t\x12*\n\x06values\x18\x03 \x03(\x0b\x32\x1a.google.protobuf.ListValue\x1a\x43\n\x06\x44\x65lete\x12\r\n\x05table\x18\x01 \x01(\t\x12*\n\x07key_set\x18\x02 \x01(\x0b\x32\x19.google.spanner.v1.KeySetB\x0b\n\toperationB\x96\x01\n\x15\x63om.google.spanner.v1B\rMutationProtoP\x01Z8google.golang.org/genproto/googleapis/spanner/v1;spanner\xaa\x02\x17Google.Cloud.Spanner.V1\xca\x02\x17Google\\Cloud\\Spanner\\V1b\x06proto3') , dependencies=[google_dot_api_dot_annotations__pb2.DESCRIPTOR,google_dot_protobuf_dot_struct__pb2.DESCRIPTOR,google_dot_cloud_dot_spanner__v1_dot_proto_dot_keys__pb2.DESCRIPTOR,]) _sym_db.RegisterFileDescriptor(DESCRIPTOR) @@ -208,6 +208,29 @@ [update][google.spanner.v1.Mutation.update], [insert\_or\_update][google.spanner.v1.Mutation.insert\_or\_update], and [replace][google.spanner.v1.Mutation.replace] operations. + + + Attributes: + table: + Required. The table whose rows will be written. + columns: + The names of the columns in + [table][google.spanner.v1.Mutation.Write.table] to be written. + The list of columns must contain enough columns to allow Cloud + Spanner to derive values for all primary key columns in the + row(s) to be modified. + values: + The values to be written. ``values`` can contain more than one + list of values. If it does, then multiple rows are written, + one for each entry in ``values``. Each list in ``values`` must + have exactly as many entries as there are entries in + [columns][google.spanner.v1.Mutation.Write.columns] above. + Sending multiple lists is equivalent to sending multiple + ``Mutation``\ s, each containing one ``values`` entry and + repeating [table][google.spanner.v1.Mutation.Write.table] and + [columns][google.spanner.v1.Mutation.Write.columns]. + Individual values in each list are encoded as described + [here][google.spanner.v1.TypeCode]. """, # @@protoc_insertion_point(class_scope:google.spanner.v1.Mutation.Write) )) @@ -218,6 +241,14 @@ __module__ = 'google.cloud.spanner_v1.proto.mutation_pb2' , __doc__ = """Arguments to [delete][google.spanner.v1.Mutation.delete] operations. + + + Attributes: + table: + Required. The table whose rows will be deleted. + key_set: + Required. The primary keys of the rows within + [table][google.spanner.v1.Mutation.Delete.table] to delete. """, # @@protoc_insertion_point(class_scope:google.spanner.v1.Mutation.Delete) )) @@ -231,29 +262,6 @@ Attributes: - table: - Required. The table whose rows will be deleted. - columns: - The names of the columns in - [table][google.spanner.v1.Mutation.Write.table] to be written. - The list of columns must contain enough columns to allow Cloud - Spanner to derive values for all primary key columns in the - row(s) to be modified. - values: - The values to be written. ``values`` can contain more than one - list of values. If it does, then multiple rows are written, - one for each entry in ``values``. Each list in ``values`` must - have exactly as many entries as there are entries in - [columns][google.spanner.v1.Mutation.Write.columns] above. - Sending multiple lists is equivalent to sending multiple - ``Mutation``\ s, each containing one ``values`` entry and - repeating [table][google.spanner.v1.Mutation.Write.table] and - [columns][google.spanner.v1.Mutation.Write.columns]. - Individual values in each list are encoded as described - [here][google.spanner.v1.TypeCode]. - key_set: - Required. The primary keys of the rows within - [table][google.spanner.v1.Mutation.Delete.table] to delete. operation: Required. The operation to perform. insert: @@ -285,7 +293,7 @@ DESCRIPTOR.has_options = True -DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\025com.google.spanner.v1B\rMutationProtoP\001Z8google.golang.org/genproto/googleapis/spanner/v1;spanner\252\002\027Google.Cloud.Spanner.V1')) +DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\025com.google.spanner.v1B\rMutationProtoP\001Z8google.golang.org/genproto/googleapis/spanner/v1;spanner\252\002\027Google.Cloud.Spanner.V1\312\002\027Google\\Cloud\\Spanner\\V1')) try: # THESE ELEMENTS WILL BE DEPRECATED. # Please use the generated *_pb2_grpc.py files instead. diff --git a/spanner/google/cloud/spanner_v1/proto/query_plan_pb2.py b/spanner/google/cloud/spanner_v1/proto/query_plan_pb2.py index cfa5bb03a4f5..5472e099c2ce 100644 --- a/spanner/google/cloud/spanner_v1/proto/query_plan_pb2.py +++ b/spanner/google/cloud/spanner_v1/proto/query_plan_pb2.py @@ -21,7 +21,7 @@ name='google/cloud/spanner_v1/proto/query_plan.proto', package='google.spanner.v1', syntax='proto3', - serialized_pb=_b('\n.google/cloud/spanner_v1/proto/query_plan.proto\x12\x11google.spanner.v1\x1a\x1cgoogle/api/annotations.proto\x1a\x1cgoogle/protobuf/struct.proto\"\xf8\x04\n\x08PlanNode\x12\r\n\x05index\x18\x01 \x01(\x05\x12.\n\x04kind\x18\x02 \x01(\x0e\x32 .google.spanner.v1.PlanNode.Kind\x12\x14\n\x0c\x64isplay_name\x18\x03 \x01(\t\x12:\n\x0b\x63hild_links\x18\x04 \x03(\x0b\x32%.google.spanner.v1.PlanNode.ChildLink\x12M\n\x14short_representation\x18\x05 \x01(\x0b\x32/.google.spanner.v1.PlanNode.ShortRepresentation\x12)\n\x08metadata\x18\x06 \x01(\x0b\x32\x17.google.protobuf.Struct\x12\x30\n\x0f\x65xecution_stats\x18\x07 \x01(\x0b\x32\x17.google.protobuf.Struct\x1a@\n\tChildLink\x12\x13\n\x0b\x63hild_index\x18\x01 \x01(\x05\x12\x0c\n\x04type\x18\x02 \x01(\t\x12\x10\n\x08variable\x18\x03 \x01(\t\x1a\xb2\x01\n\x13ShortRepresentation\x12\x13\n\x0b\x64\x65scription\x18\x01 \x01(\t\x12S\n\nsubqueries\x18\x02 \x03(\x0b\x32?.google.spanner.v1.PlanNode.ShortRepresentation.SubqueriesEntry\x1a\x31\n\x0fSubqueriesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\"8\n\x04Kind\x12\x14\n\x10KIND_UNSPECIFIED\x10\x00\x12\x0e\n\nRELATIONAL\x10\x01\x12\n\n\x06SCALAR\x10\x02\"<\n\tQueryPlan\x12/\n\nplan_nodes\x18\x01 \x03(\x0b\x32\x1b.google.spanner.v1.PlanNodeB}\n\x15\x63om.google.spanner.v1B\x0eQueryPlanProtoP\x01Z8google.golang.org/genproto/googleapis/spanner/v1;spanner\xaa\x02\x17Google.Cloud.Spanner.V1b\x06proto3') + serialized_pb=_b('\n.google/cloud/spanner_v1/proto/query_plan.proto\x12\x11google.spanner.v1\x1a\x1cgoogle/api/annotations.proto\x1a\x1cgoogle/protobuf/struct.proto\"\xf8\x04\n\x08PlanNode\x12\r\n\x05index\x18\x01 \x01(\x05\x12.\n\x04kind\x18\x02 \x01(\x0e\x32 .google.spanner.v1.PlanNode.Kind\x12\x14\n\x0c\x64isplay_name\x18\x03 \x01(\t\x12:\n\x0b\x63hild_links\x18\x04 \x03(\x0b\x32%.google.spanner.v1.PlanNode.ChildLink\x12M\n\x14short_representation\x18\x05 \x01(\x0b\x32/.google.spanner.v1.PlanNode.ShortRepresentation\x12)\n\x08metadata\x18\x06 \x01(\x0b\x32\x17.google.protobuf.Struct\x12\x30\n\x0f\x65xecution_stats\x18\x07 \x01(\x0b\x32\x17.google.protobuf.Struct\x1a@\n\tChildLink\x12\x13\n\x0b\x63hild_index\x18\x01 \x01(\x05\x12\x0c\n\x04type\x18\x02 \x01(\t\x12\x10\n\x08variable\x18\x03 \x01(\t\x1a\xb2\x01\n\x13ShortRepresentation\x12\x13\n\x0b\x64\x65scription\x18\x01 \x01(\t\x12S\n\nsubqueries\x18\x02 \x03(\x0b\x32?.google.spanner.v1.PlanNode.ShortRepresentation.SubqueriesEntry\x1a\x31\n\x0fSubqueriesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\"8\n\x04Kind\x12\x14\n\x10KIND_UNSPECIFIED\x10\x00\x12\x0e\n\nRELATIONAL\x10\x01\x12\n\n\x06SCALAR\x10\x02\"<\n\tQueryPlan\x12/\n\nplan_nodes\x18\x01 \x03(\x0b\x32\x1b.google.spanner.v1.PlanNodeB\x97\x01\n\x15\x63om.google.spanner.v1B\x0eQueryPlanProtoP\x01Z8google.golang.org/genproto/googleapis/spanner/v1;spanner\xaa\x02\x17Google.Cloud.Spanner.V1\xca\x02\x17Google\\Cloud\\Spanner\\V1b\x06proto3') , dependencies=[google_dot_api_dot_annotations__pb2.DESCRIPTOR,google_dot_protobuf_dot_struct__pb2.DESCRIPTOR,]) _sym_db.RegisterFileDescriptor(DESCRIPTOR) @@ -299,6 +299,26 @@ , __doc__ = """Metadata associated with a parent-child relationship appearing in a [PlanNode][google.spanner.v1.PlanNode]. + + + Attributes: + child_index: + The node to which the link points. + type: + The type of the link. For example, in Hash Joins this could be + used to distinguish between the build child and the probe + child, or in the case of the child being an output variable, + to represent the tag associated with the output variable. + variable: + Only present if the child node is + [SCALAR][google.spanner.v1.PlanNode.Kind.SCALAR] and + corresponds to an output variable of the parent node. The + field carries the name of the output variable. For example, a + ``TableScan`` operator that reads rows from a table will have + child links to the ``SCALAR`` nodes representing the output + variables created for each column that is read by the + operator. The corresponding ``variable`` fields will be set to + the variable names assigned to the columns. """, # @@protoc_insertion_point(class_scope:google.spanner.v1.PlanNode.ChildLink) )) @@ -317,6 +337,18 @@ , __doc__ = """Condensed representation of a node and its subtree. Only present for ``SCALAR`` [PlanNode(s)][google.spanner.v1.PlanNode]. + + + Attributes: + description: + A string representation of the expression subtree rooted at + this node. + subqueries: + A mapping of (subquery variable name) -> (subquery node id) + for cases where the ``description`` string of this node + references a ``SCALAR`` subquery contained in the expression + subtree rooted at this node. The referenced ``SCALAR`` + subquery may not necessarily be a direct child of this node. """, # @@protoc_insertion_point(class_scope:google.spanner.v1.PlanNode.ShortRepresentation) )) @@ -329,32 +361,6 @@ Attributes: - child_index: - The node to which the link points. - type: - The type of the link. For example, in Hash Joins this could be - used to distinguish between the build child and the probe - child, or in the case of the child being an output variable, - to represent the tag associated with the output variable. - variable: - Only present if the child node is - [SCALAR][google.spanner.v1.PlanNode.Kind.SCALAR] and - corresponds to an output variable of the parent node. The - field carries the name of the output variable. For example, a - ``TableScan`` operator that reads rows from a table will have - child links to the ``SCALAR`` nodes representing the output - variables created for each column that is read by the - operator. The corresponding ``variable`` fields will be set to - the variable names assigned to the columns. - description: - A string representation of the expression subtree rooted at - this node. - subqueries: - A mapping of (subquery variable name) -> (subquery node id) - for cases where the ``description`` string of this node - references a ``SCALAR`` subquery contained in the expression - subtree rooted at this node. The referenced ``SCALAR`` - subquery may not necessarily be a direct child of this node. index: The ``PlanNode``'s index in [node list][google.spanner.v1.QueryPlan.plan\_nodes]. @@ -412,7 +418,7 @@ DESCRIPTOR.has_options = True -DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\025com.google.spanner.v1B\016QueryPlanProtoP\001Z8google.golang.org/genproto/googleapis/spanner/v1;spanner\252\002\027Google.Cloud.Spanner.V1')) +DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\025com.google.spanner.v1B\016QueryPlanProtoP\001Z8google.golang.org/genproto/googleapis/spanner/v1;spanner\252\002\027Google.Cloud.Spanner.V1\312\002\027Google\\Cloud\\Spanner\\V1')) _PLANNODE_SHORTREPRESENTATION_SUBQUERIESENTRY.has_options = True _PLANNODE_SHORTREPRESENTATION_SUBQUERIESENTRY._options = _descriptor._ParseOptions(descriptor_pb2.MessageOptions(), _b('8\001')) try: diff --git a/spanner/google/cloud/spanner_v1/proto/result_set_pb2.py b/spanner/google/cloud/spanner_v1/proto/result_set_pb2.py index 6eac4bcd2f10..3bb9339f4cb2 100644 --- a/spanner/google/cloud/spanner_v1/proto/result_set_pb2.py +++ b/spanner/google/cloud/spanner_v1/proto/result_set_pb2.py @@ -24,7 +24,7 @@ name='google/cloud/spanner_v1/proto/result_set.proto', package='google.spanner.v1', syntax='proto3', - serialized_pb=_b('\n.google/cloud/spanner_v1/proto/result_set.proto\x12\x11google.spanner.v1\x1a\x1cgoogle/api/annotations.proto\x1a\x1cgoogle/protobuf/struct.proto\x1a.google/cloud/spanner_v1/proto/query_plan.proto\x1a/google/cloud/spanner_v1/proto/transaction.proto\x1a(google/cloud/spanner_v1/proto/type.proto\"\x9f\x01\n\tResultSet\x12\x36\n\x08metadata\x18\x01 \x01(\x0b\x32$.google.spanner.v1.ResultSetMetadata\x12(\n\x04rows\x18\x02 \x03(\x0b\x32\x1a.google.protobuf.ListValue\x12\x30\n\x05stats\x18\x03 \x01(\x0b\x32!.google.spanner.v1.ResultSetStats\"\xd1\x01\n\x10PartialResultSet\x12\x36\n\x08metadata\x18\x01 \x01(\x0b\x32$.google.spanner.v1.ResultSetMetadata\x12&\n\x06values\x18\x02 \x03(\x0b\x32\x16.google.protobuf.Value\x12\x15\n\rchunked_value\x18\x03 \x01(\x08\x12\x14\n\x0cresume_token\x18\x04 \x01(\x0c\x12\x30\n\x05stats\x18\x05 \x01(\x0b\x32!.google.spanner.v1.ResultSetStats\"y\n\x11ResultSetMetadata\x12/\n\x08row_type\x18\x01 \x01(\x0b\x32\x1d.google.spanner.v1.StructType\x12\x33\n\x0btransaction\x18\x02 \x01(\x0b\x32\x1e.google.spanner.v1.Transaction\"p\n\x0eResultSetStats\x12\x30\n\nquery_plan\x18\x01 \x01(\x0b\x32\x1c.google.spanner.v1.QueryPlan\x12,\n\x0bquery_stats\x18\x02 \x01(\x0b\x32\x17.google.protobuf.StructB}\n\x15\x63om.google.spanner.v1B\x0eResultSetProtoP\x01Z8google.golang.org/genproto/googleapis/spanner/v1;spanner\xaa\x02\x17Google.Cloud.Spanner.V1b\x06proto3') + serialized_pb=_b('\n.google/cloud/spanner_v1/proto/result_set.proto\x12\x11google.spanner.v1\x1a\x1cgoogle/api/annotations.proto\x1a\x1cgoogle/protobuf/struct.proto\x1a.google/cloud/spanner_v1/proto/query_plan.proto\x1a/google/cloud/spanner_v1/proto/transaction.proto\x1a(google/cloud/spanner_v1/proto/type.proto\"\x9f\x01\n\tResultSet\x12\x36\n\x08metadata\x18\x01 \x01(\x0b\x32$.google.spanner.v1.ResultSetMetadata\x12(\n\x04rows\x18\x02 \x03(\x0b\x32\x1a.google.protobuf.ListValue\x12\x30\n\x05stats\x18\x03 \x01(\x0b\x32!.google.spanner.v1.ResultSetStats\"\xd1\x01\n\x10PartialResultSet\x12\x36\n\x08metadata\x18\x01 \x01(\x0b\x32$.google.spanner.v1.ResultSetMetadata\x12&\n\x06values\x18\x02 \x03(\x0b\x32\x16.google.protobuf.Value\x12\x15\n\rchunked_value\x18\x03 \x01(\x08\x12\x14\n\x0cresume_token\x18\x04 \x01(\x0c\x12\x30\n\x05stats\x18\x05 \x01(\x0b\x32!.google.spanner.v1.ResultSetStats\"y\n\x11ResultSetMetadata\x12/\n\x08row_type\x18\x01 \x01(\x0b\x32\x1d.google.spanner.v1.StructType\x12\x33\n\x0btransaction\x18\x02 \x01(\x0b\x32\x1e.google.spanner.v1.Transaction\"p\n\x0eResultSetStats\x12\x30\n\nquery_plan\x18\x01 \x01(\x0b\x32\x1c.google.spanner.v1.QueryPlan\x12,\n\x0bquery_stats\x18\x02 \x01(\x0b\x32\x17.google.protobuf.StructB\x9a\x01\n\x15\x63om.google.spanner.v1B\x0eResultSetProtoP\x01Z8google.golang.org/genproto/googleapis/spanner/v1;spanner\xf8\x01\x01\xaa\x02\x17Google.Cloud.Spanner.V1\xca\x02\x17Google\\Cloud\\Spanner\\V1b\x06proto3') , dependencies=[google_dot_api_dot_annotations__pb2.DESCRIPTOR,google_dot_protobuf_dot_struct__pb2.DESCRIPTOR,google_dot_cloud_dot_spanner__v1_dot_proto_dot_query__plan__pb2.DESCRIPTOR,google_dot_cloud_dot_spanner__v1_dot_proto_dot_transaction__pb2.DESCRIPTOR,google_dot_cloud_dot_spanner__v1_dot_proto_dot_type__pb2.DESCRIPTOR,]) _sym_db.RegisterFileDescriptor(DESCRIPTOR) @@ -385,7 +385,7 @@ DESCRIPTOR.has_options = True -DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\025com.google.spanner.v1B\016ResultSetProtoP\001Z8google.golang.org/genproto/googleapis/spanner/v1;spanner\252\002\027Google.Cloud.Spanner.V1')) +DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\025com.google.spanner.v1B\016ResultSetProtoP\001Z8google.golang.org/genproto/googleapis/spanner/v1;spanner\370\001\001\252\002\027Google.Cloud.Spanner.V1\312\002\027Google\\Cloud\\Spanner\\V1')) try: # THESE ELEMENTS WILL BE DEPRECATED. # Please use the generated *_pb2_grpc.py files instead. diff --git a/spanner/google/cloud/spanner_v1/proto/spanner_pb2.py b/spanner/google/cloud/spanner_v1/proto/spanner_pb2.py index 658bd4117e47..53e057f7b6a0 100644 --- a/spanner/google/cloud/spanner_v1/proto/spanner_pb2.py +++ b/spanner/google/cloud/spanner_v1/proto/spanner_pb2.py @@ -14,7 +14,6 @@ from google.api import annotations_pb2 as google_dot_api_dot_annotations__pb2 -from google.api import auth_pb2 as google_dot_api_dot_auth__pb2 from google.protobuf import empty_pb2 as google_dot_protobuf_dot_empty__pb2 from google.protobuf import struct_pb2 as google_dot_protobuf_dot_struct__pb2 from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2 @@ -29,9 +28,9 @@ name='google/cloud/spanner_v1/proto/spanner.proto', package='google.spanner.v1', syntax='proto3', - serialized_pb=_b('\n+google/cloud/spanner_v1/proto/spanner.proto\x12\x11google.spanner.v1\x1a\x1cgoogle/api/annotations.proto\x1a\x15google/api/auth.proto\x1a\x1bgoogle/protobuf/empty.proto\x1a\x1cgoogle/protobuf/struct.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a(google/cloud/spanner_v1/proto/keys.proto\x1a,google/cloud/spanner_v1/proto/mutation.proto\x1a.google/cloud/spanner_v1/proto/result_set.proto\x1a/google/cloud/spanner_v1/proto/transaction.proto\x1a(google/cloud/spanner_v1/proto/type.proto\"(\n\x14\x43reateSessionRequest\x12\x10\n\x08\x64\x61tabase\x18\x01 \x01(\t\"\x17\n\x07Session\x12\x0c\n\x04name\x18\x01 \x01(\t\"!\n\x11GetSessionRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"$\n\x14\x44\x65leteSessionRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"\xb8\x03\n\x11\x45xecuteSqlRequest\x12\x0f\n\x07session\x18\x01 \x01(\t\x12;\n\x0btransaction\x18\x02 \x01(\x0b\x32&.google.spanner.v1.TransactionSelector\x12\x0b\n\x03sql\x18\x03 \x01(\t\x12\'\n\x06params\x18\x04 \x01(\x0b\x32\x17.google.protobuf.Struct\x12I\n\x0bparam_types\x18\x05 \x03(\x0b\x32\x34.google.spanner.v1.ExecuteSqlRequest.ParamTypesEntry\x12\x14\n\x0cresume_token\x18\x06 \x01(\x0c\x12\x42\n\nquery_mode\x18\x07 \x01(\x0e\x32..google.spanner.v1.ExecuteSqlRequest.QueryMode\x1aJ\n\x0fParamTypesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.google.spanner.v1.Type:\x02\x38\x01\".\n\tQueryMode\x12\n\n\x06NORMAL\x10\x00\x12\x08\n\x04PLAN\x10\x01\x12\x0b\n\x07PROFILE\x10\x02\"\xdb\x01\n\x0bReadRequest\x12\x0f\n\x07session\x18\x01 \x01(\t\x12;\n\x0btransaction\x18\x02 \x01(\x0b\x32&.google.spanner.v1.TransactionSelector\x12\r\n\x05table\x18\x03 \x01(\t\x12\r\n\x05index\x18\x04 \x01(\t\x12\x0f\n\x07\x63olumns\x18\x05 \x03(\t\x12*\n\x07key_set\x18\x06 \x01(\x0b\x32\x19.google.spanner.v1.KeySet\x12\r\n\x05limit\x18\x08 \x01(\x03\x12\x14\n\x0cresume_token\x18\t \x01(\x0c\"b\n\x17\x42\x65ginTransactionRequest\x12\x0f\n\x07session\x18\x01 \x01(\t\x12\x36\n\x07options\x18\x02 \x01(\x0b\x32%.google.spanner.v1.TransactionOptions\"\xc2\x01\n\rCommitRequest\x12\x0f\n\x07session\x18\x01 \x01(\t\x12\x18\n\x0etransaction_id\x18\x02 \x01(\x0cH\x00\x12G\n\x16single_use_transaction\x18\x03 \x01(\x0b\x32%.google.spanner.v1.TransactionOptionsH\x00\x12.\n\tmutations\x18\x04 \x03(\x0b\x32\x1b.google.spanner.v1.MutationB\r\n\x0btransaction\"F\n\x0e\x43ommitResponse\x12\x34\n\x10\x63ommit_timestamp\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\":\n\x0fRollbackRequest\x12\x0f\n\x07session\x18\x01 \x01(\t\x12\x16\n\x0etransaction_id\x18\x02 \x01(\x0c\x32\xe9\x0c\n\x07Spanner\x12\x98\x01\n\rCreateSession\x12\'.google.spanner.v1.CreateSessionRequest\x1a\x1a.google.spanner.v1.Session\"B\x82\xd3\xe4\x93\x02<\":/v1/{database=projects/*/instances/*/databases/*}/sessions\x12\x90\x01\n\nGetSession\x12$.google.spanner.v1.GetSessionRequest\x1a\x1a.google.spanner.v1.Session\"@\x82\xd3\xe4\x93\x02:\x12\x38/v1/{name=projects/*/instances/*/databases/*/sessions/*}\x12\x92\x01\n\rDeleteSession\x12\'.google.spanner.v1.DeleteSessionRequest\x1a\x16.google.protobuf.Empty\"@\x82\xd3\xe4\x93\x02:*8/v1/{name=projects/*/instances/*/databases/*/sessions/*}\x12\xa3\x01\n\nExecuteSql\x12$.google.spanner.v1.ExecuteSqlRequest\x1a\x1c.google.spanner.v1.ResultSet\"Q\x82\xd3\xe4\x93\x02K\"F/v1/{session=projects/*/instances/*/databases/*/sessions/*}:executeSql:\x01*\x12\xbe\x01\n\x13\x45xecuteStreamingSql\x12$.google.spanner.v1.ExecuteSqlRequest\x1a#.google.spanner.v1.PartialResultSet\"Z\x82\xd3\xe4\x93\x02T\"O/v1/{session=projects/*/instances/*/databases/*/sessions/*}:executeStreamingSql:\x01*0\x01\x12\x91\x01\n\x04Read\x12\x1e.google.spanner.v1.ReadRequest\x1a\x1c.google.spanner.v1.ResultSet\"K\x82\xd3\xe4\x93\x02\x45\"@/v1/{session=projects/*/instances/*/databases/*/sessions/*}:read:\x01*\x12\xac\x01\n\rStreamingRead\x12\x1e.google.spanner.v1.ReadRequest\x1a#.google.spanner.v1.PartialResultSet\"T\x82\xd3\xe4\x93\x02N\"I/v1/{session=projects/*/instances/*/databases/*/sessions/*}:streamingRead:\x01*0\x01\x12\xb7\x01\n\x10\x42\x65ginTransaction\x12*.google.spanner.v1.BeginTransactionRequest\x1a\x1e.google.spanner.v1.Transaction\"W\x82\xd3\xe4\x93\x02Q\"L/v1/{session=projects/*/instances/*/databases/*/sessions/*}:beginTransaction:\x01*\x12\x9c\x01\n\x06\x43ommit\x12 .google.spanner.v1.CommitRequest\x1a!.google.spanner.v1.CommitResponse\"M\x82\xd3\xe4\x93\x02G\"B/v1/{session=projects/*/instances/*/databases/*/sessions/*}:commit:\x01*\x12\x97\x01\n\x08Rollback\x12\".google.spanner.v1.RollbackRequest\x1a\x16.google.protobuf.Empty\"O\x82\xd3\xe4\x93\x02I\"D/v1/{session=projects/*/instances/*/databases/*/sessions/*}:rollback:\x01*B{\n\x15\x63om.google.spanner.v1B\x0cSpannerProtoP\x01Z8google.golang.org/genproto/googleapis/spanner/v1;spanner\xaa\x02\x17Google.Cloud.Spanner.V1b\x06proto3') + serialized_pb=_b('\n+google/cloud/spanner_v1/proto/spanner.proto\x12\x11google.spanner.v1\x1a\x1cgoogle/api/annotations.proto\x1a\x1bgoogle/protobuf/empty.proto\x1a\x1cgoogle/protobuf/struct.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a(google/cloud/spanner_v1/proto/keys.proto\x1a,google/cloud/spanner_v1/proto/mutation.proto\x1a.google/cloud/spanner_v1/proto/result_set.proto\x1a/google/cloud/spanner_v1/proto/transaction.proto\x1a(google/cloud/spanner_v1/proto/type.proto\"U\n\x14\x43reateSessionRequest\x12\x10\n\x08\x64\x61tabase\x18\x01 \x01(\t\x12+\n\x07session\x18\x02 \x01(\x0b\x32\x1a.google.spanner.v1.Session\"\xee\x01\n\x07Session\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x36\n\x06labels\x18\x02 \x03(\x0b\x32&.google.spanner.v1.Session.LabelsEntry\x12/\n\x0b\x63reate_time\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12=\n\x19\x61pproximate_last_use_time\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x1a-\n\x0bLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"!\n\x11GetSessionRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"^\n\x13ListSessionsRequest\x12\x10\n\x08\x64\x61tabase\x18\x01 \x01(\t\x12\x11\n\tpage_size\x18\x02 \x01(\x05\x12\x12\n\npage_token\x18\x03 \x01(\t\x12\x0e\n\x06\x66ilter\x18\x04 \x01(\t\"]\n\x14ListSessionsResponse\x12,\n\x08sessions\x18\x01 \x03(\x0b\x32\x1a.google.spanner.v1.Session\x12\x17\n\x0fnext_page_token\x18\x02 \x01(\t\"$\n\x14\x44\x65leteSessionRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"\xb8\x03\n\x11\x45xecuteSqlRequest\x12\x0f\n\x07session\x18\x01 \x01(\t\x12;\n\x0btransaction\x18\x02 \x01(\x0b\x32&.google.spanner.v1.TransactionSelector\x12\x0b\n\x03sql\x18\x03 \x01(\t\x12\'\n\x06params\x18\x04 \x01(\x0b\x32\x17.google.protobuf.Struct\x12I\n\x0bparam_types\x18\x05 \x03(\x0b\x32\x34.google.spanner.v1.ExecuteSqlRequest.ParamTypesEntry\x12\x14\n\x0cresume_token\x18\x06 \x01(\x0c\x12\x42\n\nquery_mode\x18\x07 \x01(\x0e\x32..google.spanner.v1.ExecuteSqlRequest.QueryMode\x1aJ\n\x0fParamTypesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.google.spanner.v1.Type:\x02\x38\x01\".\n\tQueryMode\x12\n\n\x06NORMAL\x10\x00\x12\x08\n\x04PLAN\x10\x01\x12\x0b\n\x07PROFILE\x10\x02\"\xdb\x01\n\x0bReadRequest\x12\x0f\n\x07session\x18\x01 \x01(\t\x12;\n\x0btransaction\x18\x02 \x01(\x0b\x32&.google.spanner.v1.TransactionSelector\x12\r\n\x05table\x18\x03 \x01(\t\x12\r\n\x05index\x18\x04 \x01(\t\x12\x0f\n\x07\x63olumns\x18\x05 \x03(\t\x12*\n\x07key_set\x18\x06 \x01(\x0b\x32\x19.google.spanner.v1.KeySet\x12\r\n\x05limit\x18\x08 \x01(\x03\x12\x14\n\x0cresume_token\x18\t \x01(\x0c\"b\n\x17\x42\x65ginTransactionRequest\x12\x0f\n\x07session\x18\x01 \x01(\t\x12\x36\n\x07options\x18\x02 \x01(\x0b\x32%.google.spanner.v1.TransactionOptions\"\xc2\x01\n\rCommitRequest\x12\x0f\n\x07session\x18\x01 \x01(\t\x12\x18\n\x0etransaction_id\x18\x02 \x01(\x0cH\x00\x12G\n\x16single_use_transaction\x18\x03 \x01(\x0b\x32%.google.spanner.v1.TransactionOptionsH\x00\x12.\n\tmutations\x18\x04 \x03(\x0b\x32\x1b.google.spanner.v1.MutationB\r\n\x0btransaction\"F\n\x0e\x43ommitResponse\x12\x34\n\x10\x63ommit_timestamp\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\":\n\x0fRollbackRequest\x12\x0f\n\x07session\x18\x01 \x01(\t\x12\x16\n\x0etransaction_id\x18\x02 \x01(\x0c\x32\x92\x0e\n\x07Spanner\x12\x9b\x01\n\rCreateSession\x12\'.google.spanner.v1.CreateSessionRequest\x1a\x1a.google.spanner.v1.Session\"E\x82\xd3\xe4\x93\x02?\":/v1/{database=projects/*/instances/*/databases/*}/sessions:\x01*\x12\x90\x01\n\nGetSession\x12$.google.spanner.v1.GetSessionRequest\x1a\x1a.google.spanner.v1.Session\"@\x82\xd3\xe4\x93\x02:\x12\x38/v1/{name=projects/*/instances/*/databases/*/sessions/*}\x12\xa3\x01\n\x0cListSessions\x12&.google.spanner.v1.ListSessionsRequest\x1a\'.google.spanner.v1.ListSessionsResponse\"B\x82\xd3\xe4\x93\x02<\x12:/v1/{database=projects/*/instances/*/databases/*}/sessions\x12\x92\x01\n\rDeleteSession\x12\'.google.spanner.v1.DeleteSessionRequest\x1a\x16.google.protobuf.Empty\"@\x82\xd3\xe4\x93\x02:*8/v1/{name=projects/*/instances/*/databases/*/sessions/*}\x12\xa3\x01\n\nExecuteSql\x12$.google.spanner.v1.ExecuteSqlRequest\x1a\x1c.google.spanner.v1.ResultSet\"Q\x82\xd3\xe4\x93\x02K\"F/v1/{session=projects/*/instances/*/databases/*/sessions/*}:executeSql:\x01*\x12\xbe\x01\n\x13\x45xecuteStreamingSql\x12$.google.spanner.v1.ExecuteSqlRequest\x1a#.google.spanner.v1.PartialResultSet\"Z\x82\xd3\xe4\x93\x02T\"O/v1/{session=projects/*/instances/*/databases/*/sessions/*}:executeStreamingSql:\x01*0\x01\x12\x91\x01\n\x04Read\x12\x1e.google.spanner.v1.ReadRequest\x1a\x1c.google.spanner.v1.ResultSet\"K\x82\xd3\xe4\x93\x02\x45\"@/v1/{session=projects/*/instances/*/databases/*/sessions/*}:read:\x01*\x12\xac\x01\n\rStreamingRead\x12\x1e.google.spanner.v1.ReadRequest\x1a#.google.spanner.v1.PartialResultSet\"T\x82\xd3\xe4\x93\x02N\"I/v1/{session=projects/*/instances/*/databases/*/sessions/*}:streamingRead:\x01*0\x01\x12\xb7\x01\n\x10\x42\x65ginTransaction\x12*.google.spanner.v1.BeginTransactionRequest\x1a\x1e.google.spanner.v1.Transaction\"W\x82\xd3\xe4\x93\x02Q\"L/v1/{session=projects/*/instances/*/databases/*/sessions/*}:beginTransaction:\x01*\x12\x9c\x01\n\x06\x43ommit\x12 .google.spanner.v1.CommitRequest\x1a!.google.spanner.v1.CommitResponse\"M\x82\xd3\xe4\x93\x02G\"B/v1/{session=projects/*/instances/*/databases/*/sessions/*}:commit:\x01*\x12\x97\x01\n\x08Rollback\x12\".google.spanner.v1.RollbackRequest\x1a\x16.google.protobuf.Empty\"O\x82\xd3\xe4\x93\x02I\"D/v1/{session=projects/*/instances/*/databases/*/sessions/*}:rollback:\x01*B\x95\x01\n\x15\x63om.google.spanner.v1B\x0cSpannerProtoP\x01Z8google.golang.org/genproto/googleapis/spanner/v1;spanner\xaa\x02\x17Google.Cloud.Spanner.V1\xca\x02\x17Google\\Cloud\\Spanner\\V1b\x06proto3') , - dependencies=[google_dot_api_dot_annotations__pb2.DESCRIPTOR,google_dot_api_dot_auth__pb2.DESCRIPTOR,google_dot_protobuf_dot_empty__pb2.DESCRIPTOR,google_dot_protobuf_dot_struct__pb2.DESCRIPTOR,google_dot_protobuf_dot_timestamp__pb2.DESCRIPTOR,google_dot_cloud_dot_spanner__v1_dot_proto_dot_keys__pb2.DESCRIPTOR,google_dot_cloud_dot_spanner__v1_dot_proto_dot_mutation__pb2.DESCRIPTOR,google_dot_cloud_dot_spanner__v1_dot_proto_dot_result__set__pb2.DESCRIPTOR,google_dot_cloud_dot_spanner__v1_dot_proto_dot_transaction__pb2.DESCRIPTOR,google_dot_cloud_dot_spanner__v1_dot_proto_dot_type__pb2.DESCRIPTOR,]) + dependencies=[google_dot_api_dot_annotations__pb2.DESCRIPTOR,google_dot_protobuf_dot_empty__pb2.DESCRIPTOR,google_dot_protobuf_dot_struct__pb2.DESCRIPTOR,google_dot_protobuf_dot_timestamp__pb2.DESCRIPTOR,google_dot_cloud_dot_spanner__v1_dot_proto_dot_keys__pb2.DESCRIPTOR,google_dot_cloud_dot_spanner__v1_dot_proto_dot_mutation__pb2.DESCRIPTOR,google_dot_cloud_dot_spanner__v1_dot_proto_dot_result__set__pb2.DESCRIPTOR,google_dot_cloud_dot_spanner__v1_dot_proto_dot_transaction__pb2.DESCRIPTOR,google_dot_cloud_dot_spanner__v1_dot_proto_dot_type__pb2.DESCRIPTOR,]) _sym_db.RegisterFileDescriptor(DESCRIPTOR) @@ -57,8 +56,8 @@ ], containing_type=None, options=None, - serialized_start=973, - serialized_end=1019, + serialized_start=1402, + serialized_end=1448, ) _sym_db.RegisterEnumDescriptor(_EXECUTESQLREQUEST_QUERYMODE) @@ -77,6 +76,13 @@ message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), + _descriptor.FieldDescriptor( + name='session', full_name='google.spanner.v1.CreateSessionRequest.session', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), ], extensions=[ ], @@ -89,11 +95,48 @@ extension_ranges=[], oneofs=[ ], - serialized_start=438, - serialized_end=478, + serialized_start=415, + serialized_end=500, ) +_SESSION_LABELSENTRY = _descriptor.Descriptor( + name='LabelsEntry', + full_name='google.spanner.v1.Session.LabelsEntry', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='key', full_name='google.spanner.v1.Session.LabelsEntry.key', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='value', full_name='google.spanner.v1.Session.LabelsEntry.value', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=_descriptor._ParseOptions(descriptor_pb2.MessageOptions(), _b('8\001')), + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=696, + serialized_end=741, +) + _SESSION = _descriptor.Descriptor( name='Session', full_name='google.spanner.v1.Session', @@ -108,10 +151,31 @@ message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), + _descriptor.FieldDescriptor( + name='labels', full_name='google.spanner.v1.Session.labels', index=1, + number=2, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='create_time', full_name='google.spanner.v1.Session.create_time', index=2, + number=3, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='approximate_last_use_time', full_name='google.spanner.v1.Session.approximate_last_use_time', index=3, + number=4, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), ], extensions=[ ], - nested_types=[], + nested_types=[_SESSION_LABELSENTRY, ], enum_types=[ ], options=None, @@ -120,8 +184,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=480, - serialized_end=503, + serialized_start=503, + serialized_end=741, ) @@ -151,8 +215,98 @@ extension_ranges=[], oneofs=[ ], - serialized_start=505, - serialized_end=538, + serialized_start=743, + serialized_end=776, +) + + +_LISTSESSIONSREQUEST = _descriptor.Descriptor( + name='ListSessionsRequest', + full_name='google.spanner.v1.ListSessionsRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='database', full_name='google.spanner.v1.ListSessionsRequest.database', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='page_size', full_name='google.spanner.v1.ListSessionsRequest.page_size', index=1, + number=2, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='page_token', full_name='google.spanner.v1.ListSessionsRequest.page_token', index=2, + number=3, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='filter', full_name='google.spanner.v1.ListSessionsRequest.filter', index=3, + number=4, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=778, + serialized_end=872, +) + + +_LISTSESSIONSRESPONSE = _descriptor.Descriptor( + name='ListSessionsResponse', + full_name='google.spanner.v1.ListSessionsResponse', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='sessions', full_name='google.spanner.v1.ListSessionsResponse.sessions', index=0, + number=1, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='next_page_token', full_name='google.spanner.v1.ListSessionsResponse.next_page_token', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=874, + serialized_end=967, ) @@ -182,8 +336,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=540, - serialized_end=576, + serialized_start=969, + serialized_end=1005, ) @@ -220,8 +374,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=897, - serialized_end=971, + serialized_start=1326, + serialized_end=1400, ) _EXECUTESQLREQUEST = _descriptor.Descriptor( @@ -293,8 +447,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=579, - serialized_end=1019, + serialized_start=1008, + serialized_end=1448, ) @@ -373,8 +527,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1022, - serialized_end=1241, + serialized_start=1451, + serialized_end=1670, ) @@ -411,8 +565,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1243, - serialized_end=1341, + serialized_start=1672, + serialized_end=1770, ) @@ -466,8 +620,8 @@ name='transaction', full_name='google.spanner.v1.CommitRequest.transaction', index=0, containing_type=None, fields=[]), ], - serialized_start=1344, - serialized_end=1538, + serialized_start=1773, + serialized_end=1967, ) @@ -497,8 +651,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1540, - serialized_end=1610, + serialized_start=1969, + serialized_end=2039, ) @@ -535,10 +689,16 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1612, - serialized_end=1670, + serialized_start=2041, + serialized_end=2099, ) +_CREATESESSIONREQUEST.fields_by_name['session'].message_type = _SESSION +_SESSION_LABELSENTRY.containing_type = _SESSION +_SESSION.fields_by_name['labels'].message_type = _SESSION_LABELSENTRY +_SESSION.fields_by_name['create_time'].message_type = google_dot_protobuf_dot_timestamp__pb2._TIMESTAMP +_SESSION.fields_by_name['approximate_last_use_time'].message_type = google_dot_protobuf_dot_timestamp__pb2._TIMESTAMP +_LISTSESSIONSRESPONSE.fields_by_name['sessions'].message_type = _SESSION _EXECUTESQLREQUEST_PARAMTYPESENTRY.fields_by_name['value'].message_type = google_dot_cloud_dot_spanner__v1_dot_proto_dot_type__pb2._TYPE _EXECUTESQLREQUEST_PARAMTYPESENTRY.containing_type = _EXECUTESQLREQUEST _EXECUTESQLREQUEST.fields_by_name['transaction'].message_type = google_dot_cloud_dot_spanner__v1_dot_proto_dot_transaction__pb2._TRANSACTIONSELECTOR @@ -561,6 +721,8 @@ DESCRIPTOR.message_types_by_name['CreateSessionRequest'] = _CREATESESSIONREQUEST DESCRIPTOR.message_types_by_name['Session'] = _SESSION DESCRIPTOR.message_types_by_name['GetSessionRequest'] = _GETSESSIONREQUEST +DESCRIPTOR.message_types_by_name['ListSessionsRequest'] = _LISTSESSIONSREQUEST +DESCRIPTOR.message_types_by_name['ListSessionsResponse'] = _LISTSESSIONSRESPONSE DESCRIPTOR.message_types_by_name['DeleteSessionRequest'] = _DELETESESSIONREQUEST DESCRIPTOR.message_types_by_name['ExecuteSqlRequest'] = _EXECUTESQLREQUEST DESCRIPTOR.message_types_by_name['ReadRequest'] = _READREQUEST @@ -580,12 +742,21 @@ Attributes: database: Required. The database in which the new session is created. + session: + The session to create. """, # @@protoc_insertion_point(class_scope:google.spanner.v1.CreateSessionRequest) )) _sym_db.RegisterMessage(CreateSessionRequest) Session = _reflection.GeneratedProtocolMessageType('Session', (_message.Message,), dict( + + LabelsEntry = _reflection.GeneratedProtocolMessageType('LabelsEntry', (_message.Message,), dict( + DESCRIPTOR = _SESSION_LABELSENTRY, + __module__ = 'google.cloud.spanner_v1.proto.spanner_pb2' + # @@protoc_insertion_point(class_scope:google.spanner.v1.Session.LabelsEntry) + )) + , DESCRIPTOR = _SESSION, __module__ = 'google.cloud.spanner_v1.proto.spanner_pb2' , @@ -594,11 +765,29 @@ Attributes: name: - Required. The name of the session. + The name of the session. This is always system-assigned; + values provided when creating a session are ignored. + labels: + The labels for the session. - Label keys must be between 1 + and 63 characters long and must conform to the following + regular expression: ``[a-z]([-a-z0-9]*[a-z0-9])?``. - Label + values must be between 0 and 63 characters long and must + conform to the regular expression + ``([a-z]([-a-z0-9]*[a-z0-9])?)?``. - No more than 64 labels + can be associated with a given session. See + https://goo.gl/xmQnxf for more information on and examples of + labels. + create_time: + Output only. The timestamp when the session is created. + approximate_last_use_time: + Output only. The approximate timestamp when the session is + last used. It is typically earlier than the actual last use + time. """, # @@protoc_insertion_point(class_scope:google.spanner.v1.Session) )) _sym_db.RegisterMessage(Session) +_sym_db.RegisterMessage(Session.LabelsEntry) GetSessionRequest = _reflection.GeneratedProtocolMessageType('GetSessionRequest', (_message.Message,), dict( DESCRIPTOR = _GETSESSIONREQUEST, @@ -615,6 +804,56 @@ )) _sym_db.RegisterMessage(GetSessionRequest) +ListSessionsRequest = _reflection.GeneratedProtocolMessageType('ListSessionsRequest', (_message.Message,), dict( + DESCRIPTOR = _LISTSESSIONSREQUEST, + __module__ = 'google.cloud.spanner_v1.proto.spanner_pb2' + , + __doc__ = """The request for [ListSessions][google.spanner.v1.Spanner.ListSessions]. + + + Attributes: + database: + Required. The database in which to list sessions. + page_size: + Number of sessions to be returned in the response. If 0 or + less, defaults to the server's maximum allowed page size. + page_token: + If non-empty, ``page_token`` should contain a [next\_page\_tok + en][google.spanner.v1.ListSessionsResponse.next\_page\_token] + from a previous [ListSessionsResponse][google.spanner.v1.ListS + essionsResponse]. + filter: + An expression for filtering the results of the request. Filter + rules are case insensitive. The fields eligible for filtering + are: - ``labels.key`` where key is the name of a label Some + examples of using filters are: - ``labels.env:*`` --> The + session has the label "env". - ``labels.env:dev`` --> The + session has the label "env" and the value of the label + contains the string "dev". + """, + # @@protoc_insertion_point(class_scope:google.spanner.v1.ListSessionsRequest) + )) +_sym_db.RegisterMessage(ListSessionsRequest) + +ListSessionsResponse = _reflection.GeneratedProtocolMessageType('ListSessionsResponse', (_message.Message,), dict( + DESCRIPTOR = _LISTSESSIONSRESPONSE, + __module__ = 'google.cloud.spanner_v1.proto.spanner_pb2' + , + __doc__ = """The response for [ListSessions][google.spanner.v1.Spanner.ListSessions]. + + + Attributes: + sessions: + The list of requested sessions. + next_page_token: + ``next_page_token`` can be sent in a subsequent + [ListSessions][google.spanner.v1.Spanner.ListSessions] call to + fetch more of the matching sessions. + """, + # @@protoc_insertion_point(class_scope:google.spanner.v1.ListSessionsResponse) + )) +_sym_db.RegisterMessage(ListSessionsResponse) + DeleteSessionRequest = _reflection.GeneratedProtocolMessageType('DeleteSessionRequest', (_message.Message,), dict( DESCRIPTOR = _DELETESESSIONREQUEST, __module__ = 'google.cloud.spanner_v1.proto.spanner_pb2' @@ -842,7 +1081,9 @@ DESCRIPTOR.has_options = True -DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\025com.google.spanner.v1B\014SpannerProtoP\001Z8google.golang.org/genproto/googleapis/spanner/v1;spanner\252\002\027Google.Cloud.Spanner.V1')) +DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\025com.google.spanner.v1B\014SpannerProtoP\001Z8google.golang.org/genproto/googleapis/spanner/v1;spanner\252\002\027Google.Cloud.Spanner.V1\312\002\027Google\\Cloud\\Spanner\\V1')) +_SESSION_LABELSENTRY.has_options = True +_SESSION_LABELSENTRY._options = _descriptor._ParseOptions(descriptor_pb2.MessageOptions(), _b('8\001')) _EXECUTESQLREQUEST_PARAMTYPESENTRY.has_options = True _EXECUTESQLREQUEST_PARAMTYPESENTRY._options = _descriptor._ParseOptions(descriptor_pb2.MessageOptions(), _b('8\001')) try: @@ -878,6 +1119,11 @@ def __init__(self, channel): request_serializer=GetSessionRequest.SerializeToString, response_deserializer=Session.FromString, ) + self.ListSessions = channel.unary_unary( + '/google.spanner.v1.Spanner/ListSessions', + request_serializer=ListSessionsRequest.SerializeToString, + response_deserializer=ListSessionsResponse.FromString, + ) self.DeleteSession = channel.unary_unary( '/google.spanner.v1.Spanner/DeleteSession', request_serializer=DeleteSessionRequest.SerializeToString, @@ -961,6 +1207,13 @@ def GetSession(self, request, context): context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') + def ListSessions(self, request, context): + """Lists all sessions in a given database. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + def DeleteSession(self, request, context): """Ends a session, releasing server resources associated with it. """ @@ -1077,6 +1330,11 @@ def add_SpannerServicer_to_server(servicer, server): request_deserializer=GetSessionRequest.FromString, response_serializer=Session.SerializeToString, ), + 'ListSessions': grpc.unary_unary_rpc_method_handler( + servicer.ListSessions, + request_deserializer=ListSessionsRequest.FromString, + response_serializer=ListSessionsResponse.SerializeToString, + ), 'DeleteSession': grpc.unary_unary_rpc_method_handler( servicer.DeleteSession, request_deserializer=DeleteSessionRequest.FromString, @@ -1162,6 +1420,10 @@ def GetSession(self, request, context): alive. """ context.code(beta_interfaces.StatusCode.UNIMPLEMENTED) + def ListSessions(self, request, context): + """Lists all sessions in a given database. + """ + context.code(beta_interfaces.StatusCode.UNIMPLEMENTED) def DeleteSession(self, request, context): """Ends a session, releasing server resources associated with it. """ @@ -1284,6 +1546,11 @@ def GetSession(self, request, timeout, metadata=None, with_call=False, protocol_ """ raise NotImplementedError() GetSession.future = None + def ListSessions(self, request, timeout, metadata=None, with_call=False, protocol_options=None): + """Lists all sessions in a given database. + """ + raise NotImplementedError() + ListSessions.future = None def DeleteSession(self, request, timeout, metadata=None, with_call=False, protocol_options=None): """Ends a session, releasing server resources associated with it. """ @@ -1385,6 +1652,7 @@ def beta_create_Spanner_server(servicer, pool=None, pool_size=None, default_time ('google.spanner.v1.Spanner', 'ExecuteSql'): ExecuteSqlRequest.FromString, ('google.spanner.v1.Spanner', 'ExecuteStreamingSql'): ExecuteSqlRequest.FromString, ('google.spanner.v1.Spanner', 'GetSession'): GetSessionRequest.FromString, + ('google.spanner.v1.Spanner', 'ListSessions'): ListSessionsRequest.FromString, ('google.spanner.v1.Spanner', 'Read'): ReadRequest.FromString, ('google.spanner.v1.Spanner', 'Rollback'): RollbackRequest.FromString, ('google.spanner.v1.Spanner', 'StreamingRead'): ReadRequest.FromString, @@ -1397,6 +1665,7 @@ def beta_create_Spanner_server(servicer, pool=None, pool_size=None, default_time ('google.spanner.v1.Spanner', 'ExecuteSql'): google_dot_cloud_dot_spanner__v1_dot_proto_dot_result__set__pb2.ResultSet.SerializeToString, ('google.spanner.v1.Spanner', 'ExecuteStreamingSql'): google_dot_cloud_dot_spanner__v1_dot_proto_dot_result__set__pb2.PartialResultSet.SerializeToString, ('google.spanner.v1.Spanner', 'GetSession'): Session.SerializeToString, + ('google.spanner.v1.Spanner', 'ListSessions'): ListSessionsResponse.SerializeToString, ('google.spanner.v1.Spanner', 'Read'): google_dot_cloud_dot_spanner__v1_dot_proto_dot_result__set__pb2.ResultSet.SerializeToString, ('google.spanner.v1.Spanner', 'Rollback'): google_dot_protobuf_dot_empty__pb2.Empty.SerializeToString, ('google.spanner.v1.Spanner', 'StreamingRead'): google_dot_cloud_dot_spanner__v1_dot_proto_dot_result__set__pb2.PartialResultSet.SerializeToString, @@ -1409,6 +1678,7 @@ def beta_create_Spanner_server(servicer, pool=None, pool_size=None, default_time ('google.spanner.v1.Spanner', 'ExecuteSql'): face_utilities.unary_unary_inline(servicer.ExecuteSql), ('google.spanner.v1.Spanner', 'ExecuteStreamingSql'): face_utilities.unary_stream_inline(servicer.ExecuteStreamingSql), ('google.spanner.v1.Spanner', 'GetSession'): face_utilities.unary_unary_inline(servicer.GetSession), + ('google.spanner.v1.Spanner', 'ListSessions'): face_utilities.unary_unary_inline(servicer.ListSessions), ('google.spanner.v1.Spanner', 'Read'): face_utilities.unary_unary_inline(servicer.Read), ('google.spanner.v1.Spanner', 'Rollback'): face_utilities.unary_unary_inline(servicer.Rollback), ('google.spanner.v1.Spanner', 'StreamingRead'): face_utilities.unary_stream_inline(servicer.StreamingRead), @@ -1431,6 +1701,7 @@ def beta_create_Spanner_stub(channel, host=None, metadata_transformer=None, pool ('google.spanner.v1.Spanner', 'ExecuteSql'): ExecuteSqlRequest.SerializeToString, ('google.spanner.v1.Spanner', 'ExecuteStreamingSql'): ExecuteSqlRequest.SerializeToString, ('google.spanner.v1.Spanner', 'GetSession'): GetSessionRequest.SerializeToString, + ('google.spanner.v1.Spanner', 'ListSessions'): ListSessionsRequest.SerializeToString, ('google.spanner.v1.Spanner', 'Read'): ReadRequest.SerializeToString, ('google.spanner.v1.Spanner', 'Rollback'): RollbackRequest.SerializeToString, ('google.spanner.v1.Spanner', 'StreamingRead'): ReadRequest.SerializeToString, @@ -1443,6 +1714,7 @@ def beta_create_Spanner_stub(channel, host=None, metadata_transformer=None, pool ('google.spanner.v1.Spanner', 'ExecuteSql'): google_dot_cloud_dot_spanner__v1_dot_proto_dot_result__set__pb2.ResultSet.FromString, ('google.spanner.v1.Spanner', 'ExecuteStreamingSql'): google_dot_cloud_dot_spanner__v1_dot_proto_dot_result__set__pb2.PartialResultSet.FromString, ('google.spanner.v1.Spanner', 'GetSession'): Session.FromString, + ('google.spanner.v1.Spanner', 'ListSessions'): ListSessionsResponse.FromString, ('google.spanner.v1.Spanner', 'Read'): google_dot_cloud_dot_spanner__v1_dot_proto_dot_result__set__pb2.ResultSet.FromString, ('google.spanner.v1.Spanner', 'Rollback'): google_dot_protobuf_dot_empty__pb2.Empty.FromString, ('google.spanner.v1.Spanner', 'StreamingRead'): google_dot_cloud_dot_spanner__v1_dot_proto_dot_result__set__pb2.PartialResultSet.FromString, @@ -1455,6 +1727,7 @@ def beta_create_Spanner_stub(channel, host=None, metadata_transformer=None, pool 'ExecuteSql': cardinality.Cardinality.UNARY_UNARY, 'ExecuteStreamingSql': cardinality.Cardinality.UNARY_STREAM, 'GetSession': cardinality.Cardinality.UNARY_UNARY, + 'ListSessions': cardinality.Cardinality.UNARY_UNARY, 'Read': cardinality.Cardinality.UNARY_UNARY, 'Rollback': cardinality.Cardinality.UNARY_UNARY, 'StreamingRead': cardinality.Cardinality.UNARY_STREAM, diff --git a/spanner/google/cloud/spanner_v1/proto/spanner_pb2_grpc.py b/spanner/google/cloud/spanner_v1/proto/spanner_pb2_grpc.py index 3eb3cbfc0c9e..6129f3660bb7 100644 --- a/spanner/google/cloud/spanner_v1/proto/spanner_pb2_grpc.py +++ b/spanner/google/cloud/spanner_v1/proto/spanner_pb2_grpc.py @@ -30,6 +30,11 @@ def __init__(self, channel): request_serializer=google_dot_cloud_dot_spanner__v1_dot_proto_dot_spanner__pb2.GetSessionRequest.SerializeToString, response_deserializer=google_dot_cloud_dot_spanner__v1_dot_proto_dot_spanner__pb2.Session.FromString, ) + self.ListSessions = channel.unary_unary( + '/google.spanner.v1.Spanner/ListSessions', + request_serializer=google_dot_cloud_dot_spanner__v1_dot_proto_dot_spanner__pb2.ListSessionsRequest.SerializeToString, + response_deserializer=google_dot_cloud_dot_spanner__v1_dot_proto_dot_spanner__pb2.ListSessionsResponse.FromString, + ) self.DeleteSession = channel.unary_unary( '/google.spanner.v1.Spanner/DeleteSession', request_serializer=google_dot_cloud_dot_spanner__v1_dot_proto_dot_spanner__pb2.DeleteSessionRequest.SerializeToString, @@ -113,6 +118,13 @@ def GetSession(self, request, context): context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') + def ListSessions(self, request, context): + """Lists all sessions in a given database. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + def DeleteSession(self, request, context): """Ends a session, releasing server resources associated with it. """ @@ -229,6 +241,11 @@ def add_SpannerServicer_to_server(servicer, server): request_deserializer=google_dot_cloud_dot_spanner__v1_dot_proto_dot_spanner__pb2.GetSessionRequest.FromString, response_serializer=google_dot_cloud_dot_spanner__v1_dot_proto_dot_spanner__pb2.Session.SerializeToString, ), + 'ListSessions': grpc.unary_unary_rpc_method_handler( + servicer.ListSessions, + request_deserializer=google_dot_cloud_dot_spanner__v1_dot_proto_dot_spanner__pb2.ListSessionsRequest.FromString, + response_serializer=google_dot_cloud_dot_spanner__v1_dot_proto_dot_spanner__pb2.ListSessionsResponse.SerializeToString, + ), 'DeleteSession': grpc.unary_unary_rpc_method_handler( servicer.DeleteSession, request_deserializer=google_dot_cloud_dot_spanner__v1_dot_proto_dot_spanner__pb2.DeleteSessionRequest.FromString, diff --git a/spanner/google/cloud/spanner_v1/proto/transaction_pb2.py b/spanner/google/cloud/spanner_v1/proto/transaction_pb2.py index e82c4e5b5e59..2b82a2444a17 100644 --- a/spanner/google/cloud/spanner_v1/proto/transaction_pb2.py +++ b/spanner/google/cloud/spanner_v1/proto/transaction_pb2.py @@ -22,7 +22,7 @@ name='google/cloud/spanner_v1/proto/transaction.proto', package='google.spanner.v1', syntax='proto3', - serialized_pb=_b('\n/google/cloud/spanner_v1/proto/transaction.proto\x12\x11google.spanner.v1\x1a\x1cgoogle/api/annotations.proto\x1a\x1egoogle/protobuf/duration.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\xe0\x03\n\x12TransactionOptions\x12\x45\n\nread_write\x18\x01 \x01(\x0b\x32/.google.spanner.v1.TransactionOptions.ReadWriteH\x00\x12\x43\n\tread_only\x18\x02 \x01(\x0b\x32..google.spanner.v1.TransactionOptions.ReadOnlyH\x00\x1a\x0b\n\tReadWrite\x1a\xa8\x02\n\x08ReadOnly\x12\x10\n\x06strong\x18\x01 \x01(\x08H\x00\x12\x38\n\x12min_read_timestamp\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.TimestampH\x00\x12\x32\n\rmax_staleness\x18\x03 \x01(\x0b\x32\x19.google.protobuf.DurationH\x00\x12\x34\n\x0eread_timestamp\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.TimestampH\x00\x12\x34\n\x0f\x65xact_staleness\x18\x05 \x01(\x0b\x32\x19.google.protobuf.DurationH\x00\x12\x1d\n\x15return_read_timestamp\x18\x06 \x01(\x08\x42\x11\n\x0ftimestamp_boundB\x06\n\x04mode\"M\n\x0bTransaction\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\x32\n\x0eread_timestamp\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\"\xa4\x01\n\x13TransactionSelector\x12;\n\nsingle_use\x18\x01 \x01(\x0b\x32%.google.spanner.v1.TransactionOptionsH\x00\x12\x0c\n\x02id\x18\x02 \x01(\x0cH\x00\x12\x36\n\x05\x62\x65gin\x18\x03 \x01(\x0b\x32%.google.spanner.v1.TransactionOptionsH\x00\x42\n\n\x08selectorB\x7f\n\x15\x63om.google.spanner.v1B\x10TransactionProtoP\x01Z8google.golang.org/genproto/googleapis/spanner/v1;spanner\xaa\x02\x17Google.Cloud.Spanner.V1b\x06proto3') + serialized_pb=_b('\n/google/cloud/spanner_v1/proto/transaction.proto\x12\x11google.spanner.v1\x1a\x1cgoogle/api/annotations.proto\x1a\x1egoogle/protobuf/duration.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\xe0\x03\n\x12TransactionOptions\x12\x45\n\nread_write\x18\x01 \x01(\x0b\x32/.google.spanner.v1.TransactionOptions.ReadWriteH\x00\x12\x43\n\tread_only\x18\x02 \x01(\x0b\x32..google.spanner.v1.TransactionOptions.ReadOnlyH\x00\x1a\x0b\n\tReadWrite\x1a\xa8\x02\n\x08ReadOnly\x12\x10\n\x06strong\x18\x01 \x01(\x08H\x00\x12\x38\n\x12min_read_timestamp\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.TimestampH\x00\x12\x32\n\rmax_staleness\x18\x03 \x01(\x0b\x32\x19.google.protobuf.DurationH\x00\x12\x34\n\x0eread_timestamp\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.TimestampH\x00\x12\x34\n\x0f\x65xact_staleness\x18\x05 \x01(\x0b\x32\x19.google.protobuf.DurationH\x00\x12\x1d\n\x15return_read_timestamp\x18\x06 \x01(\x08\x42\x11\n\x0ftimestamp_boundB\x06\n\x04mode\"M\n\x0bTransaction\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\x32\n\x0eread_timestamp\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\"\xa4\x01\n\x13TransactionSelector\x12;\n\nsingle_use\x18\x01 \x01(\x0b\x32%.google.spanner.v1.TransactionOptionsH\x00\x12\x0c\n\x02id\x18\x02 \x01(\x0cH\x00\x12\x36\n\x05\x62\x65gin\x18\x03 \x01(\x0b\x32%.google.spanner.v1.TransactionOptionsH\x00\x42\n\n\x08selectorB\x99\x01\n\x15\x63om.google.spanner.v1B\x10TransactionProtoP\x01Z8google.golang.org/genproto/googleapis/spanner/v1;spanner\xaa\x02\x17Google.Cloud.Spanner.V1\xca\x02\x17Google\\Cloud\\Spanner\\V1b\x06proto3') , dependencies=[google_dot_api_dot_annotations__pb2.DESCRIPTOR,google_dot_protobuf_dot_duration__pb2.DESCRIPTOR,google_dot_protobuf_dot_timestamp__pb2.DESCRIPTOR,]) _sym_db.RegisterFileDescriptor(DESCRIPTOR) @@ -298,7 +298,8 @@ DESCRIPTOR = _TRANSACTIONOPTIONS_READWRITE, __module__ = 'google.cloud.spanner_v1.proto.transaction_pb2' , - __doc__ = """Options for read-write transactions. + __doc__ = """Message type to initiate a read-write transaction. Currently this + transaction type has no options. """, # @@protoc_insertion_point(class_scope:google.spanner.v1.TransactionOptions.ReadWrite) )) @@ -308,7 +309,59 @@ DESCRIPTOR = _TRANSACTIONOPTIONS_READONLY, __module__ = 'google.cloud.spanner_v1.proto.transaction_pb2' , - __doc__ = """Options for read-only transactions. + __doc__ = """Message type to initiate a read-only transaction. + + + Attributes: + timestamp_bound: + How to choose the timestamp for the read-only transaction. + strong: + Read at a timestamp where all previously committed + transactions are visible. + min_read_timestamp: + Executes all reads at a timestamp >= ``min_read_timestamp``. + This is useful for requesting fresher data than some previous + read, or data that is fresh enough to observe the effects of + some previously committed transaction whose timestamp is + known. Note that this option can only be used in single-use + transactions. A timestamp in RFC3339 UTC "Zulu" format, + accurate to nanoseconds. Example: + ``"2014-10-02T15:01:23.045123456Z"``. + max_staleness: + Read data at a timestamp >= ``NOW - max_staleness`` seconds. + Guarantees that all writes that have committed more than the + specified number of seconds ago are visible. Because Cloud + Spanner chooses the exact timestamp, this mode works even if + the client's local clock is substantially skewed from Cloud + Spanner commit timestamps. Useful for reading the freshest + data available at a nearby replica, while bounding the + possible staleness if the local replica has fallen behind. + Note that this option can only be used in single-use + transactions. + read_timestamp: + Executes all reads at the given timestamp. Unlike other modes, + reads at a specific timestamp are repeatable; the same read at + the same timestamp always returns the same data. If the + timestamp is in the future, the read will block until the + specified timestamp, modulo the read's deadline. Useful for + large scale consistent reads such as mapreduces, or for + coordinating many reads against a consistent snapshot of the + data. A timestamp in RFC3339 UTC "Zulu" format, accurate to + nanoseconds. Example: ``"2014-10-02T15:01:23.045123456Z"``. + exact_staleness: + Executes all reads at a timestamp that is ``exact_staleness`` + old. The timestamp is chosen soon after the read is started. + Guarantees that all writes that have committed more than the + specified number of seconds ago are visible. Because Cloud + Spanner chooses the exact timestamp, this mode works even if + the client's local clock is substantially skewed from Cloud + Spanner commit timestamps. Useful for reading at nearby + replicas without the distributed timestamp negotiation + overhead of ``max_staleness``. + return_read_timestamp: + If true, the Cloud Spanner-selected read timestamp is included + in the [Transaction][google.spanner.v1.Transaction] message + that describes the transaction. """, # @@protoc_insertion_point(class_scope:google.spanner.v1.TransactionOptions.ReadOnly) )) @@ -316,55 +369,10 @@ DESCRIPTOR = _TRANSACTIONOPTIONS, __module__ = 'google.cloud.spanner_v1.proto.transaction_pb2' , - __doc__ = """See :ref:`spanner-txn` for more information on these. + __doc__ = """ + Attributes: - timestamp_bound: - How to choose the timestamp for the read-only transaction. - strong: - Read at a timestamp where all previously committed - transactions are visible. - min_read_timestamp: - Executes all reads at a timestamp >= ``min_read_timestamp``. - This is useful for requesting fresher data than some previous - read, or data that is fresh enough to observe the effects of - some previously committed transaction whose timestamp is - known. Note that this option can only be used in single-use - transactions. - max_staleness: - Read data at a timestamp >= ``NOW - max_staleness`` seconds. - Guarantees that all writes that have committed more than the - specified number of seconds ago are visible. Because Cloud - Spanner chooses the exact timestamp, this mode works even if - the client's local clock is substantially skewed from Cloud - Spanner commit timestamps. Useful for reading the freshest - data available at a nearby replica, while bounding the - possible staleness if the local replica has fallen behind. - Note that this option can only be used in single-use - transactions. - read_timestamp: - Executes all reads at the given timestamp. Unlike other modes, - reads at a specific timestamp are repeatable; the same read at - the same timestamp always returns the same data. If the - timestamp is in the future, the read will block until the - specified timestamp, modulo the read's deadline. Useful for - large scale consistent reads such as mapreduces, or for - coordinating many reads against a consistent snapshot of the - data. - exact_staleness: - Executes all reads at a timestamp that is ``exact_staleness`` - old. The timestamp is chosen soon after the read is started. - Guarantees that all writes that have committed more than the - specified number of seconds ago are visible. Because Cloud - Spanner chooses the exact timestamp, this mode works even if - the client's local clock is substantially skewed from Cloud - Spanner commit timestamps. Useful for reading at nearby - replicas without the distributed timestamp negotiation - overhead of ``max_staleness``. - return_read_timestamp: - If true, the Cloud Spanner-selected read timestamp is included - in the [Transaction][google.spanner.v1.Transaction] message - that describes the transaction. mode: Required. The type of transaction. read_write: @@ -388,7 +396,7 @@ DESCRIPTOR = _TRANSACTION, __module__ = 'google.cloud.spanner_v1.proto.transaction_pb2' , - __doc__ = """A transaction. + __doc__ = """A transaction. See :ref:`spanner-txn` for more information. Attributes: @@ -404,7 +412,9 @@ For snapshot read-only transactions, the read timestamp chosen for the transaction. Not returned by default: see [Transaction Options.ReadOnly.return\_read\_timestamp][google.spanner.v1.Tr - ansactionOptions.ReadOnly.return\_read\_timestamp]. + ansactionOptions.ReadOnly.return\_read\_timestamp]. A + timestamp in RFC3339 UTC "Zulu" format, accurate to + nanoseconds. Example: ``"2014-10-02T15:01:23.045123456Z"``. """, # @@protoc_insertion_point(class_scope:google.spanner.v1.Transaction) )) @@ -446,7 +456,7 @@ DESCRIPTOR.has_options = True -DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\025com.google.spanner.v1B\020TransactionProtoP\001Z8google.golang.org/genproto/googleapis/spanner/v1;spanner\252\002\027Google.Cloud.Spanner.V1')) +DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\025com.google.spanner.v1B\020TransactionProtoP\001Z8google.golang.org/genproto/googleapis/spanner/v1;spanner\252\002\027Google.Cloud.Spanner.V1\312\002\027Google\\Cloud\\Spanner\\V1')) try: # THESE ELEMENTS WILL BE DEPRECATED. # Please use the generated *_pb2_grpc.py files instead. diff --git a/spanner/google/cloud/spanner_v1/proto/type_pb2.py b/spanner/google/cloud/spanner_v1/proto/type_pb2.py index 8c2bd21f1f4e..40dcdce81a24 100644 --- a/spanner/google/cloud/spanner_v1/proto/type_pb2.py +++ b/spanner/google/cloud/spanner_v1/proto/type_pb2.py @@ -21,7 +21,7 @@ name='google/cloud/spanner_v1/proto/type.proto', package='google.spanner.v1', syntax='proto3', - serialized_pb=_b('\n(google/cloud/spanner_v1/proto/type.proto\x12\x11google.spanner.v1\x1a\x1cgoogle/api/annotations.proto\"\x9a\x01\n\x04Type\x12)\n\x04\x63ode\x18\x01 \x01(\x0e\x32\x1b.google.spanner.v1.TypeCode\x12\x33\n\x12\x61rray_element_type\x18\x02 \x01(\x0b\x32\x17.google.spanner.v1.Type\x12\x32\n\x0bstruct_type\x18\x03 \x01(\x0b\x32\x1d.google.spanner.v1.StructType\"\x7f\n\nStructType\x12\x33\n\x06\x66ields\x18\x01 \x03(\x0b\x32#.google.spanner.v1.StructType.Field\x1a<\n\x05\x46ield\x12\x0c\n\x04name\x18\x01 \x01(\t\x12%\n\x04type\x18\x02 \x01(\x0b\x32\x17.google.spanner.v1.Type*\x8e\x01\n\x08TypeCode\x12\x19\n\x15TYPE_CODE_UNSPECIFIED\x10\x00\x12\x08\n\x04\x42OOL\x10\x01\x12\t\n\x05INT64\x10\x02\x12\x0b\n\x07\x46LOAT64\x10\x03\x12\r\n\tTIMESTAMP\x10\x04\x12\x08\n\x04\x44\x41TE\x10\x05\x12\n\n\x06STRING\x10\x06\x12\t\n\x05\x42YTES\x10\x07\x12\t\n\x05\x41RRAY\x10\x08\x12\n\n\x06STRUCT\x10\tBx\n\x15\x63om.google.spanner.v1B\tTypeProtoP\x01Z8google.golang.org/genproto/googleapis/spanner/v1;spanner\xaa\x02\x17Google.Cloud.Spanner.V1b\x06proto3') + serialized_pb=_b('\n(google/cloud/spanner_v1/proto/type.proto\x12\x11google.spanner.v1\x1a\x1cgoogle/api/annotations.proto\"\x9a\x01\n\x04Type\x12)\n\x04\x63ode\x18\x01 \x01(\x0e\x32\x1b.google.spanner.v1.TypeCode\x12\x33\n\x12\x61rray_element_type\x18\x02 \x01(\x0b\x32\x17.google.spanner.v1.Type\x12\x32\n\x0bstruct_type\x18\x03 \x01(\x0b\x32\x1d.google.spanner.v1.StructType\"\x7f\n\nStructType\x12\x33\n\x06\x66ields\x18\x01 \x03(\x0b\x32#.google.spanner.v1.StructType.Field\x1a<\n\x05\x46ield\x12\x0c\n\x04name\x18\x01 \x01(\t\x12%\n\x04type\x18\x02 \x01(\x0b\x32\x17.google.spanner.v1.Type*\x8e\x01\n\x08TypeCode\x12\x19\n\x15TYPE_CODE_UNSPECIFIED\x10\x00\x12\x08\n\x04\x42OOL\x10\x01\x12\t\n\x05INT64\x10\x02\x12\x0b\n\x07\x46LOAT64\x10\x03\x12\r\n\tTIMESTAMP\x10\x04\x12\x08\n\x04\x44\x41TE\x10\x05\x12\n\n\x06STRING\x10\x06\x12\t\n\x05\x42YTES\x10\x07\x12\t\n\x05\x41RRAY\x10\x08\x12\n\n\x06STRUCT\x10\tB\x92\x01\n\x15\x63om.google.spanner.v1B\tTypeProtoP\x01Z8google.golang.org/genproto/googleapis/spanner/v1;spanner\xaa\x02\x17Google.Cloud.Spanner.V1\xca\x02\x17Google\\Cloud\\Spanner\\V1b\x06proto3') , dependencies=[google_dot_api_dot_annotations__pb2.DESCRIPTOR,]) _sym_db.RegisterFileDescriptor(DESCRIPTOR) @@ -249,6 +249,19 @@ __module__ = 'google.cloud.spanner_v1.proto.type_pb2' , __doc__ = """Message representing a single field of a struct. + + + Attributes: + name: + The name of the field. For reads, this is the column name. For + SQL queries, it is the column alias (e.g., ``"Word"`` in the + query ``"SELECT 'hello' AS Word"``), or the column name (e.g., + ``"ColName"`` in the query ``"SELECT ColName FROM Table"``). + Some columns might have an empty name (e.g., !"SELECT + UPPER(ColName)"\`). Note that a query result can contain + multiple fields with the same name. + type: + The type of the field. """, # @@protoc_insertion_point(class_scope:google.spanner.v1.StructType.Field) )) @@ -261,16 +274,6 @@ Attributes: - name: - The name of the field. For reads, this is the column name. For - SQL queries, it is the column alias (e.g., ``"Word"`` in the - query ``"SELECT 'hello' AS Word"``), or the column name (e.g., - ``"ColName"`` in the query ``"SELECT ColName FROM Table"``). - Some columns might have an empty name (e.g., !"SELECT - UPPER(ColName)"\`). Note that a query result can contain - multiple fields with the same name. - type: - The type of the field. fields: The list of fields that make up this struct. Order is significant, because values of this struct type are @@ -287,7 +290,7 @@ DESCRIPTOR.has_options = True -DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\025com.google.spanner.v1B\tTypeProtoP\001Z8google.golang.org/genproto/googleapis/spanner/v1;spanner\252\002\027Google.Cloud.Spanner.V1')) +DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\025com.google.spanner.v1B\tTypeProtoP\001Z8google.golang.org/genproto/googleapis/spanner/v1;spanner\252\002\027Google.Cloud.Spanner.V1\312\002\027Google\\Cloud\\Spanner\\V1')) try: # THESE ELEMENTS WILL BE DEPRECATED. # Please use the generated *_pb2_grpc.py files instead. diff --git a/spanner/google/cloud/spanner_v1/session.py b/spanner/google/cloud/spanner_v1/session.py index 9eb240b0f7c3..1f7a9dd16b56 100644 --- a/spanner/google/cloud/spanner_v1/session.py +++ b/spanner/google/cloud/spanner_v1/session.py @@ -17,15 +17,11 @@ from functools import total_ordering import time -from google.gax.errors import GaxError -from google.gax.grpc import exc_to_code from google.rpc.error_details_pb2 import RetryInfo -from grpc import StatusCode # pylint: disable=ungrouped-imports -from google.cloud.exceptions import NotFound -from google.cloud.exceptions import GrpcRendezvous -from google.cloud.spanner_v1._helpers import _options_with_prefix +from google.api_core.exceptions import Aborted, GoogleAPICallError, NotFound +from google.cloud.spanner_v1._helpers import _metadata_with_prefix from google.cloud.spanner_v1.batch import Batch from google.cloud.spanner_v1.snapshot import Snapshot from google.cloud.spanner_v1.transaction import Transaction @@ -96,8 +92,8 @@ def create(self): if self._session_id is not None: raise ValueError('Session ID already set by back-end') api = self._database.spanner_api - options = _options_with_prefix(self._database.name) - session_pb = api.create_session(self._database.name, options=options) + metadata = _metadata_with_prefix(self._database.name) + session_pb = api.create_session(self._database.name, metadata=metadata) self._session_id = session_pb.name.split('/')[-1] def exists(self): @@ -108,21 +104,17 @@ def exists(self): :rtype: bool :returns: True if the session exists on the back-end, else False. - :raises GaxError: - for errors other than ``NOT_FOUND`` returned from the call """ if self._session_id is None: return False api = self._database.spanner_api - options = _options_with_prefix(self._database.name) + metadata = _metadata_with_prefix(self._database.name) try: - api.get_session(self.name, options=options) - except GaxError as exc: - if exc_to_code(exc.cause) == StatusCode.NOT_FOUND: - return False - raise - else: - return True + api.get_session(self.name, metadata=metadata) + except NotFound: + return False + + return True def delete(self): """Delete this session. @@ -132,19 +124,13 @@ def delete(self): :raises ValueError: if :attr:`session_id` is not already set. :raises NotFound: if the session does not exist - :raises GaxError: - for errors other than ``NOT_FOUND`` returned from the call """ if self._session_id is None: raise ValueError('Session ID not set by back-end') api = self._database.spanner_api - options = _options_with_prefix(self._database.name) - try: - api.delete_session(self.name, options=options) - except GaxError as exc: - if exc_to_code(exc.cause) == StatusCode.NOT_FOUND: - raise NotFound(self.name) - raise + metadata = _metadata_with_prefix(self._database.name) + + api.delete_session(self.name, metadata=metadata) def snapshot(self, **kw): """Create a snapshot to perform a set of reads with shared staleness. @@ -279,19 +265,25 @@ def run_in_transaction(self, func, *args, **kw): txn.begin() try: return_value = func(txn, *args, **kw) - except (GaxError, GrpcRendezvous) as exc: + except Aborted as exc: del self._transaction _delay_until_retry(exc, deadline) continue + except GoogleAPICallError: + del self._transaction + raise except Exception: txn.rollback() raise try: txn.commit() - except GaxError as exc: + except Aborted as exc: del self._transaction _delay_until_retry(exc, deadline) + except GoogleAPICallError: + del self._transaction + raise else: return return_value @@ -305,19 +297,13 @@ def _delay_until_retry(exc, deadline): Detect retryable abort, and impose server-supplied delay. - :type exc: :class:`google.gax.errors.GaxError` + :type exc: :class:`google.api_core.exceptions.Aborted` :param exc: exception for aborted transaction :type deadline: float :param deadline: maximum timestamp to continue retrying the transaction. """ - if isinstance(exc, GrpcRendezvous): # pragma: NO COVER see #3663 - cause = exc - else: - cause = exc.cause - - if exc_to_code(cause) != StatusCode.ABORTED: - raise + cause = exc.errors[0] now = time.time() @@ -337,7 +323,7 @@ def _delay_until_retry(exc, deadline): def _get_retry_delay(cause): """Helper for :func:`_delay_until_retry`. - :type exc: :class:`google.gax.errors.GaxError` + :type exc: :class:`grpc.Call` :param exc: exception for aborted transaction :rtype: float diff --git a/spanner/google/cloud/spanner_v1/snapshot.py b/spanner/google/cloud/spanner_v1/snapshot.py index 6f67397e501a..3bdf666552c9 100644 --- a/spanner/google/cloud/spanner_v1/snapshot.py +++ b/spanner/google/cloud/spanner_v1/snapshot.py @@ -24,7 +24,7 @@ from google.cloud._helpers import _datetime_to_pb_timestamp from google.cloud._helpers import _timedelta_to_duration_pb from google.cloud.spanner_v1._helpers import _make_value_pb -from google.cloud.spanner_v1._helpers import _options_with_prefix +from google.cloud.spanner_v1._helpers import _metadata_with_prefix from google.cloud.spanner_v1._helpers import _SessionWrapper from google.cloud.spanner_v1.streamed import StreamedResultSet @@ -115,14 +115,14 @@ def read(self, table, columns, keyset, index='', limit=0): database = self._session._database api = database.spanner_api - options = _options_with_prefix(database.name) + metadata = _metadata_with_prefix(database.name) transaction = self._make_txn_selector() restart = functools.partial( api.streaming_read, self._session.name, table, columns, keyset.to_pb(), transaction=transaction, index=index, limit=limit, - options=options) + metadata=metadata) iterator = _restart_on_unavailable(restart) @@ -175,7 +175,7 @@ def execute_sql(self, sql, params=None, param_types=None, query_mode=None): params_pb = None database = self._session._database - options = _options_with_prefix(database.name) + metadata = _metadata_with_prefix(database.name) transaction = self._make_txn_selector() api = database.spanner_api @@ -183,7 +183,7 @@ def execute_sql(self, sql, params=None, param_types=None, query_mode=None): api.execute_streaming_sql, self._session.name, sql, transaction=transaction, params=params_pb, param_types=param_types, - query_mode=query_mode, options=options) + query_mode=query_mode, metadata=metadata) iterator = _restart_on_unavailable(restart) @@ -300,9 +300,9 @@ def begin(self): database = self._session._database api = database.spanner_api - options = _options_with_prefix(database.name) + metadata = _metadata_with_prefix(database.name) txn_selector = self._make_txn_selector() response = api.begin_transaction( - self._session.name, txn_selector.begin, options=options) + self._session.name, txn_selector.begin, metadata=metadata) self._transaction_id = response.id return self._transaction_id diff --git a/spanner/google/cloud/spanner_v1/transaction.py b/spanner/google/cloud/spanner_v1/transaction.py index e95e3b21aa42..9f2f6d99895e 100644 --- a/spanner/google/cloud/spanner_v1/transaction.py +++ b/spanner/google/cloud/spanner_v1/transaction.py @@ -18,7 +18,7 @@ from google.cloud.spanner_v1.proto.transaction_pb2 import TransactionOptions from google.cloud._helpers import _pb_timestamp_to_datetime -from google.cloud.spanner_v1._helpers import _options_with_prefix +from google.cloud.spanner_v1._helpers import _metadata_with_prefix from google.cloud.spanner_v1.snapshot import _SnapshotBase from google.cloud.spanner_v1.batch import _BatchBase @@ -86,11 +86,11 @@ def begin(self): database = self._session._database api = database.spanner_api - options = _options_with_prefix(database.name) + metadata = _metadata_with_prefix(database.name) txn_options = TransactionOptions( read_write=TransactionOptions.ReadWrite()) response = api.begin_transaction( - self._session.name, txn_options, options=options) + self._session.name, txn_options, metadata=metadata) self._transaction_id = response.id return self._transaction_id @@ -99,8 +99,9 @@ def rollback(self): self._check_state() database = self._session._database api = database.spanner_api - options = _options_with_prefix(database.name) - api.rollback(self._session.name, self._transaction_id, options=options) + metadata = _metadata_with_prefix(database.name) + api.rollback( + self._session.name, self._transaction_id, metadata=metadata) self._rolled_back = True del self._session._transaction @@ -118,10 +119,10 @@ def commit(self): database = self._session._database api = database.spanner_api - options = _options_with_prefix(database.name) + metadata = _metadata_with_prefix(database.name) response = api.commit( self._session.name, self._mutations, - transaction_id=self._transaction_id, options=options) + transaction_id=self._transaction_id, metadata=metadata) self.committed = _pb_timestamp_to_datetime( response.commit_timestamp) del self._session._transaction diff --git a/spanner/google/cloud/spanner_v1/types.py b/spanner/google/cloud/spanner_v1/types.py index 090baacfd0d6..8eca4c62370b 100644 --- a/spanner/google/cloud/spanner_v1/types.py +++ b/spanner/google/cloud/spanner_v1/types.py @@ -1,10 +1,10 @@ -# Copyright 2017, Google LLC All rights reserved. +# Copyright 2017 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 +# https://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, @@ -15,9 +15,8 @@ from __future__ import absolute_import import sys -from google.gax.utils.messages import get_messages +from google.api_core.protobuf_helpers import get_messages -from google.api import auth_pb2 from google.api import http_pb2 from google.cloud.spanner_v1.proto import keys_pb2 from google.cloud.spanner_v1.proto import mutation_pb2 @@ -34,7 +33,6 @@ names = [] for module in ( - auth_pb2, http_pb2, keys_pb2, mutation_pb2, @@ -47,7 +45,8 @@ duration_pb2, empty_pb2, struct_pb2, - timestamp_pb2, ): + timestamp_pb2, +): for name, message in get_messages(module).items(): message.__module__ = 'google.cloud.spanner_v1.types' setattr(sys.modules[__name__], name, message) diff --git a/spanner/setup.py b/spanner/setup.py index 4a4543117c51..f4b0b55f8149 100644 --- a/spanner/setup.py +++ b/spanner/setup.py @@ -54,7 +54,6 @@ 'google-auth >= 1.1.0', 'google-cloud-core[grpc] >= 0.28.0, < 0.29dev', 'google-api-core >= 0.1.1, < 0.2.0dev', - 'google-gax >= 0.15.15, < 0.16dev', 'grpc-google-iam-v1 >= 0.11.4, < 0.12dev', 'requests >= 2.18.4, < 3.0dev', ] diff --git a/spanner/tests/system/test_system.py b/spanner/tests/system/test_system.py index 9cf539dde1c7..54ed42b6e3a4 100644 --- a/spanner/tests/system/test_system.py +++ b/spanner/tests/system/test_system.py @@ -21,6 +21,7 @@ import time import unittest +from google.api_core import exceptions from google.cloud.spanner_v1.proto.type_pb2 import ARRAY from google.cloud.spanner_v1.proto.type_pb2 import BOOL from google.cloud.spanner_v1.proto.type_pb2 import BYTES @@ -30,13 +31,8 @@ from google.cloud.spanner_v1.proto.type_pb2 import STRING from google.cloud.spanner_v1.proto.type_pb2 import TIMESTAMP from google.cloud.spanner_v1.proto.type_pb2 import Type -from google.gax.grpc import exc_to_code -from google.gax import errors -from grpc import StatusCode from google.cloud._helpers import UTC -from google.cloud.exceptions import GrpcRendezvous -from google.cloud.exceptions import NotFound from google.cloud.spanner_v1._helpers import TimestampWithNanoseconds from google.cloud.spanner import Client from google.cloud.spanner import KeyRange @@ -74,11 +70,6 @@ class Config(object): INSTANCE = None -def _retry_on_unavailable(exc): - """Retry only errors whose status code is 'UNAVAILABLE'.""" - return exc.code() == StatusCode.UNAVAILABLE - - def _has_all_ddl(database): return len(database.ddl_statements) == len(DDL_STATEMENTS) @@ -89,7 +80,7 @@ def _list_instances(): def setUpModule(): Config.CLIENT = Client() - retry = RetryErrors(GrpcRendezvous, error_predicate=_retry_on_unavailable) + retry = RetryErrors(exceptions.ServiceUnavailable) configs = list(retry(Config.CLIENT.list_instance_configs)()) @@ -305,7 +296,7 @@ def test_table_not_found(self): ], ) self.to_delete.append(temp_db) - with self.assertRaises(NotFound) as exc_info: + with self.assertRaises(exceptions.NotFound) as exc_info: temp_db.create() expected = 'Table not found: {0}'.format(incorrect_table) @@ -393,12 +384,9 @@ def _unit_of_work(transaction, name): self._db.run_in_transaction(_unit_of_work, name='id_1') - with self.assertRaises(errors.RetryError) as expected: + with self.assertRaises(exceptions.AlreadyExists): self._db.run_in_transaction(_unit_of_work, name='id_1') - self.assertEqual( - exc_to_code(expected.exception.cause), StatusCode.ALREADY_EXISTS) - self._db.run_in_transaction(_unit_of_work, name='id_2') with self._db.snapshot() as after: @@ -541,7 +529,7 @@ def test_batch_insert_or_update_then_query(self): rows = list(snapshot.execute_sql(self.SQL)) self._check_rows_data(rows) - @RetryErrors(exception=GrpcRendezvous) + @RetryErrors(exception=exceptions.ServerError) def test_transaction_read_and_insert_then_rollback(self): retry = RetryInstanceState(_has_all_ddl) retry(self._db.reload)() @@ -575,7 +563,7 @@ def _transaction_read_then_raise(self, transaction): transaction.insert(self.TABLE, self.COLUMNS, self.ROW_DATA) raise CustomException() - @RetryErrors(exception=GrpcRendezvous) + @RetryErrors(exception=exceptions.ServerError) def test_transaction_read_and_insert_then_exception(self): retry = RetryInstanceState(_has_all_ddl) retry(self._db.reload)() @@ -594,7 +582,7 @@ def test_transaction_read_and_insert_then_exception(self): rows = list(session.read(self.TABLE, self.COLUMNS, self.ALL)) self.assertEqual(rows, []) - @RetryErrors(exception=GrpcRendezvous) + @RetryErrors(exception=exceptions.ServerError) def test_transaction_read_and_insert_or_update_then_commit(self): retry = RetryInstanceState(_has_all_ddl) retry(self._db.reload)() @@ -1331,17 +1319,15 @@ def test_invalid_type(self): batch.insert(table, columns, valid_input) invalid_input = ((0, ''),) - with self.assertRaises(errors.RetryError) as exc_info: + with self.assertRaises(exceptions.FailedPrecondition) as exc_info: with session.batch() as batch: batch.delete(table, self.ALL) batch.insert(table, columns, invalid_input) - cause = exc_info.exception.cause - self.assertEqual(cause.code(), StatusCode.FAILED_PRECONDITION) error_msg = ( 'Invalid value for column value in table ' 'counters: Expected INT64.') - self.assertEqual(cause.details(), error_msg) + self.assertIn(error_msg, str(exc_info.exception)) def test_execute_sql_w_query_param(self): session = self._db.session() diff --git a/spanner/tests/unit/gapic/v1/test_database_admin_client_v1.py b/spanner/tests/unit/gapic/v1/test_database_admin_client_v1.py index 3c1a8efb1637..3de37e8cbd20 100644 --- a/spanner/tests/unit/gapic/v1/test_database_admin_client_v1.py +++ b/spanner/tests/unit/gapic/v1/test_database_admin_client_v1.py @@ -1,10 +1,10 @@ -# Copyright 2017, Google LLC All rights reserved. +# Copyright 2017 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 +# https://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, @@ -13,10 +13,8 @@ # limitations under the License. """Unit tests.""" -import mock -import unittest +import pytest -from google.gax import errors from google.rpc import status_pb2 from google.cloud import spanner_admin_database_v1 @@ -27,23 +25,48 @@ from google.protobuf import empty_pb2 -class CustomException(Exception): - pass +class MultiCallableStub(object): + """Stub for the grpc.UnaryUnaryMultiCallable interface.""" + def __init__(self, method, channel_stub): + self.method = method + self.channel_stub = channel_stub -class TestDatabaseAdminClient(unittest.TestCase): - @mock.patch('google.gax.config.create_stub', spec=True) - def test_list_databases(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub + def __call__(self, request, timeout=None, metadata=None, credentials=None): + self.channel_stub.requests.append((self.method, request)) - client = spanner_admin_database_v1.DatabaseAdminClient() + response = None + if self.channel_stub.responses: + response = self.channel_stub.responses.pop() - # Mock request - parent = client.instance_path('[PROJECT]', '[INSTANCE]') + if isinstance(response, Exception): + raise response + + if response: + return response + + +class ChannelStub(object): + """Stub for the grpc.Channel interface.""" + + def __init__(self, responses=[]): + self.responses = responses + self.requests = [] + + def unary_unary(self, + method, + request_serializer=None, + response_deserializer=None): + return MultiCallableStub(method, self) - # Mock response + +class CustomException(Exception): + pass + + +class TestDatabaseAdminClient(object): + def test_list_databases(self): + # Setup Expected Response next_page_token = '' databases_element = {} databases = [databases_element] @@ -53,55 +76,39 @@ def test_list_databases(self, mock_create_stub): } expected_response = spanner_database_admin_pb2.ListDatabasesResponse( **expected_response) - grpc_stub.ListDatabases.return_value = expected_response + + # Mock the API response + channel = ChannelStub(responses=[expected_response]) + client = spanner_admin_database_v1.DatabaseAdminClient(channel=channel) + + # Setup Request + parent = client.instance_path('[PROJECT]', '[INSTANCE]') paged_list_response = client.list_databases(parent) resources = list(paged_list_response) - self.assertEqual(1, len(resources)) - self.assertEqual(expected_response.databases[0], resources[0]) + assert len(resources) == 1 - grpc_stub.ListDatabases.assert_called_once() - args, kwargs = grpc_stub.ListDatabases.call_args - self.assertEqual(len(args), 2) - self.assertEqual(len(kwargs), 1) - self.assertIn('metadata', kwargs) - actual_request = args[0] + assert expected_response.databases[0] == resources[0] + assert len(channel.requests) == 1 expected_request = spanner_database_admin_pb2.ListDatabasesRequest( parent=parent) - self.assertEqual(expected_request, actual_request) - - @mock.patch('google.gax.config.API_ERRORS', (CustomException, )) - @mock.patch('google.gax.config.create_stub', spec=True) - def test_list_databases_exception(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub + actual_request = channel.requests[0][1] + assert expected_request == actual_request - client = spanner_admin_database_v1.DatabaseAdminClient() + def test_list_databases_exception(self): + channel = ChannelStub(responses=[CustomException()]) + client = spanner_admin_database_v1.DatabaseAdminClient(channel=channel) - # Mock request + # Setup request parent = client.instance_path('[PROJECT]', '[INSTANCE]') - # Mock exception response - grpc_stub.ListDatabases.side_effect = CustomException() - paged_list_response = client.list_databases(parent) - self.assertRaises(errors.GaxError, list, paged_list_response) - - @mock.patch('google.gax.config.create_stub', spec=True) - def test_create_database(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub - - client = spanner_admin_database_v1.DatabaseAdminClient() - - # Mock request - parent = client.instance_path('[PROJECT]', '[INSTANCE]') - create_statement = 'createStatement552974828' + with pytest.raises(CustomException): + list(paged_list_response) - # Mock response + def test_create_database(self): + # Setup Expected Response name = 'name3373707' expected_response = {'name': name} expected_response = spanner_database_admin_pb2.Database( @@ -109,398 +116,295 @@ def test_create_database(self, mock_create_stub): operation = operations_pb2.Operation( name='operations/test_create_database', done=True) operation.response.Pack(expected_response) - grpc_stub.CreateDatabase.return_value = operation - response = client.create_database(parent, create_statement) - self.assertEqual(expected_response, response.result()) + # Mock the API response + channel = ChannelStub(responses=[operation]) + client = spanner_admin_database_v1.DatabaseAdminClient(channel=channel) - grpc_stub.CreateDatabase.assert_called_once() - args, kwargs = grpc_stub.CreateDatabase.call_args - self.assertEqual(len(args), 2) - self.assertEqual(len(kwargs), 1) - self.assertIn('metadata', kwargs) - actual_request = args[0] + # Setup Request + parent = client.instance_path('[PROJECT]', '[INSTANCE]') + create_statement = 'createStatement552974828' + response = client.create_database(parent, create_statement) + result = response.result() + assert expected_response == result + + assert len(channel.requests) == 1 expected_request = spanner_database_admin_pb2.CreateDatabaseRequest( parent=parent, create_statement=create_statement) - self.assertEqual(expected_request, actual_request) - - @mock.patch('google.gax.config.create_stub', spec=True) - def test_create_database_exception(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub + actual_request = channel.requests[0][1] + assert expected_request == actual_request - client = spanner_admin_database_v1.DatabaseAdminClient() - - # Mock request - parent = client.instance_path('[PROJECT]', '[INSTANCE]') - create_statement = 'createStatement552974828' - - # Mock exception response + def test_create_database_exception(self): + # Setup Response error = status_pb2.Status() operation = operations_pb2.Operation( name='operations/test_create_database_exception', done=True) operation.error.CopyFrom(error) - grpc_stub.CreateDatabase.return_value = operation - response = client.create_database(parent, create_statement) - self.assertEqual(error, response.exception()) - - @mock.patch('google.gax.config.create_stub', spec=True) - def test_get_database(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub + # Mock the API response + channel = ChannelStub(responses=[operation]) + client = spanner_admin_database_v1.DatabaseAdminClient(channel=channel) - client = spanner_admin_database_v1.DatabaseAdminClient() + # Setup Request + parent = client.instance_path('[PROJECT]', '[INSTANCE]') + create_statement = 'createStatement552974828' - # Mock request - name = client.database_path('[PROJECT]', '[INSTANCE]', '[DATABASE]') + response = client.create_database(parent, create_statement) + exception = response.exception() + assert exception.errors[0] == error - # Mock response + def test_get_database(self): + # Setup Expected Response name_2 = 'name2-1052831874' expected_response = {'name': name_2} expected_response = spanner_database_admin_pb2.Database( **expected_response) - grpc_stub.GetDatabase.return_value = expected_response - response = client.get_database(name) - self.assertEqual(expected_response, response) + # Mock the API response + channel = ChannelStub(responses=[expected_response]) + client = spanner_admin_database_v1.DatabaseAdminClient(channel=channel) - grpc_stub.GetDatabase.assert_called_once() - args, kwargs = grpc_stub.GetDatabase.call_args - self.assertEqual(len(args), 2) - self.assertEqual(len(kwargs), 1) - self.assertIn('metadata', kwargs) - actual_request = args[0] + # Setup Request + name = client.database_path('[PROJECT]', '[INSTANCE]', '[DATABASE]') + + response = client.get_database(name) + assert expected_response == response + assert len(channel.requests) == 1 expected_request = spanner_database_admin_pb2.GetDatabaseRequest( name=name) - self.assertEqual(expected_request, actual_request) + actual_request = channel.requests[0][1] + assert expected_request == actual_request - @mock.patch('google.gax.config.API_ERRORS', (CustomException, )) - @mock.patch('google.gax.config.create_stub', spec=True) - def test_get_database_exception(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub + def test_get_database_exception(self): + # Mock the API response + channel = ChannelStub(responses=[CustomException()]) + client = spanner_admin_database_v1.DatabaseAdminClient(channel=channel) - client = spanner_admin_database_v1.DatabaseAdminClient() - - # Mock request + # Setup request name = client.database_path('[PROJECT]', '[INSTANCE]', '[DATABASE]') - # Mock exception response - grpc_stub.GetDatabase.side_effect = CustomException() - - self.assertRaises(errors.GaxError, client.get_database, name) - - @mock.patch('google.gax.config.create_stub', spec=True) - def test_update_database_ddl(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub - - client = spanner_admin_database_v1.DatabaseAdminClient() - - # Mock request - database = client.database_path('[PROJECT]', '[INSTANCE]', - '[DATABASE]') - statements = [] + with pytest.raises(CustomException): + client.get_database(name) - # Mock response + def test_update_database_ddl(self): + # Setup Expected Response expected_response = {} expected_response = empty_pb2.Empty(**expected_response) operation = operations_pb2.Operation( name='operations/test_update_database_ddl', done=True) operation.response.Pack(expected_response) - grpc_stub.UpdateDatabaseDdl.return_value = operation - response = client.update_database_ddl(database, statements) - self.assertEqual(expected_response, response.result()) + # Mock the API response + channel = ChannelStub(responses=[operation]) + client = spanner_admin_database_v1.DatabaseAdminClient(channel=channel) - grpc_stub.UpdateDatabaseDdl.assert_called_once() - args, kwargs = grpc_stub.UpdateDatabaseDdl.call_args - self.assertEqual(len(args), 2) - self.assertEqual(len(kwargs), 1) - self.assertIn('metadata', kwargs) - actual_request = args[0] + # Setup Request + database = client.database_path('[PROJECT]', '[INSTANCE]', + '[DATABASE]') + statements = [] + + response = client.update_database_ddl(database, statements) + result = response.result() + assert expected_response == result + assert len(channel.requests) == 1 expected_request = spanner_database_admin_pb2.UpdateDatabaseDdlRequest( database=database, statements=statements) - self.assertEqual(expected_request, actual_request) + actual_request = channel.requests[0][1] + assert expected_request == actual_request - @mock.patch('google.gax.config.create_stub', spec=True) - def test_update_database_ddl_exception(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub + def test_update_database_ddl_exception(self): + # Setup Response + error = status_pb2.Status() + operation = operations_pb2.Operation( + name='operations/test_update_database_ddl_exception', done=True) + operation.error.CopyFrom(error) - client = spanner_admin_database_v1.DatabaseAdminClient() + # Mock the API response + channel = ChannelStub(responses=[operation]) + client = spanner_admin_database_v1.DatabaseAdminClient(channel=channel) - # Mock request + # Setup Request database = client.database_path('[PROJECT]', '[INSTANCE]', '[DATABASE]') statements = [] - # Mock exception response - error = status_pb2.Status() - operation = operations_pb2.Operation( - name='operations/test_update_database_ddl_exception', done=True) - operation.error.CopyFrom(error) - grpc_stub.UpdateDatabaseDdl.return_value = operation - response = client.update_database_ddl(database, statements) - self.assertEqual(error, response.exception()) - - @mock.patch('google.gax.config.create_stub', spec=True) - def test_drop_database(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub + exception = response.exception() + assert exception.errors[0] == error - client = spanner_admin_database_v1.DatabaseAdminClient() + def test_drop_database(self): + channel = ChannelStub() + client = spanner_admin_database_v1.DatabaseAdminClient(channel=channel) - # Mock request + # Setup Request database = client.database_path('[PROJECT]', '[INSTANCE]', '[DATABASE]') client.drop_database(database) - grpc_stub.DropDatabase.assert_called_once() - args, kwargs = grpc_stub.DropDatabase.call_args - self.assertEqual(len(args), 2) - self.assertEqual(len(kwargs), 1) - self.assertIn('metadata', kwargs) - actual_request = args[0] - + assert len(channel.requests) == 1 expected_request = spanner_database_admin_pb2.DropDatabaseRequest( database=database) - self.assertEqual(expected_request, actual_request) - - @mock.patch('google.gax.config.API_ERRORS', (CustomException, )) - @mock.patch('google.gax.config.create_stub', spec=True) - def test_drop_database_exception(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub + actual_request = channel.requests[0][1] + assert expected_request == actual_request - client = spanner_admin_database_v1.DatabaseAdminClient() + def test_drop_database_exception(self): + # Mock the API response + channel = ChannelStub(responses=[CustomException()]) + client = spanner_admin_database_v1.DatabaseAdminClient(channel=channel) - # Mock request + # Setup request database = client.database_path('[PROJECT]', '[INSTANCE]', '[DATABASE]') - # Mock exception response - grpc_stub.DropDatabase.side_effect = CustomException() + with pytest.raises(CustomException): + client.drop_database(database) - self.assertRaises(errors.GaxError, client.drop_database, database) - - @mock.patch('google.gax.config.create_stub', spec=True) - def test_get_database_ddl(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub + def test_get_database_ddl(self): + # Setup Expected Response + expected_response = {} + expected_response = spanner_database_admin_pb2.GetDatabaseDdlResponse( + **expected_response) - client = spanner_admin_database_v1.DatabaseAdminClient() + # Mock the API response + channel = ChannelStub(responses=[expected_response]) + client = spanner_admin_database_v1.DatabaseAdminClient(channel=channel) - # Mock request + # Setup Request database = client.database_path('[PROJECT]', '[INSTANCE]', '[DATABASE]') - # Mock response - expected_response = {} - expected_response = spanner_database_admin_pb2.GetDatabaseDdlResponse( - **expected_response) - grpc_stub.GetDatabaseDdl.return_value = expected_response - response = client.get_database_ddl(database) - self.assertEqual(expected_response, response) - - grpc_stub.GetDatabaseDdl.assert_called_once() - args, kwargs = grpc_stub.GetDatabaseDdl.call_args - self.assertEqual(len(args), 2) - self.assertEqual(len(kwargs), 1) - self.assertIn('metadata', kwargs) - actual_request = args[0] + assert expected_response == response + assert len(channel.requests) == 1 expected_request = spanner_database_admin_pb2.GetDatabaseDdlRequest( database=database) - self.assertEqual(expected_request, actual_request) - - @mock.patch('google.gax.config.API_ERRORS', (CustomException, )) - @mock.patch('google.gax.config.create_stub', spec=True) - def test_get_database_ddl_exception(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub + actual_request = channel.requests[0][1] + assert expected_request == actual_request - client = spanner_admin_database_v1.DatabaseAdminClient() + def test_get_database_ddl_exception(self): + # Mock the API response + channel = ChannelStub(responses=[CustomException()]) + client = spanner_admin_database_v1.DatabaseAdminClient(channel=channel) - # Mock request + # Setup request database = client.database_path('[PROJECT]', '[INSTANCE]', '[DATABASE]') - # Mock exception response - grpc_stub.GetDatabaseDdl.side_effect = CustomException() + with pytest.raises(CustomException): + client.get_database_ddl(database) - self.assertRaises(errors.GaxError, client.get_database_ddl, database) - - @mock.patch('google.gax.config.create_stub', spec=True) - def test_set_iam_policy(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub + def test_set_iam_policy(self): + # Setup Expected Response + version = 351608024 + etag = b'21' + expected_response = {'version': version, 'etag': etag} + expected_response = policy_pb2.Policy(**expected_response) - client = spanner_admin_database_v1.DatabaseAdminClient() + # Mock the API response + channel = ChannelStub(responses=[expected_response]) + client = spanner_admin_database_v1.DatabaseAdminClient(channel=channel) - # Mock request + # Setup Request resource = client.database_path('[PROJECT]', '[INSTANCE]', '[DATABASE]') policy = {} - # Mock response - version = 351608024 - etag = b'21' - expected_response = {'version': version, 'etag': etag} - expected_response = policy_pb2.Policy(**expected_response) - grpc_stub.SetIamPolicy.return_value = expected_response - response = client.set_iam_policy(resource, policy) - self.assertEqual(expected_response, response) - - grpc_stub.SetIamPolicy.assert_called_once() - args, kwargs = grpc_stub.SetIamPolicy.call_args - self.assertEqual(len(args), 2) - self.assertEqual(len(kwargs), 1) - self.assertIn('metadata', kwargs) - actual_request = args[0] + assert expected_response == response + assert len(channel.requests) == 1 expected_request = iam_policy_pb2.SetIamPolicyRequest( resource=resource, policy=policy) - self.assertEqual(expected_request, actual_request) + actual_request = channel.requests[0][1] + assert expected_request == actual_request - @mock.patch('google.gax.config.API_ERRORS', (CustomException, )) - @mock.patch('google.gax.config.create_stub', spec=True) - def test_set_iam_policy_exception(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub + def test_set_iam_policy_exception(self): + # Mock the API response + channel = ChannelStub(responses=[CustomException()]) + client = spanner_admin_database_v1.DatabaseAdminClient(channel=channel) - client = spanner_admin_database_v1.DatabaseAdminClient() - - # Mock request + # Setup request resource = client.database_path('[PROJECT]', '[INSTANCE]', '[DATABASE]') policy = {} - # Mock exception response - grpc_stub.SetIamPolicy.side_effect = CustomException() - - self.assertRaises(errors.GaxError, client.set_iam_policy, resource, - policy) - - @mock.patch('google.gax.config.create_stub', spec=True) - def test_get_iam_policy(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub + with pytest.raises(CustomException): + client.set_iam_policy(resource, policy) - client = spanner_admin_database_v1.DatabaseAdminClient() - - # Mock request - resource = client.database_path('[PROJECT]', '[INSTANCE]', - '[DATABASE]') - - # Mock response + def test_get_iam_policy(self): + # Setup Expected Response version = 351608024 etag = b'21' expected_response = {'version': version, 'etag': etag} expected_response = policy_pb2.Policy(**expected_response) - grpc_stub.GetIamPolicy.return_value = expected_response - response = client.get_iam_policy(resource) - self.assertEqual(expected_response, response) + # Mock the API response + channel = ChannelStub(responses=[expected_response]) + client = spanner_admin_database_v1.DatabaseAdminClient(channel=channel) + + # Setup Request + resource = client.database_path('[PROJECT]', '[INSTANCE]', + '[DATABASE]') - grpc_stub.GetIamPolicy.assert_called_once() - args, kwargs = grpc_stub.GetIamPolicy.call_args - self.assertEqual(len(args), 2) - self.assertEqual(len(kwargs), 1) - self.assertIn('metadata', kwargs) - actual_request = args[0] + response = client.get_iam_policy(resource) + assert expected_response == response + assert len(channel.requests) == 1 expected_request = iam_policy_pb2.GetIamPolicyRequest( resource=resource) - self.assertEqual(expected_request, actual_request) + actual_request = channel.requests[0][1] + assert expected_request == actual_request - @mock.patch('google.gax.config.API_ERRORS', (CustomException, )) - @mock.patch('google.gax.config.create_stub', spec=True) - def test_get_iam_policy_exception(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub + def test_get_iam_policy_exception(self): + # Mock the API response + channel = ChannelStub(responses=[CustomException()]) + client = spanner_admin_database_v1.DatabaseAdminClient(channel=channel) - client = spanner_admin_database_v1.DatabaseAdminClient() - - # Mock request + # Setup request resource = client.database_path('[PROJECT]', '[INSTANCE]', '[DATABASE]') - # Mock exception response - grpc_stub.GetIamPolicy.side_effect = CustomException() - - self.assertRaises(errors.GaxError, client.get_iam_policy, resource) + with pytest.raises(CustomException): + client.get_iam_policy(resource) - @mock.patch('google.gax.config.create_stub', spec=True) - def test_test_iam_permissions(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub + def test_test_iam_permissions(self): + # Setup Expected Response + expected_response = {} + expected_response = iam_policy_pb2.TestIamPermissionsResponse( + **expected_response) - client = spanner_admin_database_v1.DatabaseAdminClient() + # Mock the API response + channel = ChannelStub(responses=[expected_response]) + client = spanner_admin_database_v1.DatabaseAdminClient(channel=channel) - # Mock request + # Setup Request resource = client.database_path('[PROJECT]', '[INSTANCE]', '[DATABASE]') permissions = [] - # Mock response - expected_response = {} - expected_response = iam_policy_pb2.TestIamPermissionsResponse( - **expected_response) - grpc_stub.TestIamPermissions.return_value = expected_response - response = client.test_iam_permissions(resource, permissions) - self.assertEqual(expected_response, response) - - grpc_stub.TestIamPermissions.assert_called_once() - args, kwargs = grpc_stub.TestIamPermissions.call_args - self.assertEqual(len(args), 2) - self.assertEqual(len(kwargs), 1) - self.assertIn('metadata', kwargs) - actual_request = args[0] + assert expected_response == response + assert len(channel.requests) == 1 expected_request = iam_policy_pb2.TestIamPermissionsRequest( resource=resource, permissions=permissions) - self.assertEqual(expected_request, actual_request) - - @mock.patch('google.gax.config.API_ERRORS', (CustomException, )) - @mock.patch('google.gax.config.create_stub', spec=True) - def test_test_iam_permissions_exception(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub + actual_request = channel.requests[0][1] + assert expected_request == actual_request - client = spanner_admin_database_v1.DatabaseAdminClient() + def test_test_iam_permissions_exception(self): + # Mock the API response + channel = ChannelStub(responses=[CustomException()]) + client = spanner_admin_database_v1.DatabaseAdminClient(channel=channel) - # Mock request + # Setup request resource = client.database_path('[PROJECT]', '[INSTANCE]', '[DATABASE]') permissions = [] - # Mock exception response - grpc_stub.TestIamPermissions.side_effect = CustomException() - - self.assertRaises(errors.GaxError, client.test_iam_permissions, - resource, permissions) + with pytest.raises(CustomException): + client.test_iam_permissions(resource, permissions) diff --git a/spanner/tests/unit/gapic/v1/test_instance_admin_client_v1.py b/spanner/tests/unit/gapic/v1/test_instance_admin_client_v1.py index 2d20019bbb55..b4d60420dc6f 100644 --- a/spanner/tests/unit/gapic/v1/test_instance_admin_client_v1.py +++ b/spanner/tests/unit/gapic/v1/test_instance_admin_client_v1.py @@ -1,10 +1,10 @@ -# Copyright 2017, Google LLC All rights reserved. +# Copyright 2017 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 +# https://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, @@ -13,10 +13,8 @@ # limitations under the License. """Unit tests.""" -import mock -import unittest +import pytest -from google.gax import errors from google.rpc import status_pb2 from google.cloud import spanner_admin_instance_v1 @@ -28,23 +26,48 @@ from google.protobuf import field_mask_pb2 -class CustomException(Exception): - pass +class MultiCallableStub(object): + """Stub for the grpc.UnaryUnaryMultiCallable interface.""" + def __init__(self, method, channel_stub): + self.method = method + self.channel_stub = channel_stub -class TestInstanceAdminClient(unittest.TestCase): - @mock.patch('google.gax.config.create_stub', spec=True) - def test_list_instance_configs(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub + def __call__(self, request, timeout=None, metadata=None, credentials=None): + self.channel_stub.requests.append((self.method, request)) - client = spanner_admin_instance_v1.InstanceAdminClient() + response = None + if self.channel_stub.responses: + response = self.channel_stub.responses.pop() - # Mock request - parent = client.project_path('[PROJECT]') + if isinstance(response, Exception): + raise response + + if response: + return response + + +class ChannelStub(object): + """Stub for the grpc.Channel interface.""" + + def __init__(self, responses=[]): + self.responses = responses + self.requests = [] + + def unary_unary(self, + method, + request_serializer=None, + response_deserializer=None): + return MultiCallableStub(method, self) - # Mock response + +class CustomException(Exception): + pass + + +class TestInstanceAdminClient(object): + def test_list_instance_configs(self): + # Setup Expected Response next_page_token = '' instance_configs_element = {} instance_configs = [instance_configs_element] @@ -54,104 +77,74 @@ def test_list_instance_configs(self, mock_create_stub): } expected_response = spanner_instance_admin_pb2.ListInstanceConfigsResponse( **expected_response) - grpc_stub.ListInstanceConfigs.return_value = expected_response + + # Mock the API response + channel = ChannelStub(responses=[expected_response]) + client = spanner_admin_instance_v1.InstanceAdminClient(channel=channel) + + # Setup Request + parent = client.project_path('[PROJECT]') paged_list_response = client.list_instance_configs(parent) resources = list(paged_list_response) - self.assertEqual(1, len(resources)) - self.assertEqual(expected_response.instance_configs[0], resources[0]) + assert len(resources) == 1 - grpc_stub.ListInstanceConfigs.assert_called_once() - args, kwargs = grpc_stub.ListInstanceConfigs.call_args - self.assertEqual(len(args), 2) - self.assertEqual(len(kwargs), 1) - self.assertIn('metadata', kwargs) - actual_request = args[0] + assert expected_response.instance_configs[0] == resources[0] + assert len(channel.requests) == 1 expected_request = spanner_instance_admin_pb2.ListInstanceConfigsRequest( parent=parent) - self.assertEqual(expected_request, actual_request) + actual_request = channel.requests[0][1] + assert expected_request == actual_request - @mock.patch('google.gax.config.API_ERRORS', (CustomException, )) - @mock.patch('google.gax.config.create_stub', spec=True) - def test_list_instance_configs_exception(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub + def test_list_instance_configs_exception(self): + channel = ChannelStub(responses=[CustomException()]) + client = spanner_admin_instance_v1.InstanceAdminClient(channel=channel) - client = spanner_admin_instance_v1.InstanceAdminClient() - - # Mock request + # Setup request parent = client.project_path('[PROJECT]') - # Mock exception response - grpc_stub.ListInstanceConfigs.side_effect = CustomException() - paged_list_response = client.list_instance_configs(parent) - self.assertRaises(errors.GaxError, list, paged_list_response) - - @mock.patch('google.gax.config.create_stub', spec=True) - def test_get_instance_config(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub - - client = spanner_admin_instance_v1.InstanceAdminClient() + with pytest.raises(CustomException): + list(paged_list_response) - # Mock request - name = client.instance_config_path('[PROJECT]', '[INSTANCE_CONFIG]') - - # Mock response + def test_get_instance_config(self): + # Setup Expected Response name_2 = 'name2-1052831874' display_name = 'displayName1615086568' expected_response = {'name': name_2, 'display_name': display_name} expected_response = spanner_instance_admin_pb2.InstanceConfig( **expected_response) - grpc_stub.GetInstanceConfig.return_value = expected_response - response = client.get_instance_config(name) - self.assertEqual(expected_response, response) + # Mock the API response + channel = ChannelStub(responses=[expected_response]) + client = spanner_admin_instance_v1.InstanceAdminClient(channel=channel) - grpc_stub.GetInstanceConfig.assert_called_once() - args, kwargs = grpc_stub.GetInstanceConfig.call_args - self.assertEqual(len(args), 2) - self.assertEqual(len(kwargs), 1) - self.assertIn('metadata', kwargs) - actual_request = args[0] + # Setup Request + name = client.instance_config_path('[PROJECT]', '[INSTANCE_CONFIG]') + response = client.get_instance_config(name) + assert expected_response == response + + assert len(channel.requests) == 1 expected_request = spanner_instance_admin_pb2.GetInstanceConfigRequest( name=name) - self.assertEqual(expected_request, actual_request) + actual_request = channel.requests[0][1] + assert expected_request == actual_request - @mock.patch('google.gax.config.API_ERRORS', (CustomException, )) - @mock.patch('google.gax.config.create_stub', spec=True) - def test_get_instance_config_exception(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub + def test_get_instance_config_exception(self): + # Mock the API response + channel = ChannelStub(responses=[CustomException()]) + client = spanner_admin_instance_v1.InstanceAdminClient(channel=channel) - client = spanner_admin_instance_v1.InstanceAdminClient() - - # Mock request + # Setup request name = client.instance_config_path('[PROJECT]', '[INSTANCE_CONFIG]') - # Mock exception response - grpc_stub.GetInstanceConfig.side_effect = CustomException() - - self.assertRaises(errors.GaxError, client.get_instance_config, name) - - @mock.patch('google.gax.config.create_stub', spec=True) - def test_list_instances(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub - - client = spanner_admin_instance_v1.InstanceAdminClient() - - # Mock request - parent = client.project_path('[PROJECT]') + with pytest.raises(CustomException): + client.get_instance_config(name) - # Mock response + def test_list_instances(self): + # Setup Expected Response next_page_token = '' instances_element = {} instances = [instances_element] @@ -161,54 +154,39 @@ def test_list_instances(self, mock_create_stub): } expected_response = spanner_instance_admin_pb2.ListInstancesResponse( **expected_response) - grpc_stub.ListInstances.return_value = expected_response + + # Mock the API response + channel = ChannelStub(responses=[expected_response]) + client = spanner_admin_instance_v1.InstanceAdminClient(channel=channel) + + # Setup Request + parent = client.project_path('[PROJECT]') paged_list_response = client.list_instances(parent) resources = list(paged_list_response) - self.assertEqual(1, len(resources)) - self.assertEqual(expected_response.instances[0], resources[0]) + assert len(resources) == 1 - grpc_stub.ListInstances.assert_called_once() - args, kwargs = grpc_stub.ListInstances.call_args - self.assertEqual(len(args), 2) - self.assertEqual(len(kwargs), 1) - self.assertIn('metadata', kwargs) - actual_request = args[0] + assert expected_response.instances[0] == resources[0] + assert len(channel.requests) == 1 expected_request = spanner_instance_admin_pb2.ListInstancesRequest( parent=parent) - self.assertEqual(expected_request, actual_request) + actual_request = channel.requests[0][1] + assert expected_request == actual_request - @mock.patch('google.gax.config.API_ERRORS', (CustomException, )) - @mock.patch('google.gax.config.create_stub', spec=True) - def test_list_instances_exception(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub + def test_list_instances_exception(self): + channel = ChannelStub(responses=[CustomException()]) + client = spanner_admin_instance_v1.InstanceAdminClient(channel=channel) - client = spanner_admin_instance_v1.InstanceAdminClient() - - # Mock request + # Setup request parent = client.project_path('[PROJECT]') - # Mock exception response - grpc_stub.ListInstances.side_effect = CustomException() - paged_list_response = client.list_instances(parent) - self.assertRaises(errors.GaxError, list, paged_list_response) - - @mock.patch('google.gax.config.create_stub', spec=True) - def test_get_instance(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub - - client = spanner_admin_instance_v1.InstanceAdminClient() + with pytest.raises(CustomException): + list(paged_list_response) - # Mock request - name = client.instance_path('[PROJECT]', '[INSTANCE]') - - # Mock response + def test_get_instance(self): + # Setup Expected Response name_2 = 'name2-1052831874' config = 'config-1354792126' display_name = 'displayName1615086568' @@ -221,53 +199,36 @@ def test_get_instance(self, mock_create_stub): } expected_response = spanner_instance_admin_pb2.Instance( **expected_response) - grpc_stub.GetInstance.return_value = expected_response - response = client.get_instance(name) - self.assertEqual(expected_response, response) + # Mock the API response + channel = ChannelStub(responses=[expected_response]) + client = spanner_admin_instance_v1.InstanceAdminClient(channel=channel) + + # Setup Request + name = client.instance_path('[PROJECT]', '[INSTANCE]') - grpc_stub.GetInstance.assert_called_once() - args, kwargs = grpc_stub.GetInstance.call_args - self.assertEqual(len(args), 2) - self.assertEqual(len(kwargs), 1) - self.assertIn('metadata', kwargs) - actual_request = args[0] + response = client.get_instance(name) + assert expected_response == response + assert len(channel.requests) == 1 expected_request = spanner_instance_admin_pb2.GetInstanceRequest( name=name) - self.assertEqual(expected_request, actual_request) + actual_request = channel.requests[0][1] + assert expected_request == actual_request - @mock.patch('google.gax.config.API_ERRORS', (CustomException, )) - @mock.patch('google.gax.config.create_stub', spec=True) - def test_get_instance_exception(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub + def test_get_instance_exception(self): + # Mock the API response + channel = ChannelStub(responses=[CustomException()]) + client = spanner_admin_instance_v1.InstanceAdminClient(channel=channel) - client = spanner_admin_instance_v1.InstanceAdminClient() - - # Mock request + # Setup request name = client.instance_path('[PROJECT]', '[INSTANCE]') - # Mock exception response - grpc_stub.GetInstance.side_effect = CustomException() - - self.assertRaises(errors.GaxError, client.get_instance, name) + with pytest.raises(CustomException): + client.get_instance(name) - @mock.patch('google.gax.config.create_stub', spec=True) - def test_create_instance(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub - - client = spanner_admin_instance_v1.InstanceAdminClient() - - # Mock request - parent = client.project_path('[PROJECT]') - instance_id = 'instanceId-2101995259' - instance = {} - - # Mock response + def test_create_instance(self): + # Setup Expected Response name = 'name3373707' config = 'config-1354792126' display_name = 'displayName1615086568' @@ -283,58 +244,48 @@ def test_create_instance(self, mock_create_stub): operation = operations_pb2.Operation( name='operations/test_create_instance', done=True) operation.response.Pack(expected_response) - grpc_stub.CreateInstance.return_value = operation - - response = client.create_instance(parent, instance_id, instance) - self.assertEqual(expected_response, response.result()) - grpc_stub.CreateInstance.assert_called_once() - args, kwargs = grpc_stub.CreateInstance.call_args - self.assertEqual(len(args), 2) - self.assertEqual(len(kwargs), 1) - self.assertIn('metadata', kwargs) - actual_request = args[0] + # Mock the API response + channel = ChannelStub(responses=[operation]) + client = spanner_admin_instance_v1.InstanceAdminClient(channel=channel) - expected_request = spanner_instance_admin_pb2.CreateInstanceRequest( - parent=parent, instance_id=instance_id, instance=instance) - self.assertEqual(expected_request, actual_request) - - @mock.patch('google.gax.config.create_stub', spec=True) - def test_create_instance_exception(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub - - client = spanner_admin_instance_v1.InstanceAdminClient() - - # Mock request + # Setup Request parent = client.project_path('[PROJECT]') instance_id = 'instanceId-2101995259' instance = {} - # Mock exception response + response = client.create_instance(parent, instance_id, instance) + result = response.result() + assert expected_response == result + + assert len(channel.requests) == 1 + expected_request = spanner_instance_admin_pb2.CreateInstanceRequest( + parent=parent, instance_id=instance_id, instance=instance) + actual_request = channel.requests[0][1] + assert expected_request == actual_request + + def test_create_instance_exception(self): + # Setup Response error = status_pb2.Status() operation = operations_pb2.Operation( name='operations/test_create_instance_exception', done=True) operation.error.CopyFrom(error) - grpc_stub.CreateInstance.return_value = operation - - response = client.create_instance(parent, instance_id, instance) - self.assertEqual(error, response.exception()) - - @mock.patch('google.gax.config.create_stub', spec=True) - def test_update_instance(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub - client = spanner_admin_instance_v1.InstanceAdminClient() + # Mock the API response + channel = ChannelStub(responses=[operation]) + client = spanner_admin_instance_v1.InstanceAdminClient(channel=channel) - # Mock request + # Setup Request + parent = client.project_path('[PROJECT]') + instance_id = 'instanceId-2101995259' instance = {} - field_mask = {} - # Mock response + response = client.create_instance(parent, instance_id, instance) + exception = response.exception() + assert exception.errors[0] == error + + def test_update_instance(self): + # Setup Expected Response name = 'name3373707' config = 'config-1354792126' display_name = 'displayName1615086568' @@ -350,233 +301,171 @@ def test_update_instance(self, mock_create_stub): operation = operations_pb2.Operation( name='operations/test_update_instance', done=True) operation.response.Pack(expected_response) - grpc_stub.UpdateInstance.return_value = operation - response = client.update_instance(instance, field_mask) - self.assertEqual(expected_response, response.result()) + # Mock the API response + channel = ChannelStub(responses=[operation]) + client = spanner_admin_instance_v1.InstanceAdminClient(channel=channel) - grpc_stub.UpdateInstance.assert_called_once() - args, kwargs = grpc_stub.UpdateInstance.call_args - self.assertEqual(len(args), 2) - self.assertEqual(len(kwargs), 1) - self.assertIn('metadata', kwargs) - actual_request = args[0] + # Setup Request + instance = {} + field_mask = {} + + response = client.update_instance(instance, field_mask) + result = response.result() + assert expected_response == result + assert len(channel.requests) == 1 expected_request = spanner_instance_admin_pb2.UpdateInstanceRequest( instance=instance, field_mask=field_mask) - self.assertEqual(expected_request, actual_request) + actual_request = channel.requests[0][1] + assert expected_request == actual_request - @mock.patch('google.gax.config.create_stub', spec=True) - def test_update_instance_exception(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub - - client = spanner_admin_instance_v1.InstanceAdminClient() - - # Mock request - instance = {} - field_mask = {} - - # Mock exception response + def test_update_instance_exception(self): + # Setup Response error = status_pb2.Status() operation = operations_pb2.Operation( name='operations/test_update_instance_exception', done=True) operation.error.CopyFrom(error) - grpc_stub.UpdateInstance.return_value = operation - response = client.update_instance(instance, field_mask) - self.assertEqual(error, response.exception()) + # Mock the API response + channel = ChannelStub(responses=[operation]) + client = spanner_admin_instance_v1.InstanceAdminClient(channel=channel) - @mock.patch('google.gax.config.create_stub', spec=True) - def test_delete_instance(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub + # Setup Request + instance = {} + field_mask = {} - client = spanner_admin_instance_v1.InstanceAdminClient() + response = client.update_instance(instance, field_mask) + exception = response.exception() + assert exception.errors[0] == error + + def test_delete_instance(self): + channel = ChannelStub() + client = spanner_admin_instance_v1.InstanceAdminClient(channel=channel) - # Mock request + # Setup Request name = client.instance_path('[PROJECT]', '[INSTANCE]') client.delete_instance(name) - grpc_stub.DeleteInstance.assert_called_once() - args, kwargs = grpc_stub.DeleteInstance.call_args - self.assertEqual(len(args), 2) - self.assertEqual(len(kwargs), 1) - self.assertIn('metadata', kwargs) - actual_request = args[0] - + assert len(channel.requests) == 1 expected_request = spanner_instance_admin_pb2.DeleteInstanceRequest( name=name) - self.assertEqual(expected_request, actual_request) - - @mock.patch('google.gax.config.API_ERRORS', (CustomException, )) - @mock.patch('google.gax.config.create_stub', spec=True) - def test_delete_instance_exception(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub + actual_request = channel.requests[0][1] + assert expected_request == actual_request - client = spanner_admin_instance_v1.InstanceAdminClient() + def test_delete_instance_exception(self): + # Mock the API response + channel = ChannelStub(responses=[CustomException()]) + client = spanner_admin_instance_v1.InstanceAdminClient(channel=channel) - # Mock request + # Setup request name = client.instance_path('[PROJECT]', '[INSTANCE]') - # Mock exception response - grpc_stub.DeleteInstance.side_effect = CustomException() - - self.assertRaises(errors.GaxError, client.delete_instance, name) - - @mock.patch('google.gax.config.create_stub', spec=True) - def test_set_iam_policy(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub - - client = spanner_admin_instance_v1.InstanceAdminClient() + with pytest.raises(CustomException): + client.delete_instance(name) - # Mock request - resource = client.instance_path('[PROJECT]', '[INSTANCE]') - policy = {} - - # Mock response + def test_set_iam_policy(self): + # Setup Expected Response version = 351608024 etag = b'21' expected_response = {'version': version, 'etag': etag} expected_response = policy_pb2.Policy(**expected_response) - grpc_stub.SetIamPolicy.return_value = expected_response - response = client.set_iam_policy(resource, policy) - self.assertEqual(expected_response, response) + # Mock the API response + channel = ChannelStub(responses=[expected_response]) + client = spanner_admin_instance_v1.InstanceAdminClient(channel=channel) - grpc_stub.SetIamPolicy.assert_called_once() - args, kwargs = grpc_stub.SetIamPolicy.call_args - self.assertEqual(len(args), 2) - self.assertEqual(len(kwargs), 1) - self.assertIn('metadata', kwargs) - actual_request = args[0] + # Setup Request + resource = client.instance_path('[PROJECT]', '[INSTANCE]') + policy = {} + + response = client.set_iam_policy(resource, policy) + assert expected_response == response + assert len(channel.requests) == 1 expected_request = iam_policy_pb2.SetIamPolicyRequest( resource=resource, policy=policy) - self.assertEqual(expected_request, actual_request) + actual_request = channel.requests[0][1] + assert expected_request == actual_request - @mock.patch('google.gax.config.API_ERRORS', (CustomException, )) - @mock.patch('google.gax.config.create_stub', spec=True) - def test_set_iam_policy_exception(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub + def test_set_iam_policy_exception(self): + # Mock the API response + channel = ChannelStub(responses=[CustomException()]) + client = spanner_admin_instance_v1.InstanceAdminClient(channel=channel) - client = spanner_admin_instance_v1.InstanceAdminClient() - - # Mock request + # Setup request resource = client.instance_path('[PROJECT]', '[INSTANCE]') policy = {} - # Mock exception response - grpc_stub.SetIamPolicy.side_effect = CustomException() - - self.assertRaises(errors.GaxError, client.set_iam_policy, resource, - policy) - - @mock.patch('google.gax.config.create_stub', spec=True) - def test_get_iam_policy(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub - - client = spanner_admin_instance_v1.InstanceAdminClient() + with pytest.raises(CustomException): + client.set_iam_policy(resource, policy) - # Mock request - resource = client.instance_path('[PROJECT]', '[INSTANCE]') - - # Mock response + def test_get_iam_policy(self): + # Setup Expected Response version = 351608024 etag = b'21' expected_response = {'version': version, 'etag': etag} expected_response = policy_pb2.Policy(**expected_response) - grpc_stub.GetIamPolicy.return_value = expected_response - response = client.get_iam_policy(resource) - self.assertEqual(expected_response, response) + # Mock the API response + channel = ChannelStub(responses=[expected_response]) + client = spanner_admin_instance_v1.InstanceAdminClient(channel=channel) - grpc_stub.GetIamPolicy.assert_called_once() - args, kwargs = grpc_stub.GetIamPolicy.call_args - self.assertEqual(len(args), 2) - self.assertEqual(len(kwargs), 1) - self.assertIn('metadata', kwargs) - actual_request = args[0] + # Setup Request + resource = client.instance_path('[PROJECT]', '[INSTANCE]') + + response = client.get_iam_policy(resource) + assert expected_response == response + assert len(channel.requests) == 1 expected_request = iam_policy_pb2.GetIamPolicyRequest( resource=resource) - self.assertEqual(expected_request, actual_request) - - @mock.patch('google.gax.config.API_ERRORS', (CustomException, )) - @mock.patch('google.gax.config.create_stub', spec=True) - def test_get_iam_policy_exception(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub + actual_request = channel.requests[0][1] + assert expected_request == actual_request - client = spanner_admin_instance_v1.InstanceAdminClient() + def test_get_iam_policy_exception(self): + # Mock the API response + channel = ChannelStub(responses=[CustomException()]) + client = spanner_admin_instance_v1.InstanceAdminClient(channel=channel) - # Mock request + # Setup request resource = client.instance_path('[PROJECT]', '[INSTANCE]') - # Mock exception response - grpc_stub.GetIamPolicy.side_effect = CustomException() + with pytest.raises(CustomException): + client.get_iam_policy(resource) - self.assertRaises(errors.GaxError, client.get_iam_policy, resource) - - @mock.patch('google.gax.config.create_stub', spec=True) - def test_test_iam_permissions(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub + def test_test_iam_permissions(self): + # Setup Expected Response + expected_response = {} + expected_response = iam_policy_pb2.TestIamPermissionsResponse( + **expected_response) - client = spanner_admin_instance_v1.InstanceAdminClient() + # Mock the API response + channel = ChannelStub(responses=[expected_response]) + client = spanner_admin_instance_v1.InstanceAdminClient(channel=channel) - # Mock request + # Setup Request resource = client.instance_path('[PROJECT]', '[INSTANCE]') permissions = [] - # Mock response - expected_response = {} - expected_response = iam_policy_pb2.TestIamPermissionsResponse( - **expected_response) - grpc_stub.TestIamPermissions.return_value = expected_response - response = client.test_iam_permissions(resource, permissions) - self.assertEqual(expected_response, response) - - grpc_stub.TestIamPermissions.assert_called_once() - args, kwargs = grpc_stub.TestIamPermissions.call_args - self.assertEqual(len(args), 2) - self.assertEqual(len(kwargs), 1) - self.assertIn('metadata', kwargs) - actual_request = args[0] + assert expected_response == response + assert len(channel.requests) == 1 expected_request = iam_policy_pb2.TestIamPermissionsRequest( resource=resource, permissions=permissions) - self.assertEqual(expected_request, actual_request) - - @mock.patch('google.gax.config.API_ERRORS', (CustomException, )) - @mock.patch('google.gax.config.create_stub', spec=True) - def test_test_iam_permissions_exception(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub + actual_request = channel.requests[0][1] + assert expected_request == actual_request - client = spanner_admin_instance_v1.InstanceAdminClient() + def test_test_iam_permissions_exception(self): + # Mock the API response + channel = ChannelStub(responses=[CustomException()]) + client = spanner_admin_instance_v1.InstanceAdminClient(channel=channel) - # Mock request + # Setup request resource = client.instance_path('[PROJECT]', '[INSTANCE]') permissions = [] - # Mock exception response - grpc_stub.TestIamPermissions.side_effect = CustomException() - - self.assertRaises(errors.GaxError, client.test_iam_permissions, - resource, permissions) + with pytest.raises(CustomException): + client.test_iam_permissions(resource, permissions) diff --git a/spanner/tests/unit/gapic/v1/test_spanner_client_v1.py b/spanner/tests/unit/gapic/v1/test_spanner_client_v1.py index e21180bf0341..e4fa27d05a45 100644 --- a/spanner/tests/unit/gapic/v1/test_spanner_client_v1.py +++ b/spanner/tests/unit/gapic/v1/test_spanner_client_v1.py @@ -1,10 +1,10 @@ -# Copyright 2017, Google LLC All rights reserved. +# Copyright 2017 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 +# https://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, @@ -13,18 +13,9 @@ # limitations under the License. """Unit tests.""" -import mock -import unittest - -from google.gax import errors - -# ----------------------------------------------------------------------------- -# Manual change to the GAPIC unit tests because we do not export -# the `SpannerClient` at the usual location because there is a thick wrapper -# around it. -from google.cloud.spanner_v1.gapic import spanner_client as spanner_v1 -# ----------------------------------------------------------------------------- +import pytest +import google.cloud.spanner_v1.gapic.spanner_client as spanner_v1 from google.cloud.spanner_v1.proto import keys_pb2 from google.cloud.spanner_v1.proto import result_set_pb2 from google.cloud.spanner_v1.proto import spanner_pb2 @@ -32,216 +23,228 @@ from google.protobuf import empty_pb2 -class CustomException(Exception): - pass +class MultiCallableStub(object): + """Stub for the grpc.UnaryUnaryMultiCallable interface.""" + def __init__(self, method, channel_stub): + self.method = method + self.channel_stub = channel_stub -class TestSpannerClient(unittest.TestCase): - @mock.patch('google.gax.config.create_stub', spec=True) - def test_create_session(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub + def __call__(self, request, timeout=None, metadata=None, credentials=None): + self.channel_stub.requests.append((self.method, request)) - client = spanner_v1.SpannerClient() + response = None + if self.channel_stub.responses: + response = self.channel_stub.responses.pop() - # Mock request - database = client.database_path('[PROJECT]', '[INSTANCE]', - '[DATABASE]') + if isinstance(response, Exception): + raise response - # Mock response - name = 'name3373707' - expected_response = {'name': name} - expected_response = spanner_pb2.Session(**expected_response) - grpc_stub.CreateSession.return_value = expected_response + if response: + return response - response = client.create_session(database) - self.assertEqual(expected_response, response) - grpc_stub.CreateSession.assert_called_once() - args, kwargs = grpc_stub.CreateSession.call_args - self.assertEqual(len(args), 2) - self.assertEqual(len(kwargs), 1) - self.assertIn('metadata', kwargs) - actual_request = args[0] +class ChannelStub(object): + """Stub for the grpc.Channel interface.""" - expected_request = spanner_pb2.CreateSessionRequest(database=database) - self.assertEqual(expected_request, actual_request) + def __init__(self, responses=[]): + self.responses = responses + self.requests = [] + + def unary_unary(self, + method, + request_serializer=None, + response_deserializer=None): + return MultiCallableStub(method, self) + + def unary_stream(self, + method, + request_serializer=None, + response_deserializer=None): + return MultiCallableStub(method, self) + + +class CustomException(Exception): + pass - @mock.patch('google.gax.config.API_ERRORS', (CustomException, )) - @mock.patch('google.gax.config.create_stub', spec=True) - def test_create_session_exception(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub - client = spanner_v1.SpannerClient() +class TestSpannerClient(object): + def test_create_session(self): + # Setup Expected Response + name = 'name3373707' + expected_response = {'name': name} + expected_response = spanner_pb2.Session(**expected_response) + + # Mock the API response + channel = ChannelStub(responses=[expected_response]) + client = spanner_v1.SpannerClient(channel=channel) - # Mock request + # Setup Request database = client.database_path('[PROJECT]', '[INSTANCE]', '[DATABASE]') - # Mock exception response - grpc_stub.CreateSession.side_effect = CustomException() + response = client.create_session(database) + assert expected_response == response - self.assertRaises(errors.GaxError, client.create_session, database) + assert len(channel.requests) == 1 + expected_request = spanner_pb2.CreateSessionRequest(database=database) + actual_request = channel.requests[0][1] + assert expected_request == actual_request - @mock.patch('google.gax.config.create_stub', spec=True) - def test_get_session(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub + def test_create_session_exception(self): + # Mock the API response + channel = ChannelStub(responses=[CustomException()]) + client = spanner_v1.SpannerClient(channel=channel) - client = spanner_v1.SpannerClient() + # Setup request + database = client.database_path('[PROJECT]', '[INSTANCE]', + '[DATABASE]') - # Mock request - name = client.session_path('[PROJECT]', '[INSTANCE]', '[DATABASE]', - '[SESSION]') + with pytest.raises(CustomException): + client.create_session(database) - # Mock response + def test_get_session(self): + # Setup Expected Response name_2 = 'name2-1052831874' expected_response = {'name': name_2} expected_response = spanner_pb2.Session(**expected_response) - grpc_stub.GetSession.return_value = expected_response - response = client.get_session(name) - self.assertEqual(expected_response, response) + # Mock the API response + channel = ChannelStub(responses=[expected_response]) + client = spanner_v1.SpannerClient(channel=channel) + + # Setup Request + name = client.session_path('[PROJECT]', '[INSTANCE]', '[DATABASE]', + '[SESSION]') - grpc_stub.GetSession.assert_called_once() - args, kwargs = grpc_stub.GetSession.call_args - self.assertEqual(len(args), 2) - self.assertEqual(len(kwargs), 1) - self.assertIn('metadata', kwargs) - actual_request = args[0] + response = client.get_session(name) + assert expected_response == response + assert len(channel.requests) == 1 expected_request = spanner_pb2.GetSessionRequest(name=name) - self.assertEqual(expected_request, actual_request) + actual_request = channel.requests[0][1] + assert expected_request == actual_request - @mock.patch('google.gax.config.API_ERRORS', (CustomException, )) - @mock.patch('google.gax.config.create_stub', spec=True) - def test_get_session_exception(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub + def test_get_session_exception(self): + # Mock the API response + channel = ChannelStub(responses=[CustomException()]) + client = spanner_v1.SpannerClient(channel=channel) - client = spanner_v1.SpannerClient() - - # Mock request + # Setup request name = client.session_path('[PROJECT]', '[INSTANCE]', '[DATABASE]', '[SESSION]') - # Mock exception response - grpc_stub.GetSession.side_effect = CustomException() + with pytest.raises(CustomException): + client.get_session(name) - self.assertRaises(errors.GaxError, client.get_session, name) + def test_list_sessions(self): + # Setup Expected Response + next_page_token = '' + sessions_element = {} + sessions = [sessions_element] + expected_response = { + 'next_page_token': next_page_token, + 'sessions': sessions + } + expected_response = spanner_pb2.ListSessionsResponse( + **expected_response) - @mock.patch('google.gax.config.create_stub', spec=True) - def test_delete_session(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub + # Mock the API response + channel = ChannelStub(responses=[expected_response]) + client = spanner_v1.SpannerClient(channel=channel) - client = spanner_v1.SpannerClient() + # Setup Request + database = client.database_path('[PROJECT]', '[INSTANCE]', + '[DATABASE]') - # Mock request - name = client.session_path('[PROJECT]', '[INSTANCE]', '[DATABASE]', - '[SESSION]') + paged_list_response = client.list_sessions(database) + resources = list(paged_list_response) + assert len(resources) == 1 - client.delete_session(name) + assert expected_response.sessions[0] == resources[0] - grpc_stub.DeleteSession.assert_called_once() - args, kwargs = grpc_stub.DeleteSession.call_args - self.assertEqual(len(args), 2) - self.assertEqual(len(kwargs), 1) - self.assertIn('metadata', kwargs) - actual_request = args[0] + assert len(channel.requests) == 1 + expected_request = spanner_pb2.ListSessionsRequest(database=database) + actual_request = channel.requests[0][1] + assert expected_request == actual_request - expected_request = spanner_pb2.DeleteSessionRequest(name=name) - self.assertEqual(expected_request, actual_request) + def test_list_sessions_exception(self): + channel = ChannelStub(responses=[CustomException()]) + client = spanner_v1.SpannerClient(channel=channel) + + # Setup request + database = client.database_path('[PROJECT]', '[INSTANCE]', + '[DATABASE]') - @mock.patch('google.gax.config.API_ERRORS', (CustomException, )) - @mock.patch('google.gax.config.create_stub', spec=True) - def test_delete_session_exception(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub + paged_list_response = client.list_sessions(database) + with pytest.raises(CustomException): + list(paged_list_response) - client = spanner_v1.SpannerClient() + def test_delete_session(self): + channel = ChannelStub() + client = spanner_v1.SpannerClient(channel=channel) - # Mock request + # Setup Request name = client.session_path('[PROJECT]', '[INSTANCE]', '[DATABASE]', '[SESSION]') - # Mock exception response - grpc_stub.DeleteSession.side_effect = CustomException() + client.delete_session(name) - self.assertRaises(errors.GaxError, client.delete_session, name) + assert len(channel.requests) == 1 + expected_request = spanner_pb2.DeleteSessionRequest(name=name) + actual_request = channel.requests[0][1] + assert expected_request == actual_request - @mock.patch('google.gax.config.create_stub', spec=True) - def test_execute_sql(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub + def test_delete_session_exception(self): + # Mock the API response + channel = ChannelStub(responses=[CustomException()]) + client = spanner_v1.SpannerClient(channel=channel) - client = spanner_v1.SpannerClient() + # Setup request + name = client.session_path('[PROJECT]', '[INSTANCE]', '[DATABASE]', + '[SESSION]') - # Mock request - session = client.session_path('[PROJECT]', '[INSTANCE]', '[DATABASE]', - '[SESSION]') - sql = 'sql114126' + with pytest.raises(CustomException): + client.delete_session(name) - # Mock response + def test_execute_sql(self): + # Setup Expected Response expected_response = {} expected_response = result_set_pb2.ResultSet(**expected_response) - grpc_stub.ExecuteSql.return_value = expected_response - response = client.execute_sql(session, sql) - self.assertEqual(expected_response, response) + # Mock the API response + channel = ChannelStub(responses=[expected_response]) + client = spanner_v1.SpannerClient(channel=channel) - grpc_stub.ExecuteSql.assert_called_once() - args, kwargs = grpc_stub.ExecuteSql.call_args - self.assertEqual(len(args), 2) - self.assertEqual(len(kwargs), 1) - self.assertIn('metadata', kwargs) - actual_request = args[0] - - expected_request = spanner_pb2.ExecuteSqlRequest( - session=session, sql=sql) - self.assertEqual(expected_request, actual_request) - - @mock.patch('google.gax.config.API_ERRORS', (CustomException, )) - @mock.patch('google.gax.config.create_stub', spec=True) - def test_execute_sql_exception(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub - - client = spanner_v1.SpannerClient() - - # Mock request + # Setup Request session = client.session_path('[PROJECT]', '[INSTANCE]', '[DATABASE]', '[SESSION]') sql = 'sql114126' - # Mock exception response - grpc_stub.ExecuteSql.side_effect = CustomException() - - self.assertRaises(errors.GaxError, client.execute_sql, session, sql) + response = client.execute_sql(session, sql) + assert expected_response == response - @mock.patch('google.gax.config.create_stub', spec=True) - def test_execute_streaming_sql(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub + assert len(channel.requests) == 1 + expected_request = spanner_pb2.ExecuteSqlRequest( + session=session, sql=sql) + actual_request = channel.requests[0][1] + assert expected_request == actual_request - client = spanner_v1.SpannerClient() + def test_execute_sql_exception(self): + # Mock the API response + channel = ChannelStub(responses=[CustomException()]) + client = spanner_v1.SpannerClient(channel=channel) - # Mock request + # Setup request session = client.session_path('[PROJECT]', '[INSTANCE]', '[DATABASE]', '[SESSION]') sql = 'sql114126' - # Mock response + with pytest.raises(CustomException): + client.execute_sql(session, sql) + + def test_execute_streaming_sql(self): + # Setup Expected Response chunked_value = True resume_token = b'103' expected_response = { @@ -250,116 +253,82 @@ def test_execute_streaming_sql(self, mock_create_stub): } expected_response = result_set_pb2.PartialResultSet( **expected_response) - grpc_stub.ExecuteStreamingSql.return_value = iter([expected_response]) + + # Mock the API response + channel = ChannelStub(responses=[iter([expected_response])]) + client = spanner_v1.SpannerClient(channel=channel) + + # Setup Request + session = client.session_path('[PROJECT]', '[INSTANCE]', '[DATABASE]', + '[SESSION]') + sql = 'sql114126' response = client.execute_streaming_sql(session, sql) resources = list(response) - self.assertEqual(1, len(resources)) - self.assertEqual(expected_response, resources[0]) - - grpc_stub.ExecuteStreamingSql.assert_called_once() - args, kwargs = grpc_stub.ExecuteStreamingSql.call_args - self.assertEqual(len(args), 2) - self.assertEqual(len(kwargs), 1) - self.assertIn('metadata', kwargs) - actual_request = args[0] + assert len(resources) == 1 + assert expected_response == resources[0] + assert len(channel.requests) == 1 expected_request = spanner_pb2.ExecuteSqlRequest( session=session, sql=sql) - self.assertEqual(expected_request, actual_request) + actual_request = channel.requests[0][1] + assert expected_request == actual_request - @mock.patch('google.gax.config.API_ERRORS', (CustomException, )) - @mock.patch('google.gax.config.create_stub', spec=True) - def test_execute_streaming_sql_exception(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub + def test_execute_streaming_sql_exception(self): + # Mock the API response + channel = ChannelStub(responses=[CustomException()]) + client = spanner_v1.SpannerClient(channel=channel) - client = spanner_v1.SpannerClient() - - # Mock request + # Setup request session = client.session_path('[PROJECT]', '[INSTANCE]', '[DATABASE]', '[SESSION]') sql = 'sql114126' - # Mock exception response - grpc_stub.ExecuteStreamingSql.side_effect = CustomException() - - self.assertRaises(errors.GaxError, client.execute_streaming_sql, - session, sql) + with pytest.raises(CustomException): + client.execute_streaming_sql(session, sql) - @mock.patch('google.gax.config.create_stub', spec=True) - def test_read(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub + def test_read(self): + # Setup Expected Response + expected_response = {} + expected_response = result_set_pb2.ResultSet(**expected_response) - client = spanner_v1.SpannerClient() + # Mock the API response + channel = ChannelStub(responses=[expected_response]) + client = spanner_v1.SpannerClient(channel=channel) - # Mock request + # Setup Request session = client.session_path('[PROJECT]', '[INSTANCE]', '[DATABASE]', '[SESSION]') table = 'table110115790' columns = [] key_set = {} - # Mock response - expected_response = {} - expected_response = result_set_pb2.ResultSet(**expected_response) - grpc_stub.Read.return_value = expected_response - response = client.read(session, table, columns, key_set) - self.assertEqual(expected_response, response) - - grpc_stub.Read.assert_called_once() - args, kwargs = grpc_stub.Read.call_args - self.assertEqual(len(args), 2) - self.assertEqual(len(kwargs), 1) - self.assertIn('metadata', kwargs) - actual_request = args[0] + assert expected_response == response + assert len(channel.requests) == 1 expected_request = spanner_pb2.ReadRequest( session=session, table=table, columns=columns, key_set=key_set) - self.assertEqual(expected_request, actual_request) - - @mock.patch('google.gax.config.API_ERRORS', (CustomException, )) - @mock.patch('google.gax.config.create_stub', spec=True) - def test_read_exception(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub + actual_request = channel.requests[0][1] + assert expected_request == actual_request - client = spanner_v1.SpannerClient() + def test_read_exception(self): + # Mock the API response + channel = ChannelStub(responses=[CustomException()]) + client = spanner_v1.SpannerClient(channel=channel) - # Mock request + # Setup request session = client.session_path('[PROJECT]', '[INSTANCE]', '[DATABASE]', '[SESSION]') table = 'table110115790' columns = [] key_set = {} - # Mock exception response - grpc_stub.Read.side_effect = CustomException() + with pytest.raises(CustomException): + client.read(session, table, columns, key_set) - self.assertRaises(errors.GaxError, client.read, session, table, - columns, key_set) - - @mock.patch('google.gax.config.create_stub', spec=True) - def test_streaming_read(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub - - client = spanner_v1.SpannerClient() - - # Mock request - session = client.session_path('[PROJECT]', '[INSTANCE]', '[DATABASE]', - '[SESSION]') - table = 'table110115790' - columns = [] - key_set = {} - - # Mock response + def test_streaming_read(self): + # Setup Expected Response chunked_value = True resume_token = b'103' expected_response = { @@ -368,192 +337,143 @@ def test_streaming_read(self, mock_create_stub): } expected_response = result_set_pb2.PartialResultSet( **expected_response) - grpc_stub.StreamingRead.return_value = iter([expected_response]) + + # Mock the API response + channel = ChannelStub(responses=[iter([expected_response])]) + client = spanner_v1.SpannerClient(channel=channel) + + # Setup Request + session = client.session_path('[PROJECT]', '[INSTANCE]', '[DATABASE]', + '[SESSION]') + table = 'table110115790' + columns = [] + key_set = {} response = client.streaming_read(session, table, columns, key_set) resources = list(response) - self.assertEqual(1, len(resources)) - self.assertEqual(expected_response, resources[0]) - - grpc_stub.StreamingRead.assert_called_once() - args, kwargs = grpc_stub.StreamingRead.call_args - self.assertEqual(len(args), 2) - self.assertEqual(len(kwargs), 1) - self.assertIn('metadata', kwargs) - actual_request = args[0] + assert len(resources) == 1 + assert expected_response == resources[0] + assert len(channel.requests) == 1 expected_request = spanner_pb2.ReadRequest( session=session, table=table, columns=columns, key_set=key_set) - self.assertEqual(expected_request, actual_request) + actual_request = channel.requests[0][1] + assert expected_request == actual_request - @mock.patch('google.gax.config.API_ERRORS', (CustomException, )) - @mock.patch('google.gax.config.create_stub', spec=True) - def test_streaming_read_exception(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub + def test_streaming_read_exception(self): + # Mock the API response + channel = ChannelStub(responses=[CustomException()]) + client = spanner_v1.SpannerClient(channel=channel) - client = spanner_v1.SpannerClient() - - # Mock request + # Setup request session = client.session_path('[PROJECT]', '[INSTANCE]', '[DATABASE]', '[SESSION]') table = 'table110115790' columns = [] key_set = {} - # Mock exception response - grpc_stub.StreamingRead.side_effect = CustomException() - - self.assertRaises(errors.GaxError, client.streaming_read, session, - table, columns, key_set) + with pytest.raises(CustomException): + client.streaming_read(session, table, columns, key_set) - @mock.patch('google.gax.config.create_stub', spec=True) - def test_begin_transaction(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub + def test_begin_transaction(self): + # Setup Expected Response + id_ = b'27' + expected_response = {'id': id_} + expected_response = transaction_pb2.Transaction(**expected_response) - client = spanner_v1.SpannerClient() + # Mock the API response + channel = ChannelStub(responses=[expected_response]) + client = spanner_v1.SpannerClient(channel=channel) - # Mock request + # Setup Request session = client.session_path('[PROJECT]', '[INSTANCE]', '[DATABASE]', '[SESSION]') options_ = {} - # Mock response - id_ = b'27' - expected_response = {'id': id_} - expected_response = transaction_pb2.Transaction(**expected_response) - grpc_stub.BeginTransaction.return_value = expected_response - response = client.begin_transaction(session, options_) - self.assertEqual(expected_response, response) - - grpc_stub.BeginTransaction.assert_called_once() - args, kwargs = grpc_stub.BeginTransaction.call_args - self.assertEqual(len(args), 2) - self.assertEqual(len(kwargs), 1) - self.assertIn('metadata', kwargs) - actual_request = args[0] + assert expected_response == response + assert len(channel.requests) == 1 expected_request = spanner_pb2.BeginTransactionRequest( session=session, options=options_) - self.assertEqual(expected_request, actual_request) - - @mock.patch('google.gax.config.API_ERRORS', (CustomException, )) - @mock.patch('google.gax.config.create_stub', spec=True) - def test_begin_transaction_exception(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub + actual_request = channel.requests[0][1] + assert expected_request == actual_request - client = spanner_v1.SpannerClient() + def test_begin_transaction_exception(self): + # Mock the API response + channel = ChannelStub(responses=[CustomException()]) + client = spanner_v1.SpannerClient(channel=channel) - # Mock request + # Setup request session = client.session_path('[PROJECT]', '[INSTANCE]', '[DATABASE]', '[SESSION]') options_ = {} - # Mock exception response - grpc_stub.BeginTransaction.side_effect = CustomException() + with pytest.raises(CustomException): + client.begin_transaction(session, options_) - self.assertRaises(errors.GaxError, client.begin_transaction, session, - options_) - - @mock.patch('google.gax.config.create_stub', spec=True) - def test_commit(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub + def test_commit(self): + # Setup Expected Response + expected_response = {} + expected_response = spanner_pb2.CommitResponse(**expected_response) - client = spanner_v1.SpannerClient() + # Mock the API response + channel = ChannelStub(responses=[expected_response]) + client = spanner_v1.SpannerClient(channel=channel) - # Mock request + # Setup Request session = client.session_path('[PROJECT]', '[INSTANCE]', '[DATABASE]', '[SESSION]') mutations = [] - # Mock response - expected_response = {} - expected_response = spanner_pb2.CommitResponse(**expected_response) - grpc_stub.Commit.return_value = expected_response - response = client.commit(session, mutations) - self.assertEqual(expected_response, response) - - grpc_stub.Commit.assert_called_once() - args, kwargs = grpc_stub.Commit.call_args - self.assertEqual(len(args), 2) - self.assertEqual(len(kwargs), 1) - self.assertIn('metadata', kwargs) - actual_request = args[0] + assert expected_response == response + assert len(channel.requests) == 1 expected_request = spanner_pb2.CommitRequest( session=session, mutations=mutations) - self.assertEqual(expected_request, actual_request) - - @mock.patch('google.gax.config.API_ERRORS', (CustomException, )) - @mock.patch('google.gax.config.create_stub', spec=True) - def test_commit_exception(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub + actual_request = channel.requests[0][1] + assert expected_request == actual_request - client = spanner_v1.SpannerClient() + def test_commit_exception(self): + # Mock the API response + channel = ChannelStub(responses=[CustomException()]) + client = spanner_v1.SpannerClient(channel=channel) - # Mock request + # Setup request session = client.session_path('[PROJECT]', '[INSTANCE]', '[DATABASE]', '[SESSION]') mutations = [] - # Mock exception response - grpc_stub.Commit.side_effect = CustomException() - - self.assertRaises(errors.GaxError, client.commit, session, mutations) - - @mock.patch('google.gax.config.create_stub', spec=True) - def test_rollback(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub + with pytest.raises(CustomException): + client.commit(session, mutations) - client = spanner_v1.SpannerClient() + def test_rollback(self): + channel = ChannelStub() + client = spanner_v1.SpannerClient(channel=channel) - # Mock request + # Setup Request session = client.session_path('[PROJECT]', '[INSTANCE]', '[DATABASE]', '[SESSION]') transaction_id = b'28' client.rollback(session, transaction_id) - grpc_stub.Rollback.assert_called_once() - args, kwargs = grpc_stub.Rollback.call_args - self.assertEqual(len(args), 2) - self.assertEqual(len(kwargs), 1) - self.assertIn('metadata', kwargs) - actual_request = args[0] - + assert len(channel.requests) == 1 expected_request = spanner_pb2.RollbackRequest( session=session, transaction_id=transaction_id) - self.assertEqual(expected_request, actual_request) - - @mock.patch('google.gax.config.API_ERRORS', (CustomException, )) - @mock.patch('google.gax.config.create_stub', spec=True) - def test_rollback_exception(self, mock_create_stub): - # Mock gRPC layer - grpc_stub = mock.Mock() - mock_create_stub.return_value = grpc_stub + actual_request = channel.requests[0][1] + assert expected_request == actual_request - client = spanner_v1.SpannerClient() + def test_rollback_exception(self): + # Mock the API response + channel = ChannelStub(responses=[CustomException()]) + client = spanner_v1.SpannerClient(channel=channel) - # Mock request + # Setup request session = client.session_path('[PROJECT]', '[INSTANCE]', '[DATABASE]', '[SESSION]') transaction_id = b'28' - # Mock exception response - grpc_stub.Rollback.side_effect = CustomException() - - self.assertRaises(errors.GaxError, client.rollback, session, - transaction_id) + with pytest.raises(CustomException): + client.rollback(session, transaction_id) diff --git a/spanner/tests/unit/test__helpers.py b/spanner/tests/unit/test__helpers.py index c25443753533..0f579952bfb3 100644 --- a/spanner/tests/unit/test__helpers.py +++ b/spanner/tests/unit/test__helpers.py @@ -515,29 +515,15 @@ def test_ctor(self): self.assertIs(base._session, session) -class Test_options_with_prefix(unittest.TestCase): +class Test_metadata_with_prefix(unittest.TestCase): def _call_fut(self, *args, **kw): - from google.cloud.spanner_v1._helpers import _options_with_prefix + from google.cloud.spanner_v1._helpers import _metadata_with_prefix - return _options_with_prefix(*args, **kw) + return _metadata_with_prefix(*args, **kw) - def test_wo_kwargs(self): - from google.gax import CallOptions - - PREFIX = 'prefix' - options = self._call_fut(PREFIX) - self.assertIsInstance(options, CallOptions) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', PREFIX)]) - - def test_w_kwargs(self): - from google.gax import CallOptions - - PREFIX = 'prefix' - TOKEN = 'token' - options = self._call_fut('prefix', page_token=TOKEN) - self.assertIsInstance(options, CallOptions) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', PREFIX)]) - self.assertEqual(options.page_token, TOKEN) + def test(self): + prefix = 'prefix' + metadata = self._call_fut(prefix) + self.assertEqual( + metadata, [('google-cloud-resource-prefix', prefix)]) diff --git a/spanner/tests/unit/test_batch.py b/spanner/tests/unit/test_batch.py index 72f1b6d1b3d0..a34044a5a03f 100644 --- a/spanner/tests/unit/test_batch.py +++ b/spanner/tests/unit/test_batch.py @@ -15,8 +15,6 @@ import unittest -from google.cloud._testing import _GAXBaseAPI - TABLE_NAME = 'citizens' COLUMNS = ['email', 'first_name', 'last_name', 'age'] @@ -194,7 +192,7 @@ def test_commit_already_committed(self): batch.commit() def test_commit_grpc_error(self): - from google.gax.errors import GaxError + from google.api_core.exceptions import Unknown from google.cloud.spanner_v1.proto.transaction_pb2 import ( TransactionOptions) from google.cloud.spanner_v1.proto.mutation_pb2 import ( @@ -204,34 +202,14 @@ def test_commit_grpc_error(self): keys = [[0], [1], [2]] keyset = KeySet(keys=keys) database = _Database() - api = database.spanner_api = _FauxSpannerAPI( - _random_gax_error=True) + database.spanner_api = _FauxSpannerAPI(_rpc_error=True) session = _Session(database) batch = self._make_one(session) batch.delete(TABLE_NAME, keyset=keyset) - with self.assertRaises(GaxError): + with self.assertRaises(Unknown): batch.commit() - (session, mutations, single_use_txn, options) = api._committed - self.assertEqual(session, self.SESSION_NAME) - self.assertTrue(len(mutations), 1) - mutation = mutations[0] - self.assertIsInstance(mutation, MutationPB) - self.assertTrue(mutation.HasField('delete')) - delete = mutation.delete - self.assertEqual(delete.table, TABLE_NAME) - keyset_pb = delete.key_set - self.assertEqual(len(keyset_pb.ranges), 0) - self.assertEqual(len(keyset_pb.keys), len(keys)) - for found, expected in zip(keyset_pb.keys, keys): - self.assertEqual( - [int(value.string_value) for value in found.values], expected) - self.assertIsInstance(single_use_txn, TransactionOptions) - self.assertTrue(single_use_txn.HasField('read_write')) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', database.name)]) - def test_commit_ok(self): import datetime from google.cloud.spanner_v1.proto.spanner_pb2 import CommitResponse @@ -255,13 +233,13 @@ def test_commit_ok(self): self.assertEqual(committed, now) self.assertEqual(batch.committed, committed) - (session, mutations, single_use_txn, options) = api._committed + (session, mutations, single_use_txn, metadata) = api._committed self.assertEqual(session, self.SESSION_NAME) self.assertEqual(mutations, batch._mutations) self.assertIsInstance(single_use_txn, TransactionOptions) self.assertTrue(single_use_txn.HasField('read_write')) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', database.name)]) + self.assertEqual( + metadata, [('google-cloud-resource-prefix', database.name)]) def test_context_mgr_already_committed(self): import datetime @@ -302,13 +280,13 @@ def test_context_mgr_success(self): self.assertEqual(batch.committed, now) - (session, mutations, single_use_txn, options) = api._committed + (session, mutations, single_use_txn, metadata) = api._committed self.assertEqual(session, self.SESSION_NAME) self.assertEqual(mutations, batch._mutations) self.assertIsInstance(single_use_txn, TransactionOptions) self.assertTrue(single_use_txn.HasField('read_write')) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', database.name)]) + self.assertEqual( + metadata, [('google-cloud-resource-prefix', database.name)]) def test_context_mgr_failure(self): import datetime @@ -349,18 +327,23 @@ class _Database(object): name = 'testing' -class _FauxSpannerAPI(_GAXBaseAPI): +class _FauxSpannerAPI(): _create_instance_conflict = False _instance_not_found = False _committed = None + _rpc_error = False + + def __init__(self, **kwargs): + self.__dict__.update(**kwargs) def commit(self, session, mutations, - transaction_id='', single_use_transaction=None, options=None): - from google.gax.errors import GaxError + transaction_id='', single_use_transaction=None, metadata=None): + from google.api_core.exceptions import Unknown assert transaction_id == '' - self._committed = (session, mutations, single_use_transaction, options) - if self._random_gax_error: - raise GaxError('error') + self._committed = ( + session, mutations, single_use_transaction, metadata) + if self._rpc_error: + raise Unknown('error') return self._commit_response diff --git a/spanner/tests/unit/test_client.py b/spanner/tests/unit/test_client.py index 00d7f34fb9c8..4bff711b3c9f 100644 --- a/spanner/tests/unit/test_client.py +++ b/spanner/tests/unit/test_client.py @@ -15,7 +15,6 @@ import unittest import mock -import six def _make_credentials(): @@ -105,48 +104,9 @@ def test_constructor_credentials_wo_create_scoped(self): expected_scopes = None self._constructor_test_helper(expected_scopes, creds) - def test_admin_api_lib_name(self): - from google.cloud.spanner_v1 import __version__ - from google.cloud.spanner_admin_database_v1 import gapic as db - from google.cloud.spanner_admin_instance_v1 import gapic as inst - - # Get the actual admin client classes. - DatabaseAdminClient = db.database_admin_client.DatabaseAdminClient - InstanceAdminClient = inst.instance_admin_client.InstanceAdminClient - - # Test that the DatabaseAdminClient is called with the gccl library - # name and version. - with mock.patch.object(DatabaseAdminClient, '__init__') as mock_dac: - mock_dac.return_value = None - client = self._make_one( - credentials=_make_credentials(), - project='foo', - ) - self.assertIsInstance(client.database_admin_api, - DatabaseAdminClient) - mock_dac.assert_called_once() - self.assertEqual(mock_dac.mock_calls[0][2]['lib_name'], 'gccl') - self.assertEqual(mock_dac.mock_calls[0][2]['lib_version'], - __version__) - - # Test that the InstanceAdminClient is called with the gccl library - # name and version. - with mock.patch.object(InstanceAdminClient, '__init__') as mock_iac: - mock_iac.return_value = None - client = self._make_one( - credentials=_make_credentials(), - project='foo', - ) - self.assertIsInstance(client.instance_admin_api, - InstanceAdminClient) - mock_iac.assert_called_once() - self.assertEqual(mock_iac.mock_calls[0][2]['lib_name'], 'gccl') - self.assertEqual(mock_iac.mock_calls[0][2]['lib_version'], - __version__) - def test_instance_admin_api(self): - from google.cloud.spanner_v1 import __version__ - from google.cloud.spanner_v1.client import SPANNER_ADMIN_SCOPE + from google.cloud.spanner_v1.client import ( + _CLIENT_INFO, SPANNER_ADMIN_SCOPE) credentials = _make_credentials() client = self._make_one(project=self.PROJECT, credentials=credentials) @@ -163,15 +123,14 @@ def test_instance_admin_api(self): self.assertIs(again, api) instance_admin_client.assert_called_once_with( - lib_name='gccl', - lib_version=__version__, - credentials=credentials.with_scopes.return_value) + credentials=credentials.with_scopes.return_value, + client_info=_CLIENT_INFO) credentials.with_scopes.assert_called_once_with(expected_scopes) def test_database_admin_api(self): - from google.cloud.spanner_v1 import __version__ - from google.cloud.spanner_v1.client import SPANNER_ADMIN_SCOPE + from google.cloud.spanner_v1.client import ( + _CLIENT_INFO, SPANNER_ADMIN_SCOPE) credentials = _make_credentials() client = self._make_one(project=self.PROJECT, credentials=credentials) @@ -188,9 +147,8 @@ def test_database_admin_api(self): self.assertIs(again, api) database_admin_client.assert_called_once_with( - lib_name='gccl', - lib_version=__version__, - credentials=credentials.with_scopes.return_value) + credentials=credentials.with_scopes.return_value, + client_info=_CLIENT_INFO) credentials.with_scopes.assert_called_once_with(expected_scopes) @@ -220,72 +178,82 @@ def test_project_name_property(self): project_name = 'projects/' + self.PROJECT self.assertEqual(client.project_name, project_name) - def test_list_instance_configs_wo_paging(self): - from google.cloud._testing import _GAXPageIterator - from google.gax import INITIAL_PAGE + def test_list_instance_configs(self): + from google.cloud.spanner_admin_instance_v1.gapic import ( + instance_admin_client) + from google.cloud.spanner_admin_instance_v1.proto import ( + spanner_instance_admin_pb2) from google.cloud.spanner_v1.client import InstanceConfig + api = instance_admin_client.InstanceAdminClient(mock.Mock()) credentials = _make_credentials() client = self._make_one(project=self.PROJECT, credentials=credentials) - client.connection = object() - api = client._instance_admin_api = _FauxInstanceAdminAPI() - config = _InstanceConfigPB(name=self.CONFIGURATION_NAME, - display_name=self.DISPLAY_NAME) - response = _GAXPageIterator([config]) - api._list_instance_configs_response = response - - iterator = client.list_instance_configs() - configs = list(iterator) - - self.assertEqual(len(configs), 1) - config = configs[0] - self.assertTrue(isinstance(config, InstanceConfig)) - self.assertEqual(config.name, self.CONFIGURATION_NAME) - self.assertEqual(config.display_name, self.DISPLAY_NAME) - - project, page_size, options = api._listed_instance_configs - self.assertEqual(project, self.PATH) - self.assertEqual(page_size, None) - self.assertIs(options.page_token, INITIAL_PAGE) - self.assertEqual( - options.kwargs['metadata'], - [('google-cloud-resource-prefix', client.project_name)]) - - def test_list_instance_configs_w_paging(self): - from google.cloud._testing import _GAXPageIterator - from google.cloud.spanner_v1.client import InstanceConfig + client._instance_admin_api = api + + instance_config_pbs = ( + spanner_instance_admin_pb2.ListInstanceConfigsResponse( + instance_configs=[ + spanner_instance_admin_pb2.InstanceConfig( + name=self.CONFIGURATION_NAME, + display_name=self.DISPLAY_NAME), + ] + ) + ) + + api._list_instance_configs = mock.Mock( + return_value=instance_config_pbs) + + response = client.list_instance_configs() + instance_configs = list(response) + + instance_config = instance_configs[0] + self.assertIsInstance(instance_config, InstanceConfig) + self.assertEqual(instance_config.name, self.CONFIGURATION_NAME) + self.assertEqual(instance_config.display_name, self.DISPLAY_NAME) + + api._list_instance_configs.assert_called_once_with( + spanner_instance_admin_pb2.ListInstanceConfigsRequest( + parent=self.PATH), + metadata=[('google-cloud-resource-prefix', client.project_name)], + retry=mock.ANY, + timeout=mock.ANY) - SIZE = 15 - TOKEN_RETURNED = 'TOKEN_RETURNED' - TOKEN_PASSED = 'TOKEN_PASSED' + def test_list_instance_configs_w_options(self): + from google.cloud.spanner_admin_instance_v1.gapic import ( + instance_admin_client) + from google.cloud.spanner_admin_instance_v1.proto import ( + spanner_instance_admin_pb2) + + api = instance_admin_client.InstanceAdminClient(mock.Mock()) credentials = _make_credentials() client = self._make_one(project=self.PROJECT, credentials=credentials) - client.connection = object() - api = client._instance_admin_api = _FauxInstanceAdminAPI() - config = _InstanceConfigPB(name=self.CONFIGURATION_NAME, - display_name=self.DISPLAY_NAME) - response = _GAXPageIterator([config], page_token=TOKEN_RETURNED) - api._list_instance_configs_response = response - - iterator = client.list_instance_configs(SIZE, TOKEN_PASSED) - page = six.next(iterator.pages) - next_token = iterator.next_page_token - configs = list(page) - - self.assertEqual(len(configs), 1) - config = configs[0] - self.assertTrue(isinstance(config, InstanceConfig)) - self.assertEqual(config.name, self.CONFIGURATION_NAME) - self.assertEqual(config.display_name, self.DISPLAY_NAME) - self.assertEqual(next_token, TOKEN_RETURNED) - - project, page_size, options = api._listed_instance_configs - self.assertEqual(project, self.PATH) - self.assertEqual(page_size, SIZE) - self.assertEqual(options.page_token, TOKEN_PASSED) - self.assertEqual( - options.kwargs['metadata'], - [('google-cloud-resource-prefix', client.project_name)]) + client._instance_admin_api = api + + instance_config_pbs = ( + spanner_instance_admin_pb2.ListInstanceConfigsResponse( + instance_configs=[ + spanner_instance_admin_pb2.InstanceConfig( + name=self.CONFIGURATION_NAME, + display_name=self.DISPLAY_NAME), + ] + ) + ) + + api._list_instance_configs = mock.Mock( + return_value=instance_config_pbs) + + token = 'token' + page_size = 42 + list(client.list_instance_configs(page_token=token, page_size=42)) + + api._list_instance_configs.assert_called_once_with( + spanner_instance_admin_pb2.ListInstanceConfigsRequest( + parent=self.PATH, + page_size=page_size, + page_token=token), + metadata=[('google-cloud-resource-prefix', client.project_name)], + retry=mock.ANY, + timeout=mock.ANY) def test_instance_factory_defaults(self): from google.cloud.spanner_v1.instance import DEFAULT_NODE_COUNT @@ -320,107 +288,79 @@ def test_instance_factory_explicit(self): self.assertEqual(instance.node_count, self.NODE_COUNT) self.assertIs(instance._client, client) - def test_list_instances_wo_paging(self): - from google.cloud._testing import _GAXPageIterator - from google.gax import INITIAL_PAGE - from google.cloud.spanner_v1.instance import Instance + def test_list_instances(self): + from google.cloud.spanner_admin_instance_v1.gapic import ( + instance_admin_client) + from google.cloud.spanner_admin_instance_v1.proto import ( + spanner_instance_admin_pb2) + from google.cloud.spanner_v1.client import Instance + api = instance_admin_client.InstanceAdminClient(mock.Mock()) credentials = _make_credentials() client = self._make_one(project=self.PROJECT, credentials=credentials) - client.connection = object() - api = client._instance_admin_api = _FauxInstanceAdminAPI() - instance = _InstancePB(name=self.INSTANCE_NAME, - config=self.CONFIGURATION_NAME, - display_name=self.DISPLAY_NAME, - node_count=self.NODE_COUNT) - response = _GAXPageIterator([instance]) - api._list_instances_response = response - - iterator = client.list_instances(filter_='name:TEST') - instances = list(iterator) - - self.assertEqual(len(instances), 1) - instance = instances[0] - self.assertTrue(isinstance(instance, Instance)) - self.assertEqual(instance.name, self.INSTANCE_NAME) - self.assertEqual(instance.configuration_name, self.CONFIGURATION_NAME) - self.assertEqual(instance.display_name, self.DISPLAY_NAME) - self.assertEqual(instance.node_count, self.NODE_COUNT) + client._instance_admin_api = api + + instance_pbs = ( + spanner_instance_admin_pb2.ListInstancesResponse( + instances=[ + spanner_instance_admin_pb2.Instance( + name=self.INSTANCE_NAME, + config=self.CONFIGURATION_NAME, + display_name=self.DISPLAY_NAME, + node_count=self.NODE_COUNT), + ] + ) + ) - project, filter_, page_size, options = api._listed_instances - self.assertEqual(project, self.PATH) - self.assertEqual(filter_, 'name:TEST') - self.assertEqual(page_size, None) - self.assertIs(options.page_token, INITIAL_PAGE) - self.assertEqual( - options.kwargs['metadata'], - [('google-cloud-resource-prefix', client.project_name)]) - - def test_list_instances_w_paging(self): - from google.cloud._testing import _GAXPageIterator - from google.cloud.spanner_v1.instance import Instance + api._list_instances = mock.Mock( + return_value=instance_pbs) + + response = client.list_instances() + instances = list(response) - SIZE = 15 - TOKEN_RETURNED = 'TOKEN_RETURNED' - TOKEN_PASSED = 'TOKEN_PASSED' - credentials = _make_credentials() - client = self._make_one(project=self.PROJECT, credentials=credentials) - client.connection = object() - api = client._instance_admin_api = _FauxInstanceAdminAPI() - instance = _InstancePB(name=self.INSTANCE_NAME, - config=self.CONFIGURATION_NAME, - display_name=self.DISPLAY_NAME, - node_count=self.NODE_COUNT) - response = _GAXPageIterator([instance], page_token=TOKEN_RETURNED) - api._list_instances_response = response - - iterator = client.list_instances( - page_size=SIZE, page_token=TOKEN_PASSED) - page = six.next(iterator.pages) - next_token = iterator.next_page_token - instances = list(page) - - self.assertEqual(len(instances), 1) instance = instances[0] - self.assertTrue(isinstance(instance, Instance)) + self.assertIsInstance(instance, Instance) self.assertEqual(instance.name, self.INSTANCE_NAME) self.assertEqual(instance.configuration_name, self.CONFIGURATION_NAME) self.assertEqual(instance.display_name, self.DISPLAY_NAME) self.assertEqual(instance.node_count, self.NODE_COUNT) - self.assertEqual(next_token, TOKEN_RETURNED) - project, filter_, page_size, options = api._listed_instances - self.assertEqual(project, self.PATH) - self.assertEqual(filter_, '') - self.assertEqual(page_size, SIZE) - self.assertEqual(options.page_token, TOKEN_PASSED) - self.assertEqual( - options.kwargs['metadata'], - [('google-cloud-resource-prefix', client.project_name)]) + api._list_instances.assert_called_once_with( + spanner_instance_admin_pb2.ListInstancesRequest( + parent=self.PATH), + metadata=[('google-cloud-resource-prefix', client.project_name)], + retry=mock.ANY, + timeout=mock.ANY) + def test_list_instances_w_options(self): + from google.cloud.spanner_admin_instance_v1.gapic import ( + instance_admin_client) + from google.cloud.spanner_admin_instance_v1.proto import ( + spanner_instance_admin_pb2) -class _FauxInstanceAdminAPI(object): - - def list_instance_configs(self, name, page_size, options): - self._listed_instance_configs = (name, page_size, options) - return self._list_instance_configs_response - - def list_instances(self, name, filter_, page_size, options): - self._listed_instances = (name, filter_, page_size, options) - return self._list_instances_response - - -class _InstanceConfigPB(object): - - def __init__(self, name, display_name): - self.name = name - self.display_name = display_name - + api = instance_admin_client.InstanceAdminClient(mock.Mock()) + credentials = _make_credentials() + client = self._make_one(project=self.PROJECT, credentials=credentials) + client._instance_admin_api = api -class _InstancePB(object): + instance_pbs = ( + spanner_instance_admin_pb2.ListInstancesResponse( + instances=[] + ) + ) - def __init__(self, name, config, display_name=None, node_count=None): - self.name = name - self.config = config - self.display_name = display_name - self.node_count = node_count + api._list_instances = mock.Mock( + return_value=instance_pbs) + + token = 'token' + page_size = 42 + list(client.list_instances(page_token=token, page_size=42)) + + api._list_instances.assert_called_once_with( + spanner_instance_admin_pb2.ListInstancesRequest( + parent=self.PATH, + page_size=page_size, + page_token=token), + metadata=[('google-cloud-resource-prefix', client.project_name)], + retry=mock.ANY, + timeout=mock.ANY) diff --git a/spanner/tests/unit/test_database.py b/spanner/tests/unit/test_database.py index 97c9fe3b0e85..b4e6ea562af3 100644 --- a/spanner/tests/unit/test_database.py +++ b/spanner/tests/unit/test_database.py @@ -17,8 +17,6 @@ import mock -from google.cloud._testing import _GAXBaseAPI - from google.cloud.spanner_v1 import __version__ @@ -190,6 +188,8 @@ def test_name_property(self): self.assertEqual(database.name, expected_name) def test_spanner_api_property_w_scopeless_creds(self): + from google.cloud.spanner_v1.database import _CLIENT_INFO + client = _Client() credentials = client.credentials = object() instance = _Instance(self.INSTANCE_NAME, client=client) @@ -208,13 +208,13 @@ def test_spanner_api_property_w_scopeless_creds(self): self.assertIs(again, api) spanner_client.assert_called_once_with( - lib_name='gccl', - lib_version=__version__, - credentials=credentials) + credentials=credentials, + client_info=_CLIENT_INFO) def test_spanner_api_w_scoped_creds(self): import google.auth.credentials - from google.cloud.spanner_v1.database import SPANNER_DATA_SCOPE + from google.cloud.spanner_v1.database import ( + _CLIENT_INFO, SPANNER_DATA_SCOPE) class _CredentialsWithScopes( google.auth.credentials.Scoped): @@ -250,8 +250,7 @@ def with_scopes(self, scopes): self.assertEqual(len(spanner_client.call_args_list), 1) called_args, called_kw = spanner_client.call_args self.assertEqual(called_args, ()) - self.assertEqual(called_kw['lib_name'], 'gccl') - self.assertEqual(called_kw['lib_version'], __version__) + self.assertEqual(called_kw['client_info'], _CLIENT_INFO) scoped = called_kw['credentials'] self.assertEqual(scoped._scopes, expected_scopes) self.assertIs(scoped._source, credentials) @@ -288,7 +287,7 @@ def test_create_grpc_error(self): client = _Client() api = client.database_admin_api = _FauxDatabaseAdminAPI( - _random_gax_error=True) + _rpc_error=True) instance = _Instance(self.INSTANCE_NAME, client=client) pool = _Pool() database = self._make_one(self.DATABASE_ID, instance, pool=pool) @@ -297,13 +296,13 @@ def test_create_grpc_error(self): database.create() (parent, create_statement, extra_statements, - options) = api._created_database + metadata) = api._created_database self.assertEqual(parent, self.INSTANCE_NAME) self.assertEqual(create_statement, 'CREATE DATABASE %s' % self.DATABASE_ID) self.assertEqual(extra_statements, []) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', database.name)]) + self.assertEqual( + metadata, [('google-cloud-resource-prefix', database.name)]) def test_create_already_exists(self): from google.cloud.exceptions import Conflict @@ -320,13 +319,13 @@ def test_create_already_exists(self): database.create() (parent, create_statement, extra_statements, - options) = api._created_database + metadata) = api._created_database self.assertEqual(parent, self.INSTANCE_NAME) self.assertEqual(create_statement, 'CREATE DATABASE `%s`' % DATABASE_ID_HYPHEN) self.assertEqual(extra_statements, []) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', database.name)]) + self.assertEqual( + metadata, [('google-cloud-resource-prefix', database.name)]) def test_create_instance_not_found(self): from google.cloud.exceptions import NotFound @@ -343,13 +342,13 @@ def test_create_instance_not_found(self): database.create() (parent, create_statement, extra_statements, - options) = api._created_database + metadata) = api._created_database self.assertEqual(parent, self.INSTANCE_NAME) self.assertEqual(create_statement, 'CREATE DATABASE `%s`' % DATABASE_ID_HYPHEN) self.assertEqual(extra_statements, []) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', database.name)]) + self.assertEqual( + metadata, [('google-cloud-resource-prefix', database.name)]) def test_create_success(self): from tests._fixtures import DDL_STATEMENTS @@ -369,32 +368,27 @@ def test_create_success(self): self.assertIs(future, op_future) (parent, create_statement, extra_statements, - options) = api._created_database + metadata) = api._created_database self.assertEqual(parent, self.INSTANCE_NAME) self.assertEqual(create_statement, 'CREATE DATABASE %s' % self.DATABASE_ID) self.assertEqual(extra_statements, DDL_STATEMENTS) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', database.name)]) + self.assertEqual( + metadata, [('google-cloud-resource-prefix', database.name)]) def test_exists_grpc_error(self): - from google.gax.errors import GaxError + from google.api_core.exceptions import Unknown client = _Client() - api = client.database_admin_api = _FauxDatabaseAdminAPI( - _random_gax_error=True) + client.database_admin_api = _FauxDatabaseAdminAPI( + _rpc_error=True) instance = _Instance(self.INSTANCE_NAME, client=client) pool = _Pool() database = self._make_one(self.DATABASE_ID, instance, pool=pool) - with self.assertRaises(GaxError): + with self.assertRaises(Unknown): database.exists() - name, options = api._got_database_ddl - self.assertEqual(name, self.DATABASE_NAME) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', database.name)]) - def test_exists_not_found(self): client = _Client() api = client.database_admin_api = _FauxDatabaseAdminAPI( @@ -405,10 +399,10 @@ def test_exists_not_found(self): self.assertFalse(database.exists()) - name, options = api._got_database_ddl + name, metadata = api._got_database_ddl self.assertEqual(name, self.DATABASE_NAME) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', database.name)]) + self.assertEqual( + metadata, [('google-cloud-resource-prefix', database.name)]) def test_exists_success(self): from google.cloud.spanner_admin_database_v1.proto import ( @@ -426,29 +420,24 @@ def test_exists_success(self): self.assertTrue(database.exists()) - name, options = api._got_database_ddl + name, metadata = api._got_database_ddl self.assertEqual(name, self.DATABASE_NAME) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', database.name)]) + self.assertEqual( + metadata, [('google-cloud-resource-prefix', database.name)]) def test_reload_grpc_error(self): - from google.gax.errors import GaxError + from google.api_core.exceptions import Unknown client = _Client() - api = client.database_admin_api = _FauxDatabaseAdminAPI( - _random_gax_error=True) + client.database_admin_api = _FauxDatabaseAdminAPI( + _rpc_error=True) instance = _Instance(self.INSTANCE_NAME, client=client) pool = _Pool() database = self._make_one(self.DATABASE_ID, instance, pool=pool) - with self.assertRaises(GaxError): + with self.assertRaises(Unknown): database.reload() - name, options = api._got_database_ddl - self.assertEqual(name, self.DATABASE_NAME) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', database.name)]) - def test_reload_not_found(self): from google.cloud.exceptions import NotFound @@ -462,10 +451,10 @@ def test_reload_not_found(self): with self.assertRaises(NotFound): database.reload() - name, options = api._got_database_ddl + name, metadata = api._got_database_ddl self.assertEqual(name, self.DATABASE_NAME) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', database.name)]) + self.assertEqual( + metadata, [('google-cloud-resource-prefix', database.name)]) def test_reload_success(self): from google.cloud.spanner_admin_database_v1.proto import ( @@ -485,32 +474,25 @@ def test_reload_success(self): self.assertEqual(database._ddl_statements, tuple(DDL_STATEMENTS)) - name, options = api._got_database_ddl + name, metadata = api._got_database_ddl self.assertEqual(name, self.DATABASE_NAME) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', database.name)]) + self.assertEqual( + metadata, [('google-cloud-resource-prefix', database.name)]) def test_update_ddl_grpc_error(self): - from google.gax.errors import GaxError + from google.api_core.exceptions import Unknown from tests._fixtures import DDL_STATEMENTS client = _Client() - api = client.database_admin_api = _FauxDatabaseAdminAPI( - _random_gax_error=True) + client.database_admin_api = _FauxDatabaseAdminAPI( + _rpc_error=True) instance = _Instance(self.INSTANCE_NAME, client=client) pool = _Pool() database = self._make_one(self.DATABASE_ID, instance, pool=pool) - with self.assertRaises(GaxError): + with self.assertRaises(Unknown): database.update_ddl(DDL_STATEMENTS) - name, statements, op_id, options = api._updated_database_ddl - self.assertEqual(name, self.DATABASE_NAME) - self.assertEqual(statements, DDL_STATEMENTS) - self.assertEqual(op_id, '') - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', database.name)]) - def test_update_ddl_not_found(self): from google.cloud.exceptions import NotFound from tests._fixtures import DDL_STATEMENTS @@ -525,12 +507,12 @@ def test_update_ddl_not_found(self): with self.assertRaises(NotFound): database.update_ddl(DDL_STATEMENTS) - name, statements, op_id, options = api._updated_database_ddl + name, statements, op_id, metadata = api._updated_database_ddl self.assertEqual(name, self.DATABASE_NAME) self.assertEqual(statements, DDL_STATEMENTS) self.assertEqual(op_id, '') - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', database.name)]) + self.assertEqual( + metadata, [('google-cloud-resource-prefix', database.name)]) def test_update_ddl(self): from tests._fixtures import DDL_STATEMENTS @@ -547,31 +529,26 @@ def test_update_ddl(self): self.assertIs(future, op_future) - name, statements, op_id, options = api._updated_database_ddl + name, statements, op_id, metadata = api._updated_database_ddl self.assertEqual(name, self.DATABASE_NAME) self.assertEqual(statements, DDL_STATEMENTS) self.assertEqual(op_id, '') - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', database.name)]) + self.assertEqual( + metadata, [('google-cloud-resource-prefix', database.name)]) def test_drop_grpc_error(self): - from google.gax.errors import GaxError + from google.api_core.exceptions import Unknown client = _Client() - api = client.database_admin_api = _FauxDatabaseAdminAPI( - _random_gax_error=True) + client.database_admin_api = _FauxDatabaseAdminAPI( + _rpc_error=True) instance = _Instance(self.INSTANCE_NAME, client=client) pool = _Pool() database = self._make_one(self.DATABASE_ID, instance, pool=pool) - with self.assertRaises(GaxError): + with self.assertRaises(Unknown): database.drop() - name, options = api._dropped_database - self.assertEqual(name, self.DATABASE_NAME) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', database.name)]) - def test_drop_not_found(self): from google.cloud.exceptions import NotFound @@ -585,10 +562,10 @@ def test_drop_not_found(self): with self.assertRaises(NotFound): database.drop() - name, options = api._dropped_database + name, metadata = api._dropped_database self.assertEqual(name, self.DATABASE_NAME) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', database.name)]) + self.assertEqual( + metadata, [('google-cloud-resource-prefix', database.name)]) def test_drop_success(self): from google.protobuf.empty_pb2 import Empty @@ -602,10 +579,10 @@ def test_drop_success(self): database.drop() - name, options = api._dropped_database + name, metadata = api._dropped_database self.assertEqual(name, self.DATABASE_NAME) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', database.name)]) + self.assertEqual( + metadata, [('google-cloud-resource-prefix', database.name)]) def test_session_factory(self): from google.cloud.spanner_v1.session import Session @@ -776,13 +753,13 @@ def test_context_mgr_success(self): self.assertIs(pool._session, session) self.assertEqual(batch.committed, now) (session_name, mutations, single_use_txn, - options) = api._committed + metadata) = api._committed self.assertIs(session_name, self.SESSION_NAME) self.assertEqual(mutations, []) self.assertIsInstance(single_use_txn, TransactionOptions) self.assertTrue(single_use_txn.HasField('read_write')) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', database.name)]) + self.assertEqual( + metadata, [('google-cloud-resource-prefix', database.name)]) def test_context_mgr_failure(self): from google.cloud.spanner_v1.batch import Batch @@ -944,69 +921,72 @@ class _FauxOperationFuture(object): pass -class _FauxSpannerClient(_GAXBaseAPI): +class _FauxSpannerClient(object): _committed = None + def __init__(self, **kwargs): + self.__dict__.update(**kwargs) + def commit(self, session, mutations, - transaction_id='', single_use_transaction=None, options=None): + transaction_id='', single_use_transaction=None, metadata=None): assert transaction_id == '' - self._committed = (session, mutations, single_use_transaction, options) + self._committed = ( + session, mutations, single_use_transaction, metadata) return self._commit_response -class _FauxDatabaseAdminAPI(_GAXBaseAPI): +class _FauxDatabaseAdminAPI(object): _create_database_conflict = False _database_not_found = False + _rpc_error = False - def _make_grpc_already_exists(self): - from grpc.beta.interfaces import StatusCode - - return self._make_grpc_error(StatusCode.ALREADY_EXISTS) + def __init__(self, **kwargs): + self.__dict__.update(**kwargs) def create_database(self, parent, create_statement, extra_statements=None, - options=None): - from google.gax.errors import GaxError + metadata=None): + from google.api_core.exceptions import AlreadyExists, NotFound, Unknown self._created_database = ( - parent, create_statement, extra_statements, options) - if self._random_gax_error: - raise GaxError('error') + parent, create_statement, extra_statements, metadata) + if self._rpc_error: + raise Unknown('error') if self._create_database_conflict: - raise GaxError('conflict', self._make_grpc_already_exists()) + raise AlreadyExists('conflict') if self._database_not_found: - raise GaxError('not found', self._make_grpc_not_found()) + raise NotFound('not found') return self._create_database_response - def get_database_ddl(self, database, options=None): - from google.gax.errors import GaxError + def get_database_ddl(self, database, metadata=None): + from google.api_core.exceptions import NotFound, Unknown - self._got_database_ddl = database, options - if self._random_gax_error: - raise GaxError('error') + self._got_database_ddl = database, metadata + if self._rpc_error: + raise Unknown('error') if self._database_not_found: - raise GaxError('not found', self._make_grpc_not_found()) + raise NotFound('not found') return self._get_database_ddl_response - def drop_database(self, database, options=None): - from google.gax.errors import GaxError + def drop_database(self, database, metadata=None): + from google.api_core.exceptions import NotFound, Unknown - self._dropped_database = database, options - if self._random_gax_error: - raise GaxError('error') + self._dropped_database = database, metadata + if self._rpc_error: + raise Unknown('error') if self._database_not_found: - raise GaxError('not found', self._make_grpc_not_found()) + raise NotFound('not found') return self._drop_database_response def update_database_ddl(self, database, statements, operation_id, - options=None): - from google.gax.errors import GaxError + metadata=None): + from google.api_core.exceptions import NotFound, Unknown self._updated_database_ddl = ( - database, statements, operation_id, options) - if self._random_gax_error: - raise GaxError('error') + database, statements, operation_id, metadata) + if self._rpc_error: + raise Unknown('error') if self._database_not_found: - raise GaxError('not found', self._make_grpc_not_found()) + raise NotFound('not found') return self._update_database_ddl_response diff --git a/spanner/tests/unit/test_instance.py b/spanner/tests/unit/test_instance.py index 6624d0ac050b..c15febadf7ca 100644 --- a/spanner/tests/unit/test_instance.py +++ b/spanner/tests/unit/test_instance.py @@ -14,7 +14,7 @@ import unittest -from google.cloud._testing import _GAXBaseAPI +import mock class TestInstance(unittest.TestCase): @@ -185,27 +185,17 @@ def test___ne__(self): self.assertNotEqual(instance1, instance2) def test_create_grpc_error(self): - from google.gax.errors import GaxError + from google.api_core.exceptions import Unknown client = _Client(self.PROJECT) - api = client.instance_admin_api = _FauxInstanceAdminAPI( - _random_gax_error=True) + client.instance_admin_api = _FauxInstanceAdminAPI( + _rpc_error=True) instance = self._make_one(self.INSTANCE_ID, client, configuration_name=self.CONFIG_NAME) - with self.assertRaises(GaxError): + with self.assertRaises(Unknown): instance.create() - (parent, instance_id, instance, options) = api._created_instance - self.assertEqual(parent, self.PARENT) - self.assertEqual(instance_id, self.INSTANCE_ID) - self.assertEqual(instance.name, self.INSTANCE_NAME) - self.assertEqual(instance.config, self.CONFIG_NAME) - self.assertEqual(instance.display_name, self.INSTANCE_ID) - self.assertEqual(instance.node_count, 1) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', instance.name)]) - def test_create_already_exists(self): from google.cloud.exceptions import Conflict @@ -218,15 +208,15 @@ def test_create_already_exists(self): with self.assertRaises(Conflict): instance.create() - (parent, instance_id, instance, options) = api._created_instance + (parent, instance_id, instance, metadata) = api._created_instance self.assertEqual(parent, self.PARENT) self.assertEqual(instance_id, self.INSTANCE_ID) self.assertEqual(instance.name, self.INSTANCE_NAME) self.assertEqual(instance.config, self.CONFIG_NAME) self.assertEqual(instance.display_name, self.INSTANCE_ID) self.assertEqual(instance.node_count, 1) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', instance.name)]) + self.assertEqual( + metadata, [('google-cloud-resource-prefix', instance.name)]) def test_create_success(self): op_future = _FauxOperationFuture() @@ -242,32 +232,27 @@ def test_create_success(self): self.assertIs(future, op_future) - (parent, instance_id, instance, options) = api._created_instance + (parent, instance_id, instance, metadata) = api._created_instance self.assertEqual(parent, self.PARENT) self.assertEqual(instance_id, self.INSTANCE_ID) self.assertEqual(instance.name, self.INSTANCE_NAME) self.assertEqual(instance.config, self.CONFIG_NAME) self.assertEqual(instance.display_name, self.DISPLAY_NAME) self.assertEqual(instance.node_count, self.NODE_COUNT) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', instance.name)]) + self.assertEqual( + metadata, [('google-cloud-resource-prefix', instance.name)]) def test_exists_instance_grpc_error(self): - from google.gax.errors import GaxError + from google.api_core.exceptions import Unknown client = _Client(self.PROJECT) - api = client.instance_admin_api = _FauxInstanceAdminAPI( - _random_gax_error=True) + client.instance_admin_api = _FauxInstanceAdminAPI( + _rpc_error=True) instance = self._make_one(self.INSTANCE_ID, client, self.CONFIG_NAME) - with self.assertRaises(GaxError): + with self.assertRaises(Unknown): instance.exists() - name, options = api._got_instance - self.assertEqual(name, self.INSTANCE_NAME) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', instance.name)]) - def test_exists_instance_not_found(self): client = _Client(self.PROJECT) api = client.instance_admin_api = _FauxInstanceAdminAPI( @@ -277,10 +262,10 @@ def test_exists_instance_not_found(self): self.assertFalse(instance.exists()) - name, options = api._got_instance + name, metadata = api._got_instance self.assertEqual(name, self.INSTANCE_NAME) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', instance.name)]) + self.assertEqual( + metadata, [('google-cloud-resource-prefix', instance.name)]) def test_exists_success(self): from google.cloud.spanner_admin_instance_v1.proto import ( @@ -299,27 +284,22 @@ def test_exists_success(self): self.assertTrue(instance.exists()) - name, options = api._got_instance + name, metadata = api._got_instance self.assertEqual(name, self.INSTANCE_NAME) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', instance.name)]) + self.assertEqual( + metadata, [('google-cloud-resource-prefix', instance.name)]) def test_reload_instance_grpc_error(self): - from google.gax.errors import GaxError + from google.api_core.exceptions import Unknown client = _Client(self.PROJECT) - api = client.instance_admin_api = _FauxInstanceAdminAPI( - _random_gax_error=True) + client.instance_admin_api = _FauxInstanceAdminAPI( + _rpc_error=True) instance = self._make_one(self.INSTANCE_ID, client, self.CONFIG_NAME) - with self.assertRaises(GaxError): + with self.assertRaises(Unknown): instance.reload() - name, options = api._got_instance - self.assertEqual(name, self.INSTANCE_NAME) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', instance.name)]) - def test_reload_instance_not_found(self): from google.cloud.exceptions import NotFound @@ -332,10 +312,10 @@ def test_reload_instance_not_found(self): with self.assertRaises(NotFound): instance.reload() - name, options = api._got_instance + name, metadata = api._got_instance self.assertEqual(name, self.INSTANCE_NAME) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', instance.name)]) + self.assertEqual( + metadata, [('google-cloud-resource-prefix', instance.name)]) def test_reload_success(self): from google.cloud.spanner_admin_instance_v1.proto import ( @@ -358,34 +338,23 @@ def test_reload_success(self): self.assertEqual(instance.node_count, self.NODE_COUNT) self.assertEqual(instance.display_name, self.DISPLAY_NAME) - name, options = api._got_instance + name, metadata = api._got_instance self.assertEqual(name, self.INSTANCE_NAME) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', instance.name)]) + self.assertEqual( + metadata, [('google-cloud-resource-prefix', instance.name)]) def test_update_grpc_error(self): - from google.gax.errors import GaxError - from google.cloud.spanner_v1.instance import DEFAULT_NODE_COUNT + from google.api_core.exceptions import Unknown client = _Client(self.PROJECT) - api = client.instance_admin_api = _FauxInstanceAdminAPI( - _random_gax_error=True) + client.instance_admin_api = _FauxInstanceAdminAPI( + _rpc_error=True) instance = self._make_one(self.INSTANCE_ID, client, configuration_name=self.CONFIG_NAME) - with self.assertRaises(GaxError): + with self.assertRaises(Unknown): instance.update() - instance, field_mask, options = api._updated_instance - self.assertEqual(field_mask.paths, - ['config', 'display_name', 'node_count']) - self.assertEqual(instance.name, self.INSTANCE_NAME) - self.assertEqual(instance.config, self.CONFIG_NAME) - self.assertEqual(instance.display_name, self.INSTANCE_ID) - self.assertEqual(instance.node_count, DEFAULT_NODE_COUNT) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', instance.name)]) - def test_update_not_found(self): from google.cloud.exceptions import NotFound from google.cloud.spanner_v1.instance import DEFAULT_NODE_COUNT @@ -399,15 +368,15 @@ def test_update_not_found(self): with self.assertRaises(NotFound): instance.update() - instance, field_mask, options = api._updated_instance + instance, field_mask, metadata = api._updated_instance self.assertEqual(field_mask.paths, ['config', 'display_name', 'node_count']) self.assertEqual(instance.name, self.INSTANCE_NAME) self.assertEqual(instance.config, self.CONFIG_NAME) self.assertEqual(instance.display_name, self.INSTANCE_ID) self.assertEqual(instance.node_count, DEFAULT_NODE_COUNT) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', instance.name)]) + self.assertEqual( + metadata, [('google-cloud-resource-prefix', instance.name)]) def test_update_success(self): op_future = _FauxOperationFuture() @@ -423,32 +392,27 @@ def test_update_success(self): self.assertIs(future, op_future) - instance, field_mask, options = api._updated_instance + instance, field_mask, metadata = api._updated_instance self.assertEqual(field_mask.paths, ['config', 'display_name', 'node_count']) self.assertEqual(instance.name, self.INSTANCE_NAME) self.assertEqual(instance.config, self.CONFIG_NAME) self.assertEqual(instance.display_name, self.DISPLAY_NAME) self.assertEqual(instance.node_count, self.NODE_COUNT) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', instance.name)]) + self.assertEqual( + metadata, [('google-cloud-resource-prefix', instance.name)]) def test_delete_grpc_error(self): - from google.gax.errors import GaxError + from google.api_core.exceptions import Unknown client = _Client(self.PROJECT) - api = client.instance_admin_api = _FauxInstanceAdminAPI( - _random_gax_error=True) + client.instance_admin_api = _FauxInstanceAdminAPI( + _rpc_error=True) instance = self._make_one(self.INSTANCE_ID, client) - with self.assertRaises(GaxError): + with self.assertRaises(Unknown): instance.delete() - name, options = api._deleted_instance - self.assertEqual(name, self.INSTANCE_NAME) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', instance.name)]) - def test_delete_not_found(self): from google.cloud.exceptions import NotFound @@ -460,10 +424,10 @@ def test_delete_not_found(self): with self.assertRaises(NotFound): instance.delete() - name, options = api._deleted_instance + name, metadata = api._deleted_instance self.assertEqual(name, self.INSTANCE_NAME) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', instance.name)]) + self.assertEqual( + metadata, [('google-cloud-resource-prefix', instance.name)]) def test_delete_success(self): from google.protobuf.empty_pb2 import Empty @@ -475,10 +439,10 @@ def test_delete_success(self): instance.delete() - name, options = api._deleted_instance + name, metadata = api._deleted_instance self.assertEqual(name, self.INSTANCE_NAME) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', instance.name)]) + self.assertEqual( + metadata, [('google-cloud-resource-prefix', instance.name)]) def test_database_factory_defaults(self): from google.cloud.spanner_v1.database import Database @@ -517,66 +481,76 @@ def test_database_factory_explicit(self): self.assertIs(database._pool, pool) self.assertIs(pool._bound, database) - def test_list_databases_wo_paging(self): - from google.cloud._testing import _GAXPageIterator - from google.gax import INITIAL_PAGE + def test_list_databases(self): + from google.cloud.spanner_admin_database_v1.gapic import ( + database_admin_client) + from google.cloud.spanner_admin_database_v1.proto import ( + spanner_database_admin_pb2) from google.cloud.spanner_v1.database import Database - NEXT_TOKEN = 'TOKEN' - database_pb = _DatabasePB(name=self.DATABASE_NAME) - response = _GAXPageIterator([database_pb], page_token=NEXT_TOKEN) + api = database_admin_client.DatabaseAdminClient(mock.Mock()) client = _Client(self.PROJECT) - api = client.database_admin_api = _FauxDatabaseAdminAPI() - api._list_databases_response = response + client.database_admin_api = api instance = self._make_one(self.INSTANCE_ID, client) - iterator = instance.list_databases() - next_token = iterator.next_page_token - databases = list(iterator) + databases_pb = spanner_database_admin_pb2.ListDatabasesResponse( + databases=[ + spanner_database_admin_pb2.Database( + name='{}/databases/aa'.format(self.INSTANCE_NAME)), + spanner_database_admin_pb2.Database( + name='{}/databases/bb'.format(self.INSTANCE_NAME)) + ] + ) - self.assertEqual(len(databases), 1) - database = databases[0] - self.assertTrue(isinstance(database, Database)) - self.assertEqual(database.name, self.DATABASE_NAME) - self.assertEqual(next_token, NEXT_TOKEN) - - instance_name, page_size, options = api._listed_databases - self.assertEqual(instance_name, self.INSTANCE_NAME) - self.assertEqual(page_size, None) - self.assertIs(options.page_token, INITIAL_PAGE) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', instance.name)]) - - def test_list_databases_w_paging(self): - from google.cloud._testing import _GAXPageIterator - from google.cloud.spanner_v1.database import Database + api._list_databases = mock.Mock(return_value=databases_pb) + + response = instance.list_databases() + databases = list(response) + + self.assertIsInstance(databases[0], Database) + self.assertTrue(databases[0].name.endswith('/aa')) + self.assertTrue(databases[1].name.endswith('/bb')) + + api._list_databases.assert_called_once_with( + spanner_database_admin_pb2.ListDatabasesRequest( + parent=self.INSTANCE_NAME), + metadata=[('google-cloud-resource-prefix', instance.name)], + retry=mock.ANY, + timeout=mock.ANY) + + def test_list_databases_w_options(self): + from google.cloud.spanner_admin_database_v1.gapic import ( + database_admin_client) + from google.cloud.spanner_admin_database_v1.proto import ( + spanner_database_admin_pb2) - SIZE = 15 - TOKEN = 'TOKEN' - database_pb = _DatabasePB(name=self.DATABASE_NAME) - response = _GAXPageIterator([database_pb]) + api = database_admin_client.DatabaseAdminClient(mock.Mock()) client = _Client(self.PROJECT) - api = client.database_admin_api = _FauxDatabaseAdminAPI() - api._list_databases_response = response + client.database_admin_api = api instance = self._make_one(self.INSTANCE_ID, client) - iterator = instance.list_databases( - page_size=SIZE, page_token=TOKEN) - next_token = iterator.next_page_token - databases = list(iterator) + databases_pb = spanner_database_admin_pb2.ListDatabasesResponse( + databases=[] + ) - self.assertEqual(len(databases), 1) - database = databases[0] - self.assertTrue(isinstance(database, Database)) - self.assertEqual(database.name, self.DATABASE_NAME) - self.assertEqual(next_token, None) + api._list_databases = mock.Mock(return_value=databases_pb) + + page_size = 42 + page_token = 'token' + response = instance.list_databases( + page_size=page_size, page_token=page_token) + databases = list(response) - instance_name, page_size, options = api._listed_databases - self.assertEqual(instance_name, self.INSTANCE_NAME) - self.assertEqual(page_size, SIZE) - self.assertEqual(options.page_token, TOKEN) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', instance.name)]) + self.assertEqual(databases, []) + + api._list_databases.assert_called_once_with( + spanner_database_admin_pb2.ListDatabasesRequest( + parent=self.INSTANCE_NAME, + page_size=page_size, + page_token=page_token), + metadata=[('google-cloud-resource-prefix', instance.name)], + retry=mock.ANY, + timeout=mock.ANY) class _Client(object): @@ -597,70 +571,56 @@ def __eq__(self, other): other.timeout_seconds == self.timeout_seconds) -class _DatabasePB(object): - - def __init__(self, name): - self.name = name - - -class _FauxInstanceAdminAPI(_GAXBaseAPI): +class _FauxInstanceAdminAPI(object): _create_instance_conflict = False _instance_not_found = False + _rpc_error = False - def _make_grpc_already_exists(self): - from grpc.beta.interfaces import StatusCode - - return self._make_grpc_error(StatusCode.ALREADY_EXISTS) + def __init__(self, **kwargs): + self.__dict__.update(**kwargs) - def create_instance(self, parent, instance_id, instance, options=None): - from google.gax.errors import GaxError + def create_instance(self, parent, instance_id, instance, metadata=None): + from google.api_core.exceptions import AlreadyExists, Unknown - self._created_instance = (parent, instance_id, instance, options) - if self._random_gax_error: - raise GaxError('error') + self._created_instance = (parent, instance_id, instance, metadata) + if self._rpc_error: + raise Unknown('error') if self._create_instance_conflict: - raise GaxError('conflict', self._make_grpc_already_exists()) + raise AlreadyExists('conflict') return self._create_instance_response - def get_instance(self, name, options=None): - from google.gax.errors import GaxError + def get_instance(self, name, metadata=None): + from google.api_core.exceptions import NotFound, Unknown - self._got_instance = (name, options) - if self._random_gax_error: - raise GaxError('error') + self._got_instance = (name, metadata) + if self._rpc_error: + raise Unknown('error') if self._instance_not_found: - raise GaxError('not found', self._make_grpc_not_found()) + raise NotFound('error') return self._get_instance_response - def update_instance(self, instance, field_mask, options=None): - from google.gax.errors import GaxError + def update_instance(self, instance, field_mask, metadata=None): + from google.api_core.exceptions import NotFound, Unknown - self._updated_instance = (instance, field_mask, options) - if self._random_gax_error: - raise GaxError('error') + self._updated_instance = (instance, field_mask, metadata) + if self._rpc_error: + raise Unknown('error') if self._instance_not_found: - raise GaxError('not found', self._make_grpc_not_found()) + raise NotFound('error') return self._update_instance_response - def delete_instance(self, name, options=None): - from google.gax.errors import GaxError + def delete_instance(self, name, metadata=None): + from google.api_core.exceptions import NotFound, Unknown - self._deleted_instance = name, options - if self._random_gax_error: - raise GaxError('error') + self._deleted_instance = name, metadata + if self._rpc_error: + raise Unknown('error') if self._instance_not_found: - raise GaxError('not found', self._make_grpc_not_found()) + raise NotFound('error') return self._delete_instance_response -class _FauxDatabaseAdminAPI(object): - - def list_databases(self, name, page_size, options): - self._listed_databases = (name, page_size, options) - return self._list_databases_response - - class _FauxOperationFuture(object): pass diff --git a/spanner/tests/unit/test_session.py b/spanner/tests/unit/test_session.py index e914d921aa5f..096c0cdd7cb2 100644 --- a/spanner/tests/unit/test_session.py +++ b/spanner/tests/unit/test_session.py @@ -15,7 +15,15 @@ import unittest -from google.cloud._testing import _GAXBaseAPI +import mock + + +def _make_rpc_error(error_cls, trailing_metadata=None): + import grpc + + grpc_error = mock.create_autospec(grpc.Call, instance=True) + grpc_error.trailing_metadata.return_value = trailing_metadata + raise error_cls('error', errors=(grpc_error,)) class TestSession(unittest.TestCase): @@ -80,27 +88,22 @@ def test_create_ok(self): self.assertEqual(session.session_id, self.SESSION_ID) - database_name, options = gax_api._create_session_called_with + database_name, metadata = gax_api._create_session_called_with self.assertEqual(database_name, self.DATABASE_NAME) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', database.name)]) + self.assertEqual( + metadata, [('google-cloud-resource-prefix', database.name)]) def test_create_error(self): - from google.gax.errors import GaxError + from google.api_core.exceptions import Unknown - gax_api = _SpannerApi(_random_gax_error=True) + gax_api = _SpannerApi(_rpc_error=Unknown('error')) database = _Database(self.DATABASE_NAME) database.spanner_api = gax_api session = self._make_one(database) - with self.assertRaises(GaxError): + with self.assertRaises(Unknown): session.create() - database_name, options = gax_api._create_session_called_with - self.assertEqual(database_name, self.DATABASE_NAME) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', database.name)]) - def test_exists_wo_session_id(self): database = _Database(self.DATABASE_NAME) session = self._make_one(database) @@ -116,10 +119,10 @@ def test_exists_hit(self): self.assertTrue(session.exists()) - session_name, options = gax_api._get_session_called_with + session_name, metadata = gax_api._get_session_called_with self.assertEqual(session_name, self.SESSION_NAME) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', database.name)]) + self.assertEqual( + metadata, [('google-cloud-resource-prefix', database.name)]) def test_exists_miss(self): gax_api = _SpannerApi() @@ -130,28 +133,23 @@ def test_exists_miss(self): self.assertFalse(session.exists()) - session_name, options = gax_api._get_session_called_with + session_name, metadata = gax_api._get_session_called_with self.assertEqual(session_name, self.SESSION_NAME) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', database.name)]) + self.assertEqual( + metadata, [('google-cloud-resource-prefix', database.name)]) def test_exists_error(self): - from google.gax.errors import GaxError + from google.api_core.exceptions import Unknown - gax_api = _SpannerApi(_random_gax_error=True) + gax_api = _SpannerApi(_rpc_error=Unknown('error')) database = _Database(self.DATABASE_NAME) database.spanner_api = gax_api session = self._make_one(database) session._session_id = self.SESSION_ID - with self.assertRaises(GaxError): + with self.assertRaises(Unknown): session.exists() - session_name, options = gax_api._get_session_called_with - self.assertEqual(session_name, self.SESSION_NAME) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', database.name)]) - def test_delete_wo_session_id(self): database = _Database(self.DATABASE_NAME) session = self._make_one(database) @@ -167,10 +165,10 @@ def test_delete_hit(self): session.delete() - session_name, options = gax_api._delete_session_called_with + session_name, metadata = gax_api._delete_session_called_with self.assertEqual(session_name, self.SESSION_NAME) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', database.name)]) + self.assertEqual( + metadata, [('google-cloud-resource-prefix', database.name)]) def test_delete_miss(self): from google.cloud.exceptions import NotFound @@ -184,28 +182,23 @@ def test_delete_miss(self): with self.assertRaises(NotFound): session.delete() - session_name, options = gax_api._delete_session_called_with + session_name, metadata = gax_api._delete_session_called_with self.assertEqual(session_name, self.SESSION_NAME) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', database.name)]) + self.assertEqual( + metadata, [('google-cloud-resource-prefix', database.name)]) def test_delete_error(self): - from google.gax.errors import GaxError + from google.api_core.exceptions import Unknown - gax_api = _SpannerApi(_random_gax_error=True) + gax_api = _SpannerApi(_rpc_error=Unknown('error')) database = _Database(self.DATABASE_NAME) database.spanner_api = gax_api session = self._make_one(database) session._session_id = self.SESSION_ID - with self.assertRaises(GaxError): + with self.assertRaises(Unknown): session.delete() - session_name, options = gax_api._delete_session_called_with - self.assertEqual(session_name, self.SESSION_NAME) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', database.name)]) - def test_snapshot_not_created(self): database = _Database(self.DATABASE_NAME) session = self._make_one(database) @@ -439,8 +432,8 @@ def unit_of_work(txn, *args, **kw): self.assertEqual(args, ()) self.assertEqual(kw, {}) - def test_run_in_transaction_callback_raises_gax_error_non_abort(self): - from google.gax.errors import GaxError + def test_run_in_transaction_callback_raises_non_abort_rpc_error(self): + from google.api_core.exceptions import Cancelled from google.cloud.spanner_v1.proto.transaction_pb2 import ( Transaction as TransactionPB) from google.cloud.spanner_v1.transaction import Transaction @@ -464,15 +457,12 @@ def test_run_in_transaction_callback_raises_gax_error_non_abort(self): called_with = [] - class Testing(GaxError): - pass - def unit_of_work(txn, *args, **kw): called_with.append((txn, args, kw)) txn.insert(TABLE_NAME, COLUMNS, VALUES) - raise Testing('testing') + raise Cancelled('error') - with self.assertRaises(Testing): + with self.assertRaises(Cancelled): session.run_in_transaction(unit_of_work) self.assertIsNone(session._transaction) @@ -532,7 +522,7 @@ def unit_of_work(txn, *args, **kw): self.assertEqual(kw, {'some_arg': 'def'}) def test_run_in_transaction_w_commit_error(self): - from google.gax.errors import GaxError + from google.api_core.exceptions import Unknown from google.cloud.spanner_v1.transaction import Transaction TABLE_NAME = 'citizens' @@ -542,8 +532,7 @@ def test_run_in_transaction_w_commit_error(self): ['bharney@example.com', 'Bharney', 'Rhubble', 31], ] gax_api = _SpannerApi( - _commit_error=True, - ) + _commit_error=True) database = _Database(self.DATABASE_NAME) database.spanner_api = gax_api session = self._make_one(database) @@ -551,13 +540,15 @@ def test_run_in_transaction_w_commit_error(self): begun_txn = session._transaction = Transaction(session) begun_txn._transaction_id = b'FACEDACE' + assert session._transaction._transaction_id + called_with = [] def unit_of_work(txn, *args, **kw): called_with.append((txn, args, kw)) txn.insert(TABLE_NAME, COLUMNS, VALUES) - with self.assertRaises(GaxError): + with self.assertRaises(Unknown): session.run_in_transaction(unit_of_work) self.assertIsNone(session._transaction) @@ -676,8 +667,7 @@ def unit_of_work(txn, *args, **kw): def test_run_in_transaction_w_callback_raises_abort_wo_metadata(self): import datetime - from google.gax.errors import GaxError - from grpc import StatusCode + from google.api_core.exceptions import Aborted from google.cloud.spanner_v1.proto.spanner_pb2 import CommitResponse from google.cloud.spanner_v1.proto.transaction_pb2 import ( Transaction as TransactionPB) @@ -716,10 +706,8 @@ def test_run_in_transaction_w_callback_raises_abort_wo_metadata(self): def unit_of_work(txn, *args, **kw): called_with.append((txn, args, kw)) if len(called_with) < 2: - grpc_error = gax_api._make_grpc_error( - StatusCode.ABORTED, - trailing=gax_api._trailing_metadata()) - raise GaxError('conflict', grpc_error) + raise _make_rpc_error( + Aborted, gax_api._trailing_metadata()) txn.insert(TABLE_NAME, COLUMNS, VALUES) time_module = _FauxTimeModule() @@ -741,15 +729,12 @@ def unit_of_work(txn, *args, **kw): def test_run_in_transaction_w_abort_w_retry_metadata_deadline(self): import datetime - from google.gax.errors import GaxError - from google.gax.grpc import exc_to_code - from grpc import StatusCode + from google.api_core.exceptions import Aborted from google.cloud.spanner_v1.proto.spanner_pb2 import CommitResponse from google.cloud.spanner_v1.proto.transaction_pb2 import ( Transaction as TransactionPB) from google.cloud._helpers import UTC from google.cloud._helpers import _datetime_to_pb_timestamp - from google.cloud.spanner_v1.transaction import Transaction from google.cloud.spanner_v1 import session as MUT from google.cloud._testing import _Monkey @@ -785,29 +770,22 @@ def unit_of_work(txn, *args, **kw): txn.insert(TABLE_NAME, COLUMNS, VALUES) time_module = _FauxTimeModule() + time_module._times = [1, 1.5] with _Monkey(MUT, time=time_module): - with self.assertRaises(GaxError) as exc: + with self.assertRaises(Aborted): session.run_in_transaction( - unit_of_work, 'abc', some_arg='def', timeout_secs=0.01) + unit_of_work, 'abc', timeout_secs=1) - self.assertEqual(exc_to_code(exc.exception.cause), StatusCode.ABORTED) self.assertIsNone(time_module._slept) self.assertEqual(len(called_with), 1) - txn, args, kw = called_with[0] - self.assertIsInstance(txn, Transaction) - self.assertIsNone(txn.committed) - self.assertEqual(args, ('abc',)) - self.assertEqual(kw, {'some_arg': 'def'}) def test_run_in_transaction_w_timeout(self): + from google.api_core.exceptions import Aborted from google.cloud.spanner_v1 import session as MUT from google.cloud._testing import _Monkey - from google.gax.errors import GaxError - from google.gax.grpc import exc_to_code from google.cloud.spanner_v1.proto.transaction_pb2 import ( Transaction as TransactionPB) - from grpc import StatusCode from google.cloud.spanner_v1.transaction import Transaction TABLE_NAME = 'citizens' @@ -837,11 +815,9 @@ def unit_of_work(txn, *args, **kw): time_module._times = [1, 1.5, 2.5] # retry once w/ timeout_secs=1 with _Monkey(MUT, time=time_module): - with self.assertRaises(GaxError) as exc: + with self.assertRaises(Aborted): session.run_in_transaction(unit_of_work, timeout_secs=1) - self.assertEqual(exc_to_code(exc.exception.cause), StatusCode.ABORTED) - self.assertEqual(time_module._slept, None) self.assertEqual(len(called_with), 2) for txn, args, kw in called_with: @@ -857,43 +833,48 @@ def __init__(self, name): self.name = name -class _SpannerApi(_GAXBaseAPI): +class _SpannerApi(object): _commit_abort_count = 0 _commit_abort_retry_seconds = None _commit_abort_retry_nanos = None - _random_gax_error = _commit_error = False + _commit_error = False + _rpc_error = None - def create_session(self, database, options=None): - from google.gax.errors import GaxError + def __init__(self, **kwargs): + self.__dict__.update(**kwargs) - self._create_session_called_with = database, options - if self._random_gax_error: - raise GaxError('error') + def create_session(self, database, metadata=None): + if self._rpc_error is not None: + raise self._rpc_error + + self._create_session_called_with = database, metadata return self._create_session_response - def get_session(self, name, options=None): - from google.gax.errors import GaxError + def get_session(self, name, metadata=None): + from google.api_core.exceptions import NotFound + + if self._rpc_error is not None: + raise self._rpc_error - self._get_session_called_with = name, options - if self._random_gax_error: - raise GaxError('error') + self._get_session_called_with = name, metadata try: return self._get_session_response except AttributeError: - raise GaxError('miss', self._make_grpc_not_found()) + raise NotFound('miss') + + def delete_session(self, name, metadata=None): + from google.api_core.exceptions import NotFound - def delete_session(self, name, options=None): - from google.gax.errors import GaxError + if self._rpc_error is not None: + raise self._rpc_error - self._delete_session_called_with = name, options - if self._random_gax_error: - raise GaxError('error') + self._delete_session_called_with = name, metadata if not self._delete_session_ok: - raise GaxError('miss', self._make_grpc_not_found()) + raise NotFound('miss') - def begin_transaction(self, session, options_, options=None): - self._begun = (session, options_, options) + def begin_transaction(self, session, options_, metadata=None): + self._begun = (session, options_, metadata) return self._begin_transaction_response def _trailing_metadata(self): @@ -912,23 +893,21 @@ def _trailing_metadata(self): ] def commit(self, session, mutations, - transaction_id='', single_use_transaction=None, options=None): - from grpc import StatusCode - from google.gax.errors import GaxError + transaction_id='', single_use_transaction=None, metadata=None): + from google.api_core.exceptions import Unknown, Aborted assert single_use_transaction is None - self._committed = (session, mutations, transaction_id, options) + self._committed = (session, mutations, transaction_id, metadata) if self._commit_error: - raise GaxError('error', self._make_grpc_error(StatusCode.UNKNOWN)) + raise Unknown('error') if self._commit_abort_count > 0: self._commit_abort_count -= 1 - grpc_error = self._make_grpc_error( - StatusCode.ABORTED, trailing=self._trailing_metadata()) - raise GaxError('conflict', grpc_error) + raise _make_rpc_error( + Aborted, trailing_metadata=self._trailing_metadata()) return self._commit_response - def rollback(self, session, transaction_id, options=None): - self._rolled_back = (session, transaction_id, options) + def rollback(self, session, transaction_id, metadata=None): + self._rolled_back = (session, transaction_id, metadata) return self._rollback_response diff --git a/spanner/tests/unit/test_snapshot.py b/spanner/tests/unit/test_snapshot.py index d98b844338d7..58637fbaecb3 100644 --- a/spanner/tests/unit/test_snapshot.py +++ b/spanner/tests/unit/test_snapshot.py @@ -17,8 +17,6 @@ import mock -from google.cloud._testing import _GAXBaseAPI - TABLE_NAME = 'citizens' COLUMNS = ['email', 'first_name', 'last_name', 'age'] @@ -151,6 +149,13 @@ def _make_txn_selector(self): return _Derived(session) + def _make_spanner_api(self): + import google.cloud.spanner_v1.gapic.spanner_client + + return mock.create_autospec( + google.cloud.spanner_v1.gapic.spanner_client.SpannerClient, + instance=True) + def test_ctor(self): session = _Session() base = self._make_one(session) @@ -162,37 +167,21 @@ def test__make_txn_selector_virtual(self): with self.assertRaises(NotImplementedError): base._make_txn_selector() - def test_read_grpc_error(self): + def test_read_other_error(self): from google.cloud.spanner_v1.proto.transaction_pb2 import ( TransactionSelector) - from google.gax.errors import GaxError from google.cloud.spanner_v1.keyset import KeySet KEYSET = KeySet(all_=True) database = _Database() - api = database.spanner_api = _FauxSpannerAPI( - _random_gax_error=True) + database.spanner_api = self._make_spanner_api() + database.spanner_api.streaming_read.side_effect = RuntimeError() session = _Session(database) derived = self._makeDerived(session) - with self.assertRaises(GaxError): + with self.assertRaises(RuntimeError): list(derived.read(TABLE_NAME, COLUMNS, KEYSET)) - (r_session, table, columns, key_set, transaction, index, - limit, resume_token, options) = api._streaming_read_with - - self.assertEqual(r_session, self.SESSION_NAME) - self.assertTrue(transaction.single_use.read_only.strong) - self.assertEqual(table, TABLE_NAME) - self.assertEqual(columns, COLUMNS) - self.assertEqual(key_set, KEYSET.to_pb()) - self.assertIsInstance(transaction, TransactionSelector) - self.assertEqual(index, '') - self.assertEqual(limit, 0) - self.assertEqual(resume_token, b'') - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', database.name)]) - def _read_helper(self, multi_use, first=True, count=0): from google.protobuf.struct_pb2 import Struct from google.cloud.spanner_v1.proto.result_set_pb2 import ( @@ -257,7 +246,7 @@ def _read_helper(self, multi_use, first=True, count=0): self.assertEqual(result_set.stats, stats_pb) (r_session, table, columns, key_set, transaction, index, - limit, resume_token, options) = api._streaming_read_with + limit, resume_token, metadata) = api._streaming_read_with self.assertEqual(r_session, self.SESSION_NAME) self.assertEqual(table, TABLE_NAME) @@ -274,8 +263,8 @@ def _read_helper(self, multi_use, first=True, count=0): self.assertEqual(index, INDEX) self.assertEqual(limit, LIMIT) self.assertEqual(resume_token, b'') - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', database.name)]) + self.assertEqual( + metadata, [('google-cloud-resource-prefix', database.name)]) def test_read_wo_multi_use(self): self._read_helper(multi_use=False) @@ -297,34 +286,19 @@ def test_read_w_multi_use_w_first_w_count_gt_0(self): with self.assertRaises(ValueError): self._read_helper(multi_use=True, first=True, count=1) - def test_execute_sql_grpc_error(self): + def test_execute_sql_other_error(self): from google.cloud.spanner_v1.proto.transaction_pb2 import ( TransactionSelector) - from google.gax.errors import GaxError database = _Database() - api = database.spanner_api = _FauxSpannerAPI( - _random_gax_error=True) + database.spanner_api = self._make_spanner_api() + database.spanner_api.execute_streaming_sql.side_effect = RuntimeError() session = _Session(database) derived = self._makeDerived(session) - with self.assertRaises(GaxError): + with self.assertRaises(RuntimeError): list(derived.execute_sql(SQL_QUERY)) - (r_session, sql, transaction, params, param_types, - resume_token, query_mode, options) = api._executed_streaming_sql_with - - self.assertEqual(r_session, self.SESSION_NAME) - self.assertEqual(sql, SQL_QUERY) - self.assertIsInstance(transaction, TransactionSelector) - self.assertTrue(transaction.single_use.read_only.strong) - self.assertEqual(params, None) - self.assertEqual(param_types, None) - self.assertEqual(resume_token, b'') - self.assertEqual(query_mode, None) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', database.name)]) - def test_execute_sql_w_params_wo_param_types(self): database = _Database() session = _Session(database) @@ -395,7 +369,7 @@ def _execute_sql_helper(self, multi_use, first=True, count=0): self.assertEqual(result_set.stats, stats_pb) (r_session, sql, transaction, params, param_types, - resume_token, query_mode, options) = api._executed_streaming_sql_with + resume_token, query_mode, metadata) = api._executed_streaming_sql_with self.assertEqual(r_session, self.SESSION_NAME) self.assertEqual(sql, SQL_QUERY_WITH_PARAM) @@ -413,8 +387,8 @@ def _execute_sql_helper(self, multi_use, first=True, count=0): self.assertEqual(param_types, PARAM_TYPES) self.assertEqual(query_mode, MODE) self.assertEqual(resume_token, b'') - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', database.name)]) + self.assertEqual( + metadata, [('google-cloud-resource-prefix', database.name)]) def test_execute_sql_wo_multi_use(self): self._execute_sql_helper(multi_use=False) @@ -455,6 +429,13 @@ def _getTargetClass(self): def _make_one(self, *args, **kwargs): return self._getTargetClass()(*args, **kwargs) + def _make_spanner_api(self): + import google.cloud.spanner_v1.gapic.spanner_client + + return mock.create_autospec( + google.cloud.spanner_v1.gapic.spanner_client.SpannerClient, + instance=True) + def _makeTimestamp(self): import datetime from google.cloud._helpers import UTC @@ -692,29 +673,18 @@ def test_begin_w_existing_txn_id(self): with self.assertRaises(ValueError): snapshot.begin() - def test_begin_w_gax_error(self): - from google.gax.errors import GaxError - from google.cloud._helpers import _pb_timestamp_to_datetime - + def test_begin_w_other_error(self): database = _Database() - api = database.spanner_api = _FauxSpannerAPI( - _random_gax_error=True) + database.spanner_api = self._make_spanner_api() + database.spanner_api.begin_transaction.side_effect = RuntimeError() timestamp = self._makeTimestamp() session = _Session(database) snapshot = self._make_one( session, read_timestamp=timestamp, multi_use=True) - with self.assertRaises(GaxError): + with self.assertRaises(RuntimeError): snapshot.begin() - session_id, txn_options, options = api._begun - self.assertEqual(session_id, session.name) - self.assertEqual( - _pb_timestamp_to_datetime(txn_options.read_only.read_timestamp), - timestamp) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', database.name)]) - def test_begin_ok_exact_staleness(self): from google.cloud.spanner_v1.proto.transaction_pb2 import ( Transaction as TransactionPB) @@ -733,13 +703,13 @@ def test_begin_ok_exact_staleness(self): self.assertEqual(txn_id, self.TRANSACTION_ID) self.assertEqual(snapshot._transaction_id, self.TRANSACTION_ID) - session_id, txn_options, options = api._begun + session_id, txn_options, metadata = api._begun self.assertEqual(session_id, session.name) read_only = txn_options.read_only self.assertEqual(read_only.exact_staleness.seconds, 3) self.assertEqual(read_only.exact_staleness.nanos, 123456000) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', database.name)]) + self.assertEqual( + metadata, [('google-cloud-resource-prefix', database.name)]) def test_begin_ok_exact_strong(self): from google.cloud.spanner_v1.proto.transaction_pb2 import ( @@ -757,11 +727,11 @@ def test_begin_ok_exact_strong(self): self.assertEqual(txn_id, self.TRANSACTION_ID) self.assertEqual(snapshot._transaction_id, self.TRANSACTION_ID) - session_id, txn_options, options = api._begun + session_id, txn_options, metadata = api._begun self.assertEqual(session_id, session.name) self.assertTrue(txn_options.read_only.strong) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', database.name)]) + self.assertEqual( + metadata, [('google-cloud-resource-prefix', database.name)]) class _Session(object): @@ -775,42 +745,34 @@ class _Database(object): name = 'testing' -class _FauxSpannerAPI(_GAXBaseAPI): +class _FauxSpannerAPI(object): _read_with = _begin = None - def begin_transaction(self, session, options_, options=None): - from google.gax.errors import GaxError + def __init__(self, **kwargs): + self.__dict__.update(**kwargs) - self._begun = (session, options_, options) - if self._random_gax_error: - raise GaxError('error') + def begin_transaction(self, session, options_, metadata=None): + self._begun = (session, options_, metadata) return self._begin_transaction_response # pylint: disable=too-many-arguments def streaming_read(self, session, table, columns, key_set, transaction=None, index='', limit=0, - resume_token=b'', options=None): - from google.gax.errors import GaxError - + resume_token=b'', metadata=None): self._streaming_read_with = ( session, table, columns, key_set, transaction, index, - limit, resume_token, options) - if self._random_gax_error: - raise GaxError('error') + limit, resume_token, metadata) return self._streaming_read_response # pylint: enable=too-many-arguments def execute_streaming_sql(self, session, sql, transaction=None, params=None, param_types=None, - resume_token=b'', query_mode=None, options=None): - from google.gax.errors import GaxError - + resume_token=b'', query_mode=None, + metadata=None): self._executed_streaming_sql_with = ( session, sql, transaction, params, param_types, resume_token, - query_mode, options) - if self._random_gax_error: - raise GaxError('error') + query_mode, metadata) return self._execute_streaming_sql_response diff --git a/spanner/tests/unit/test_transaction.py b/spanner/tests/unit/test_transaction.py index 68e7ce3a644b..29c1e765888e 100644 --- a/spanner/tests/unit/test_transaction.py +++ b/spanner/tests/unit/test_transaction.py @@ -15,7 +15,7 @@ import unittest -from google.cloud._testing import _GAXBaseAPI +import mock TABLE_NAME = 'citizens' @@ -47,11 +47,18 @@ def _make_one(self, session, *args, **kwargs): session._transaction = transaction return transaction + def _make_spanner_api(self): + import google.cloud.spanner_v1.gapic.spanner_client + + return mock.create_autospec( + google.cloud.spanner_v1.gapic.spanner_client.SpannerClient, + instance=True) + def test_ctor_session_w_existing_txn(self): session = _Session() session._transaction = object() with self.assertRaises(ValueError): - transaction = self._make_one(session) + self._make_one(session) def test_ctor_defaults(self): session = _Session() @@ -118,24 +125,16 @@ def test_begin_already_committed(self): with self.assertRaises(ValueError): transaction.begin() - def test_begin_w_gax_error(self): - from google.gax.errors import GaxError - + def test_begin_w_other_error(self): database = _Database() - api = database.spanner_api = _FauxSpannerAPI( - _random_gax_error=True) + database.spanner_api = self._make_spanner_api() + database.spanner_api.begin_transaction.side_effect = RuntimeError() session = _Session(database) transaction = self._make_one(session) - with self.assertRaises(GaxError): + with self.assertRaises(RuntimeError): transaction.begin() - session_id, txn_options, options = api._begun - self.assertEqual(session_id, session.name) - self.assertTrue(txn_options.HasField('read_write')) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', database.name)]) - def test_begin_ok(self): from google.cloud.spanner_v1.proto.transaction_pb2 import ( Transaction as TransactionPB) @@ -152,11 +151,11 @@ def test_begin_ok(self): self.assertEqual(txn_id, self.TRANSACTION_ID) self.assertEqual(transaction._transaction_id, self.TRANSACTION_ID) - session_id, txn_options, options = api._begun + session_id, txn_options, metadata = api._begun self.assertEqual(session_id, session.name) self.assertTrue(txn_options.HasField('read_write')) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', database.name)]) + self.assertEqual( + metadata, [('google-cloud-resource-prefix', database.name)]) def test_rollback_not_begun(self): session = _Session() @@ -180,28 +179,20 @@ def test_rollback_already_rolled_back(self): with self.assertRaises(ValueError): transaction.rollback() - def test_rollback_w_gax_error(self): - from google.gax.errors import GaxError - + def test_rollback_w_other_error(self): database = _Database() - api = database.spanner_api = _FauxSpannerAPI( - _random_gax_error=True) + database.spanner_api = self._make_spanner_api() + database.spanner_api.rollback.side_effect = RuntimeError('other error') session = _Session(database) transaction = self._make_one(session) transaction._transaction_id = self.TRANSACTION_ID transaction.insert(TABLE_NAME, COLUMNS, VALUES) - with self.assertRaises(GaxError): + with self.assertRaises(RuntimeError): transaction.rollback() self.assertFalse(transaction._rolled_back) - session_id, txn_id, options = api._rolled_back - self.assertEqual(session_id, session.name) - self.assertEqual(txn_id, self.TRANSACTION_ID) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', database.name)]) - def test_rollback_ok(self): from google.protobuf.empty_pb2 import Empty @@ -219,11 +210,11 @@ def test_rollback_ok(self): self.assertTrue(transaction._rolled_back) self.assertIsNone(session._transaction) - session_id, txn_id, options = api._rolled_back + session_id, txn_id, metadata = api._rolled_back self.assertEqual(session_id, session.name) self.assertEqual(txn_id, self.TRANSACTION_ID) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', database.name)]) + self.assertEqual( + metadata, [('google-cloud-resource-prefix', database.name)]) def test_commit_not_begun(self): session = _Session() @@ -254,29 +245,20 @@ def test_commit_no_mutations(self): with self.assertRaises(ValueError): transaction.commit() - def test_commit_w_gax_error(self): - from google.gax.errors import GaxError - + def test_commit_w_other_error(self): database = _Database() - api = database.spanner_api = _FauxSpannerAPI( - _random_gax_error=True) + database.spanner_api = self._make_spanner_api() + database.spanner_api.commit.side_effect = RuntimeError() session = _Session(database) transaction = self._make_one(session) transaction._transaction_id = self.TRANSACTION_ID transaction.replace(TABLE_NAME, COLUMNS, VALUES) - with self.assertRaises(GaxError): + with self.assertRaises(RuntimeError): transaction.commit() self.assertIsNone(transaction.committed) - session_id, mutations, txn_id, options = api._committed - self.assertEqual(session_id, session.name) - self.assertEqual(txn_id, self.TRANSACTION_ID) - self.assertEqual(mutations, transaction._mutations) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', database.name)]) - def test_commit_ok(self): import datetime from google.cloud.spanner_v1.proto.spanner_pb2 import CommitResponse @@ -302,12 +284,12 @@ def test_commit_ok(self): self.assertEqual(transaction.committed, now) self.assertIsNone(session._transaction) - session_id, mutations, txn_id, options = api._committed + session_id, mutations, txn_id, metadata = api._committed self.assertEqual(session_id, session.name) self.assertEqual(txn_id, self.TRANSACTION_ID) self.assertEqual(mutations, transaction._mutations) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', database.name)]) + self.assertEqual( + metadata, [('google-cloud-resource-prefix', database.name)]) def test_context_mgr_success(self): import datetime @@ -334,12 +316,12 @@ def test_context_mgr_success(self): self.assertEqual(transaction.committed, now) - session_id, mutations, txn_id, options = api._committed + session_id, mutations, txn_id, metadata = api._committed self.assertEqual(session_id, self.SESSION_NAME) self.assertEqual(txn_id, self.TRANSACTION_ID) self.assertEqual(mutations, transaction._mutations) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', database.name)]) + self.assertEqual( + metadata, [('google-cloud-resource-prefix', database.name)]) def test_context_mgr_failure(self): from google.protobuf.empty_pb2 import Empty @@ -366,11 +348,11 @@ def test_context_mgr_failure(self): self.assertEqual(api._committed, None) - session_id, txn_id, options = api._rolled_back + session_id, txn_id, metadata = api._rolled_back self.assertEqual(session_id, session.name) self.assertEqual(txn_id, self.TRANSACTION_ID) - self.assertEqual(options.kwargs['metadata'], - [('google-cloud-resource-prefix', database.name)]) + self.assertEqual( + metadata, [('google-cloud-resource-prefix', database.name)]) class _Database(object): @@ -386,32 +368,23 @@ def __init__(self, database=None, name=TestTransaction.SESSION_NAME): self.name = name -class _FauxSpannerAPI(_GAXBaseAPI): +class _FauxSpannerAPI(object): _committed = None - def begin_transaction(self, session, options_, options=None): - from google.gax.errors import GaxError + def __init__(self, **kwargs): + self.__dict__.update(**kwargs) - self._begun = (session, options_, options) - if self._random_gax_error: - raise GaxError('error') + def begin_transaction(self, session, options_, metadata=None): + self._begun = (session, options_, metadata) return self._begin_transaction_response - def rollback(self, session, transaction_id, options=None): - from google.gax.errors import GaxError - - self._rolled_back = (session, transaction_id, options) - if self._random_gax_error: - raise GaxError('error') + def rollback(self, session, transaction_id, metadata=None): + self._rolled_back = (session, transaction_id, metadata) return self._rollback_response def commit(self, session, mutations, - transaction_id='', single_use_transaction=None, options=None): - from google.gax.errors import GaxError - + transaction_id='', single_use_transaction=None, metadata=None): assert single_use_transaction is None - self._committed = (session, mutations, transaction_id, options) - if self._random_gax_error: - raise GaxError('error') + self._committed = (session, mutations, transaction_id, metadata) return self._commit_response