As of January 1, 2020 this library no longer supports Python 2 on the latest released version.
Library versions released prior to that date will continue to be available. For more information please
visit Python 2 support on Google Cloud.
Source code for google.cloud.spanner_v1.client
# Copyright 2016 Google LLC All rights reserved.
#
# 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.
"""Parent client for calling the Cloud Spanner API.
This is the base from which all interactions with the API occur.
In the hierarchy of API concepts
* a :class:`~google.cloud.spanner_v1.client.Client` owns an
:class:`~google.cloud.spanner_v1.instance.Instance`
* a :class:`~google.cloud.spanner_v1.instance.Instance` owns a
:class:`~google.cloud.spanner_v1.database.Database`
"""
import grpc
import os
import warnings
from google.api_core.gapic_v1 import client_info
from google.auth.credentials import AnonymousCredentials
import google.api_core.client_options
from google.cloud.client import ClientWithProject
from google.cloud.spanner_admin_database_v1 import DatabaseAdminClient
from google.cloud.spanner_admin_database_v1.services.database_admin.transports.grpc import (
DatabaseAdminGrpcTransport,
)
from google.cloud.spanner_admin_instance_v1 import InstanceAdminClient
from google.cloud.spanner_admin_instance_v1.services.instance_admin.transports.grpc import (
InstanceAdminGrpcTransport,
)
from google.cloud.spanner_admin_instance_v1 import ListInstanceConfigsRequest
from google.cloud.spanner_admin_instance_v1 import ListInstancesRequest
from google.cloud.spanner_v1 import __version__
from google.cloud.spanner_v1 import ExecuteSqlRequest
from google.cloud.spanner_v1._helpers import _merge_query_options
from google.cloud.spanner_v1._helpers import _metadata_with_prefix
from google.cloud.spanner_v1.instance import Instance
_CLIENT_INFO = client_info.ClientInfo(client_library_version=__version__)
EMULATOR_ENV_VAR = "SPANNER_EMULATOR_HOST"
_EMULATOR_HOST_HTTP_SCHEME = (
"%s contains a http scheme. When used with a scheme it may cause gRPC's "
"DNS resolver to endlessly attempt to resolve. %s is intended to be used "
"without a scheme: ex %s=localhost:8080."
) % ((EMULATOR_ENV_VAR,) * 3)
SPANNER_ADMIN_SCOPE = "https://www.googleapis.com/auth/spanner.admin"
OPTIMIZER_VERSION_ENV_VAR = "SPANNER_OPTIMIZER_VERSION"
OPTIMIZER_STATISITCS_PACKAGE_ENV_VAR = "SPANNER_OPTIMIZER_STATISTICS_PACKAGE"
def _get_spanner_emulator_host():
return os.getenv(EMULATOR_ENV_VAR)
def _get_spanner_optimizer_version():
return os.getenv(OPTIMIZER_VERSION_ENV_VAR, "")
def _get_spanner_optimizer_statistics_package():
return os.getenv(OPTIMIZER_STATISITCS_PACKAGE_ENV_VAR, "")
[docs]class Client(ClientWithProject):
"""Client for interacting with Cloud Spanner API.
.. note::
Since the Cloud Spanner API requires the gRPC transport, no
``_http`` argument is accepted by this class.
:type project: :class:`str` or :func:`unicode <unicode>`
:param project: (Optional) The ID of the project which owns the
instances, tables and data. If not provided, will
attempt to determine from the environment.
:type credentials:
:class:`Credentials <google.auth.credentials.Credentials>` or
:data:`NoneType <types.NoneType>`
:param credentials: (Optional) 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.
:type client_info: :class:`~google.api_core.gapic_v1.client_info.ClientInfo`
:param client_info:
(Optional) 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 library or
partner tool.
:type client_options: :class:`~google.api_core.client_options.ClientOptions`
or :class:`dict`
:param client_options: (Optional) Client options used to set user options
on the client. API Endpoint should be set through client_options.
:type query_options:
:class:`~google.cloud.spanner_v1.types.ExecuteSqlRequest.QueryOptions`
or :class:`dict`
:param query_options:
(Optional) Query optimizer configuration to use for the given query.
If a dict is provided, it must be of the same form as the protobuf
message :class:`~google.cloud.spanner_v1.types.QueryOptions`
:type route_to_leader_enabled: boolean
:param route_to_leader_enabled:
(Optional) Default True. Set route_to_leader_enabled as False to
disable leader aware routing. Disabling leader aware routing would
route all requests in RW/PDML transactions to the closest region.
:type directed_read_options: :class:`~google.cloud.spanner_v1.DirectedReadOptions`
or :class:`dict`
:param directed_read_options: (Optional) Client options used to set the directed_read_options
for all ReadRequests and ExecuteSqlRequests that indicates which replicas
or regions should be used for non-transactional reads or queries.
:raises: :class:`ValueError <exceptions.ValueError>` if both ``read_only``
and ``admin`` are :data:`True`
"""
_instance_admin_api = None
_database_admin_api = None
_SET_PROJECT = True # Used by from_service_account_json()
SCOPE = (SPANNER_ADMIN_SCOPE,)
"""The scopes required for Google Cloud Spanner."""
def __init__(
self,
project=None,
credentials=None,
client_info=_CLIENT_INFO,
client_options=None,
query_options=None,
route_to_leader_enabled=True,
directed_read_options=None,
):
self._emulator_host = _get_spanner_emulator_host()
if client_options and type(client_options) is dict:
self._client_options = google.api_core.client_options.from_dict(
client_options
)
else:
self._client_options = client_options
if self._emulator_host:
credentials = AnonymousCredentials()
elif isinstance(credentials, AnonymousCredentials):
self._emulator_host = self._client_options.api_endpoint
# NOTE: This API has no use for the _http argument, but sending it
# will have no impact since the _http() @property only lazily
# creates a working HTTP object.
super(Client, self).__init__(
project=project,
credentials=credentials,
client_options=client_options,
_http=None,
)
self._client_info = client_info
env_query_options = ExecuteSqlRequest.QueryOptions(
optimizer_version=_get_spanner_optimizer_version(),
optimizer_statistics_package=_get_spanner_optimizer_statistics_package(),
)
# Environment flag config has higher precedence than application config.
self._query_options = _merge_query_options(query_options, env_query_options)
if self._emulator_host is not None and (
"http://" in self._emulator_host or "https://" in self._emulator_host
):
warnings.warn(_EMULATOR_HOST_HTTP_SCHEME)
self._route_to_leader_enabled = route_to_leader_enabled
self._directed_read_options = directed_read_options
@property
def credentials(self):
"""Getter for client's credentials.
:rtype:
:class:`Credentials <google.auth.credentials.Credentials>`
:returns: The credentials stored on the client.
"""
return self._credentials
@property
def project_name(self):
"""Project name to be used with Spanner APIs.
.. note::
This property will not change if ``project`` does not, but the
return value is not cached.
The project name is of the form
``"projects/{project}"``
:rtype: str
:returns: The project name to be used with the Cloud Spanner Admin
API RPC service.
"""
return "projects/" + self.project
@property
def instance_admin_api(self):
"""Helper for session-related API calls."""
if self._instance_admin_api is None:
if self._emulator_host is not None:
transport = InstanceAdminGrpcTransport(
channel=grpc.insecure_channel(target=self._emulator_host)
)
self._instance_admin_api = InstanceAdminClient(
client_info=self._client_info,
client_options=self._client_options,
transport=transport,
)
else:
self._instance_admin_api = InstanceAdminClient(
credentials=self.credentials,
client_info=self._client_info,
client_options=self._client_options,
)
return self._instance_admin_api
@property
def database_admin_api(self):
"""Helper for session-related API calls."""
if self._database_admin_api is None:
if self._emulator_host is not None:
transport = DatabaseAdminGrpcTransport(
channel=grpc.insecure_channel(target=self._emulator_host)
)
self._database_admin_api = DatabaseAdminClient(
client_info=self._client_info,
client_options=self._client_options,
transport=transport,
)
else:
self._database_admin_api = DatabaseAdminClient(
credentials=self.credentials,
client_info=self._client_info,
client_options=self._client_options,
)
return self._database_admin_api
@property
def route_to_leader_enabled(self):
"""Getter for if read-write or pdml requests will be routed to leader.
:rtype: boolean
:returns: If read-write requests will be routed to leader.
"""
return self._route_to_leader_enabled
@property
def directed_read_options(self):
"""Getter for directed_read_options.
:rtype:
:class:`~google.cloud.spanner_v1.DirectedReadOptions`
or :class:`dict`
:returns: The directed_read_options for the client.
"""
return self._directed_read_options
[docs] def copy(self):
"""Make a copy of this client.
Copies the local data stored as simple types but does not copy the
current state of any open connections with the Cloud Bigtable API.
:rtype: :class:`.Client`
:returns: A copy of the current client.
"""
return self.__class__(project=self.project, credentials=self._credentials)
[docs] def list_instance_configs(self, page_size=None):
"""List available instance configurations for the client's project.
.. _RPC docs: https://cloud.google.com/spanner/docs/reference/rpc/\
google.spanner.admin.instance.v1#google.spanner.admin.\
instance.v1.InstanceAdmin.ListInstanceConfigs
See `RPC docs`_.
:type page_size: int
:param page_size:
Optional. The maximum number of configs in each page of results
from this request. Non-positive values are ignored. Defaults
to a sensible value set by the API.
:rtype: :class:`~google.api_core.page_iterator.Iterator`
:returns:
Iterator of
:class:`~google.cloud.spanner_admin_instance_v1.types.InstanceConfig`
resources within the client's project.
"""
metadata = _metadata_with_prefix(self.project_name)
request = ListInstanceConfigsRequest(
parent=self.project_name, page_size=page_size
)
page_iter = self.instance_admin_api.list_instance_configs(
request=request, metadata=metadata
)
return page_iter
[docs] def instance(
self,
instance_id,
configuration_name=None,
display_name=None,
node_count=None,
labels=None,
processing_units=None,
):
"""Factory to create a instance associated with this client.
:type instance_id: str
:param instance_id: The ID of the instance.
:type configuration_name: string
:param configuration_name:
(Optional) Name of the instance configuration used to set up the
instance's cluster, in the form:
``projects/<project>/instanceConfigs/``
``<config>``.
**Required** for instances which do not yet exist.
:type display_name: str
:param display_name: (Optional) The display name for the instance in
the Cloud Console UI. (Must be between 4 and 30
characters.) If this value is not set in the
constructor, will fall back to the instance ID.
:type node_count: int
:param node_count: (Optional) The number of nodes in the instance's
cluster; used to set up the instance's cluster.
:type processing_units: int
:param processing_units: (Optional) The number of processing units
allocated to this instance.
:type labels: dict (str -> str) or None
:param labels: (Optional) User-assigned labels for this instance.
:rtype: :class:`~google.cloud.spanner_v1.instance.Instance`
:returns: an instance owned by this client.
"""
return Instance(
instance_id,
self,
configuration_name,
node_count,
display_name,
self._emulator_host,
labels,
processing_units,
)
[docs] def list_instances(self, filter_="", page_size=None):
"""List instances for the client's project.
See
https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.database.v1#google.spanner.admin.database.v1.InstanceAdmin.ListInstances
:type filter_: string
:param filter_: (Optional) Filter to select instances listed. See
the ``ListInstancesRequest`` docs above for examples.
:type page_size: int
:param page_size:
Optional. The maximum number of instances in each page of results
from this request. Non-positive values are ignored. Defaults
to a sensible value set by the API.
:rtype: :class:`~google.api_core.page_iterator.Iterator`
:returns:
Iterator of :class:`~google.cloud.spanner_admin_instance_v1.types.Instance`
resources within the client's project.
"""
metadata = _metadata_with_prefix(self.project_name)
request = ListInstancesRequest(
parent=self.project_name, filter=filter_, page_size=page_size
)
page_iter = self.instance_admin_api.list_instances(
request=request, metadata=metadata
)
return page_iter
@directed_read_options.setter
def directed_read_options(self, directed_read_options):
"""Sets directed_read_options for the client
:type directed_read_options: :class:`~google.cloud.spanner_v1.DirectedReadOptions`
or :class:`dict`
:param directed_read_options: Client options used to set the directed_read_options
for all ReadRequests and ExecuteSqlRequests that indicates which replicas
or regions should be used for non-transactional reads or queries.
"""
self._directed_read_options = directed_read_options