diff --git a/datastore/docs/conf.py b/datastore/docs/conf.py new file mode 100644 index 000000000000..de92e20469fd --- /dev/null +++ b/datastore/docs/conf.py @@ -0,0 +1,310 @@ +# -*- coding: utf-8 -*- +# +# google-cloud-datastore documentation build configuration file +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys +import os +import shlex + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +sys.path.insert(0, os.path.abspath('..')) + +__version__ = '0.90.4' + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.autosummary', + 'sphinx.ext.intersphinx', + 'sphinx.ext.coverage', + 'sphinx.ext.napoleon', + 'sphinx.ext.viewcode', +] + +# autodoc/autosummary flags +autoclass_content = 'both' +autodoc_default_flags = ['members'] +autosummary_generate = True + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'google-cloud-datastore' +copyright = u'2017, Google' +author = u'Google APIs' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The full version, including alpha/beta/rc tags. +release = __version__ +# The short X.Y version. +version = '.'.join(release.split('.')[0:2]) + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +#keep_warnings = False + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = True + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'sphinx_rtd_theme' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +# html_static_path = [] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +#html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Language to be used for generating the HTML full-text search index. +# Sphinx supports the following languages: +# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' +# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr' +#html_search_language = 'en' + +# A dictionary with options for the search language support, empty by default. +# Now only 'ja' uses this config value +#html_search_options = {'type': 'default'} + +# The name of a javascript file (relative to the configuration directory) that +# implements a search results scorer. If empty, the default will be used. +#html_search_scorer = 'scorer.js' + +# Output file base name for HTML help builder. +htmlhelp_basename = 'google-cloud-datastore-doc' + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + #'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + #'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + #'preamble': '', + + # Latex figure (float) alignment + #'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'google-cloud-datastore.tex', + u'google-cloud-datastore Documentation', author, 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [(master_doc, 'google-cloud-datastore', + u'google-cloud-datastore Documentation', [author], 1)] + +# If true, show URL addresses after external links. +#man_show_urls = False + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'google-cloud-datastore', + u'google-cloud-datastore Documentation', author, 'google-cloud-datastore', + 'GAPIC library for the {metadata.shortName} v1 service', 'APIs'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +#texinfo_no_detailmenu = False + +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = { + 'python': ('http://python.readthedocs.org/en/latest/', None), + 'gax': ('https://gax-python.readthedocs.org/en/latest/', None), +} + +# Napoleon settings +napoleon_google_docstring = True +napoleon_numpy_docstring = True +napoleon_include_private_with_doc = False +napoleon_include_special_with_doc = True +napoleon_use_admonition_for_examples = False +napoleon_use_admonition_for_notes = False +napoleon_use_admonition_for_references = False +napoleon_use_ivar = False +napoleon_use_param = True +napoleon_use_rtype = True diff --git a/datastore/docs/gapic/v1/api.rst b/datastore/docs/gapic/v1/api.rst new file mode 100644 index 000000000000..9d987a96747a --- /dev/null +++ b/datastore/docs/gapic/v1/api.rst @@ -0,0 +1,6 @@ +Client for Google Cloud Datastore API +===================================== + +.. automodule:: google.cloud.datastore_v1 + :members: + :inherited-members: \ No newline at end of file diff --git a/datastore/docs/gapic/v1/types.rst b/datastore/docs/gapic/v1/types.rst new file mode 100644 index 000000000000..840085452eb4 --- /dev/null +++ b/datastore/docs/gapic/v1/types.rst @@ -0,0 +1,5 @@ +Types for Google Cloud Datastore API Client +=========================================== + +.. automodule:: google.cloud.datastore_v1.types + :members: \ No newline at end of file diff --git a/datastore/docs/index.rst b/datastore/docs/index.rst new file mode 100644 index 000000000000..08466ac45a67 --- /dev/null +++ b/datastore/docs/index.rst @@ -0,0 +1,84 @@ +Python Client for Google Cloud Datastore API (`Beta`_) +====================================================== + +`Google Cloud Datastore API`_: Accesses the schemaless NoSQL database to provide fully managed, robust, +scalable storage for your application. + +- `Client Library Documentation`_ +- `Product Documentation`_ + +.. _Beta: https://github.com/GoogleCloudPlatform/google-cloud-python/blob/master/README.rst +.. _Google Cloud Datastore API: https://cloud.google.com/datastore +.. _Client Library Documentation: https://googlecloudplatform.github.io/google-cloud-python/stable/datastore/usage.html +.. _Product Documentation: https://cloud.google.com/datastore + +Quick Start +----------- + +In order to use this library, you first need to go through the following steps: + +1. `Select or create a Cloud Platform project.`_ +2. `Enable billing for your project.`_ +3. `Enable the Google Cloud Datastore API.`_ +4. `Setup Authentication.`_ + +.. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project +.. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project +.. _Enable the Google Cloud Datastore API.: https://cloud.google.com/datastore +.. _Setup Authentication.: https://googlecloudplatform.github.io/google-cloud-python/stable/core/auth.html + +Installation +~~~~~~~~~~~~ + +Install this library in a `virtualenv`_ using pip. `virtualenv`_ is a tool to +create isolated Python environments. The basic problem it addresses is one of +dependencies and versions, and indirectly permissions. + +With `virtualenv`_, it's possible to install this library without needing system +install permissions, and without clashing with the installed system +dependencies. + +.. _`virtualenv`: https://virtualenv.pypa.io/en/latest/ + + +Mac/Linux +^^^^^^^^^ + +.. code-block:: console + + pip install virtualenv + virtualenv + source /bin/activate + /bin/pip install google-cloud-datastore + + +Windows +^^^^^^^ + +.. code-block:: console + + pip install virtualenv + virtualenv + \Scripts\activate + \Scripts\pip.exe install google-cloud-datastore + +Next Steps +~~~~~~~~~~ + +- Read the `Client Library Documentation`_ for Google Cloud Datastore API + API to see other available methods on the client. +- Read the `Google Cloud Datastore API Product documentation`_ to learn + more about the product and see How-to Guides. +- View this `repository’s main README`_ to see the full list of Cloud + APIs that we cover. + +.. _Google Cloud Datastore API Product documentation: https://cloud.google.com/datastore +.. _repository’s main README: https://github.com/GoogleCloudPlatform/google-cloud-python/blob/master/README.rst + +Api Reference +------------- +.. toctree:: + :maxdepth: 2 + + gapic/v1/api + gapic/v1/types \ No newline at end of file diff --git a/datastore/google/cloud/datastore/_gapic.py b/datastore/google/cloud/datastore/_gapic.py new file mode 100644 index 000000000000..b56ba5e89c64 --- /dev/null +++ b/datastore/google/cloud/datastore/_gapic.py @@ -0,0 +1,52 @@ +# 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 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Helpers for making API requests via gapic / gRPC.""" + +from google.api_core.gapic_v1 import client_info +from google.cloud.datastore_v1.gapic import datastore_client +from grpc import insecure_channel +import six + +from google.cloud._helpers import make_secure_channel +from google.cloud._http import DEFAULT_USER_AGENT + +from google.cloud.datastore import __version__ + + +def make_datastore_api(client): + """Create an instance of the GAPIC Datastore API. + + :type client: :class:`~google.cloud.datastore.client.Client` + :param client: The client that holds configuration details. + + :rtype: :class:`.datastore.v1.datastore_client.DatastoreClient` + :returns: A datastore API instance with the proper credentials. + """ + parse_result = six.moves.urllib_parse.urlparse( + client._base_url) + host = parse_result.netloc + if parse_result.scheme == 'https': + channel = make_secure_channel( + client._credentials, DEFAULT_USER_AGENT, host) + else: + channel = insecure_channel(host) + + return datastore_client.DatastoreClient( + channel=channel, + client_info=client_info.ClientInfo( + client_library_version=__version__, + gapic_version=__version__, + ), + ) diff --git a/datastore/google/cloud/datastore/_gax.py b/datastore/google/cloud/datastore/_gax.py deleted file mode 100644 index 4eb54eb7681d..000000000000 --- a/datastore/google/cloud/datastore/_gax.py +++ /dev/null @@ -1,240 +0,0 @@ -# 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 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Helpers for making API requests via GAX / gRPC.""" - - -import contextlib -import sys - -from google.api_core.gapic_v1 import client_info -from google.cloud.datastore_v1.gapic import datastore_client -from google.gax.errors import GaxError -from google.gax.grpc import exc_to_code -from google.gax.utils import metrics -from grpc import insecure_channel -from grpc import StatusCode -import six - -from google.cloud._helpers import make_secure_channel -from google.cloud._http import DEFAULT_USER_AGENT -from google.cloud import exceptions - -from google.cloud.datastore import __version__ - - -_METRICS_HEADERS = ( - ('gccl', __version__), -) -_HEADER_STR = metrics.stringify(metrics.fill(_METRICS_HEADERS)) -_GRPC_EXTRA_OPTIONS = ( - ('x-goog-api-client', _HEADER_STR), -) -_GRPC_ERROR_MAPPING = { - StatusCode.UNKNOWN: exceptions.InternalServerError, - StatusCode.INVALID_ARGUMENT: exceptions.BadRequest, - StatusCode.DEADLINE_EXCEEDED: exceptions.GatewayTimeout, - StatusCode.NOT_FOUND: exceptions.NotFound, - StatusCode.ALREADY_EXISTS: exceptions.Conflict, - StatusCode.PERMISSION_DENIED: exceptions.Forbidden, - StatusCode.UNAUTHENTICATED: exceptions.Unauthorized, - StatusCode.RESOURCE_EXHAUSTED: exceptions.TooManyRequests, - StatusCode.FAILED_PRECONDITION: exceptions.PreconditionFailed, - StatusCode.ABORTED: exceptions.Conflict, - StatusCode.OUT_OF_RANGE: exceptions.BadRequest, - StatusCode.UNIMPLEMENTED: exceptions.MethodNotImplemented, - StatusCode.INTERNAL: exceptions.InternalServerError, - StatusCode.UNAVAILABLE: exceptions.ServiceUnavailable, - StatusCode.DATA_LOSS: exceptions.InternalServerError, -} - - -@contextlib.contextmanager -def _catch_remap_gax_error(): - """Remap GAX exceptions that happen in context. - - .. _code.proto: https://github.com/googleapis/googleapis/blob/\ - master/google/rpc/code.proto - - Remaps gRPC exceptions to the classes defined in - :mod:`~google.cloud.exceptions` (according to the description - in `code.proto`_). - """ - try: - yield - except GaxError as exc: - error_code = exc_to_code(exc.cause) - error_class = _GRPC_ERROR_MAPPING.get(error_code) - if error_class is None: - raise - else: - new_exc = error_class(exc.cause.details()) - six.reraise(error_class, new_exc, sys.exc_info()[2]) - - -class GAPICDatastoreAPI(datastore_client.DatastoreClient): - """An API object that sends proto-over-gRPC requests. - - A light wrapper around the parent class, with exception re-mapping - provided (from GaxError to our native errors). - - :type args: tuple - :param args: Positional arguments to pass to constructor. - - :type kwargs: dict - :param kwargs: Keyword arguments to pass to constructor. - """ - - def lookup(self, *args, **kwargs): - """Perform a ``lookup`` request. - - A light wrapper around the the base method from the parent class. - Intended to provide exception re-mapping (from GaxError to our - native errors). - - :type args: tuple - :param args: Positional arguments to pass to base method. - - :type kwargs: dict - :param kwargs: Keyword arguments to pass to base method. - - :rtype: :class:`.datastore_pb2.LookupResponse` - :returns: The returned protobuf response object. - """ - with _catch_remap_gax_error(): - return super(GAPICDatastoreAPI, self).lookup(*args, **kwargs) - - def run_query(self, *args, **kwargs): - """Perform a ``runQuery`` request. - - A light wrapper around the the base method from the parent class. - Intended to provide exception re-mapping (from GaxError to our - native errors). - - :type args: tuple - :param args: Positional arguments to pass to base method. - - :type kwargs: dict - :param kwargs: Keyword arguments to pass to base method. - - :rtype: :class:`.datastore_pb2.RunQueryResponse` - :returns: The returned protobuf response object. - """ - with _catch_remap_gax_error(): - return super(GAPICDatastoreAPI, self).run_query(*args, **kwargs) - - def begin_transaction(self, *args, **kwargs): - """Perform a ``beginTransaction`` request. - - A light wrapper around the the base method from the parent class. - Intended to provide exception re-mapping (from GaxError to our - native errors). - - :type args: tuple - :param args: Positional arguments to pass to base method. - - :type kwargs: dict - :param kwargs: Keyword arguments to pass to base method. - - :rtype: :class:`.datastore_pb2.BeginTransactionResponse` - :returns: The returned protobuf response object. - """ - with _catch_remap_gax_error(): - return super(GAPICDatastoreAPI, self).begin_transaction( - *args, **kwargs) - - def commit(self, *args, **kwargs): - """Perform a ``commit`` request. - - A light wrapper around the the base method from the parent class. - Intended to provide exception re-mapping (from GaxError to our - native errors). - - :type args: tuple - :param args: Positional arguments to pass to base method. - - :type kwargs: dict - :param kwargs: Keyword arguments to pass to base method. - - :rtype: :class:`.datastore_pb2.CommitResponse` - :returns: The returned protobuf response object. - """ - with _catch_remap_gax_error(): - return super(GAPICDatastoreAPI, self).commit(*args, **kwargs) - - def rollback(self, *args, **kwargs): - """Perform a ``rollback`` request. - - A light wrapper around the the base method from the parent class. - Intended to provide exception re-mapping (from GaxError to our - native errors). - - :type args: tuple - :param args: Positional arguments to pass to base method. - - :type kwargs: dict - :param kwargs: Keyword arguments to pass to base method. - - :rtype: :class:`.datastore_pb2.RollbackResponse` - :returns: The returned protobuf response object. - """ - with _catch_remap_gax_error(): - return super(GAPICDatastoreAPI, self).rollback(*args, **kwargs) - - def allocate_ids(self, *args, **kwargs): - """Perform an ``allocateIds`` request. - - A light wrapper around the the base method from the parent class. - Intended to provide exception re-mapping (from GaxError to our - native errors). - - :type args: tuple - :param args: Positional arguments to pass to base method. - - :type kwargs: dict - :param kwargs: Keyword arguments to pass to base method. - - :rtype: :class:`.datastore_pb2.AllocateIdsResponse` - :returns: The returned protobuf response object. - """ - with _catch_remap_gax_error(): - return super(GAPICDatastoreAPI, self).allocate_ids( - *args, **kwargs) - - -def make_datastore_api(client): - """Create an instance of the GAPIC Datastore API. - - :type client: :class:`~google.cloud.datastore.client.Client` - :param client: The client that holds configuration details. - - :rtype: :class:`.datastore.v1.datastore_client.DatastoreClient` - :returns: A datastore API instance with the proper credentials. - """ - parse_result = six.moves.urllib_parse.urlparse( - client._base_url) - host = parse_result.netloc - if parse_result.scheme == 'https': - channel = make_secure_channel( - client._credentials, DEFAULT_USER_AGENT, host) - else: - channel = insecure_channel(host) - - return GAPICDatastoreAPI( - channel=channel, - client_info=client_info.ClientInfo( - client_library_version=__version__, - gapic_version=__version__, - ), - ) diff --git a/datastore/google/cloud/datastore/client.py b/datastore/google/cloud/datastore/client.py index b53e2deb54f3..ac93f8480d6f 100644 --- a/datastore/google/cloud/datastore/client.py +++ b/datastore/google/cloud/datastore/client.py @@ -31,7 +31,7 @@ from google.cloud.environment_vars import GCD_HOST try: - from google.cloud.datastore._gax import make_datastore_api + from google.cloud.datastore._gapic import make_datastore_api _HAVE_GRPC = True except ImportError: # pragma: NO COVER make_datastore_api = None @@ -86,7 +86,7 @@ def _extended_lookup(datastore_api, project, key_pbs, :type datastore_api: :class:`google.cloud.datastore._http.HTTPDatastoreAPI` - or :class:`google.cloud.datastore._gax.GAPICDatastoreAPI` + or :class:`google.cloud.datastore_v1.gapic.DatastoreClient` :param datastore_api: The datastore API object used to connect to datastore. diff --git a/datastore/google/cloud/datastore_v1/__init__.py b/datastore/google/cloud/datastore_v1/__init__.py index 5157e60d4e80..5297ae3121d7 100644 --- a/datastore/google/cloud/datastore_v1/__init__.py +++ b/datastore/google/cloud/datastore_v1/__init__.py @@ -1,10 +1,10 @@ -# Copyright 2017, Google LLC All rights reserved. +# Copyright 2018 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 DatastoreClient(datastore_client.DatastoreClient): __all__ = ( 'enums', 'types', - 'DatastoreClient', ) + 'DatastoreClient', +) diff --git a/datastore/google/cloud/datastore_v1/gapic/datastore_client.py b/datastore/google/cloud/datastore_v1/gapic/datastore_client.py index 983e30dce902..e747909477cc 100644 --- a/datastore/google/cloud/datastore_v1/gapic/datastore_client.py +++ b/datastore/google/cloud/datastore_v1/gapic/datastore_client.py @@ -1,25 +1,16 @@ -# Copyright 2017, Google LLC All rights reserved. +# Copyright 2018 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/datastore/v1/datastore.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.datastore.v1 Datastore API.""" import pkg_resources @@ -57,11 +48,12 @@ class DatastoreClient(object): # this service _DEFAULT_SCOPES = ( 'https://www.googleapis.com/auth/cloud-platform', - 'https://www.googleapis.com/auth/datastore', ) + 'https://www.googleapis.com/auth/datastore', + ) # 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.datastore.v1.Datastore') + # method configuration in the client_config dictionary. + _INTERFACE_NAME = 'google.datastore.v1.Datastore' def __init__(self, channel=None, @@ -72,81 +64,97 @@ def __init__(self, Args: channel (grpc.Channel): A ``Channel`` instance through - which to make calls. If specified, then the ``credentials`` - argument is ignored. + 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. Generally, you only need - to set this if you're developing your own client library. + 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. """ + # 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( - 'channel and credentials arguments to {} are mutually ' - 'exclusive.'.format(self.__class__.__name__)) + '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) + scopes=self._DEFAULT_SCOPES, + ) + # Create the gRPC stubs. self.datastore_stub = (datastore_pb2.DatastoreStub(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 - interface_config = client_config['interfaces'][self._INTERFACE_NAME] + # 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( - interface_config) + 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._lookup = google.api_core.gapic_v1.method.wrap_method( self.datastore_stub.Lookup, default_retry=method_configs['Lookup'].retry, default_timeout=method_configs['Lookup'].timeout, - client_info=client_info) + client_info=client_info, + ) self._run_query = google.api_core.gapic_v1.method.wrap_method( self.datastore_stub.RunQuery, default_retry=method_configs['RunQuery'].retry, default_timeout=method_configs['RunQuery'].timeout, - client_info=client_info) + client_info=client_info, + ) self._begin_transaction = google.api_core.gapic_v1.method.wrap_method( self.datastore_stub.BeginTransaction, default_retry=method_configs['BeginTransaction'].retry, default_timeout=method_configs['BeginTransaction'].timeout, - client_info=client_info) + client_info=client_info, + ) self._commit = google.api_core.gapic_v1.method.wrap_method( self.datastore_stub.Commit, default_retry=method_configs['Commit'].retry, default_timeout=method_configs['Commit'].timeout, - client_info=client_info) + client_info=client_info, + ) self._rollback = google.api_core.gapic_v1.method.wrap_method( self.datastore_stub.Rollback, default_retry=method_configs['Rollback'].retry, default_timeout=method_configs['Rollback'].timeout, - client_info=client_info) + client_info=client_info, + ) self._allocate_ids = google.api_core.gapic_v1.method.wrap_method( self.datastore_stub.AllocateIds, default_retry=method_configs['AllocateIds'].retry, default_timeout=method_configs['AllocateIds'].timeout, - client_info=client_info) + client_info=client_info, + ) self._reserve_ids = google.api_core.gapic_v1.method.wrap_method( self.datastore_stub.ReserveIds, default_retry=method_configs['ReserveIds'].retry, default_timeout=method_configs['ReserveIds'].timeout, - client_info=client_info) + client_info=client_info, + ) # Service calls def lookup(self, @@ -154,7 +162,8 @@ def lookup(self, keys, read_options=None, retry=google.api_core.gapic_v1.method.DEFAULT, - timeout=google.api_core.gapic_v1.method.DEFAULT): + timeout=google.api_core.gapic_v1.method.DEFAULT, + metadata=None): """ Looks up entities by key. @@ -182,6 +191,8 @@ def lookup(self, 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. + metadata (Optional[Sequence[Tuple[str, str]]]): Additional metadata + that is provided to the method. Returns: A :class:`~google.cloud.datastore_v1.types.LookupResponse` instance. @@ -193,9 +204,16 @@ def lookup(self, to a retryable error and retry attempts failed. ValueError: If the parameters are invalid. """ + if metadata is None: + metadata = [] + metadata = list(metadata) request = datastore_pb2.LookupRequest( - project_id=project_id, keys=keys, read_options=read_options) - return self._lookup(request, retry=retry, timeout=timeout) + project_id=project_id, + keys=keys, + read_options=read_options, + ) + return self._lookup( + request, retry=retry, timeout=timeout, metadata=metadata) def run_query(self, project_id, @@ -204,7 +222,8 @@ def run_query(self, query=None, gql_query=None, retry=google.api_core.gapic_v1.method.DEFAULT, - timeout=google.api_core.gapic_v1.method.DEFAULT): + timeout=google.api_core.gapic_v1.method.DEFAULT, + metadata=None): """ Queries for entities. @@ -241,6 +260,8 @@ def run_query(self, 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. + metadata (Optional[Sequence[Tuple[str, str]]]): Additional metadata + that is provided to the method. Returns: A :class:`~google.cloud.datastore_v1.types.RunQueryResponse` instance. @@ -252,25 +273,32 @@ def run_query(self, to a retryable error and retry attempts failed. ValueError: If the parameters are invalid. """ + if metadata is None: + metadata = [] + metadata = list(metadata) # Sanity check: We have some fields which are mutually exclusive; # raise ValueError if more than one is sent. google.api_core.protobuf_helpers.check_oneof( query=query, - gql_query=gql_query, ) + gql_query=gql_query, + ) request = datastore_pb2.RunQueryRequest( project_id=project_id, partition_id=partition_id, read_options=read_options, query=query, - gql_query=gql_query) - return self._run_query(request, retry=retry, timeout=timeout) + gql_query=gql_query, + ) + return self._run_query( + request, retry=retry, timeout=timeout, metadata=metadata) def begin_transaction(self, project_id, transaction_options=None, retry=google.api_core.gapic_v1.method.DEFAULT, - timeout=google.api_core.gapic_v1.method.DEFAULT): + timeout=google.api_core.gapic_v1.method.DEFAULT, + metadata=None): """ Begins a new transaction. @@ -294,6 +322,8 @@ def begin_transaction(self, 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. + metadata (Optional[Sequence[Tuple[str, str]]]): Additional metadata + that is provided to the method. Returns: A :class:`~google.cloud.datastore_v1.types.BeginTransactionResponse` instance. @@ -305,9 +335,15 @@ def begin_transaction(self, to a retryable error and retry attempts failed. ValueError: If the parameters are invalid. """ + if metadata is None: + metadata = [] + metadata = list(metadata) request = datastore_pb2.BeginTransactionRequest( - project_id=project_id, transaction_options=transaction_options) - return self._begin_transaction(request, retry=retry, timeout=timeout) + project_id=project_id, + transaction_options=transaction_options, + ) + return self._begin_transaction( + request, retry=retry, timeout=timeout, metadata=metadata) def commit(self, project_id, @@ -315,7 +351,8 @@ def commit(self, mutations, transaction=None, retry=google.api_core.gapic_v1.method.DEFAULT, - timeout=google.api_core.gapic_v1.method.DEFAULT): + timeout=google.api_core.gapic_v1.method.DEFAULT, + metadata=None): """ Commits a transaction, optionally creating, deleting or modifying some entities. @@ -359,6 +396,8 @@ def commit(self, 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. + metadata (Optional[Sequence[Tuple[str, str]]]): Additional metadata + that is provided to the method. Returns: A :class:`~google.cloud.datastore_v1.types.CommitResponse` instance. @@ -370,6 +409,9 @@ def commit(self, to a retryable error and retry attempts failed. ValueError: If the parameters are invalid. """ + if metadata is None: + metadata = [] + metadata = list(metadata) # Sanity check: We have some fields which are mutually exclusive; # raise ValueError if more than one is sent. google.api_core.protobuf_helpers.check_oneof(transaction=transaction, ) @@ -378,14 +420,17 @@ def commit(self, project_id=project_id, mode=mode, mutations=mutations, - transaction=transaction) - return self._commit(request, retry=retry, timeout=timeout) + transaction=transaction, + ) + return self._commit( + request, retry=retry, timeout=timeout, metadata=metadata) def rollback(self, project_id, transaction, retry=google.api_core.gapic_v1.method.DEFAULT, - timeout=google.api_core.gapic_v1.method.DEFAULT): + timeout=google.api_core.gapic_v1.method.DEFAULT, + metadata=None): """ Rolls back a transaction. @@ -409,6 +454,8 @@ def rollback(self, 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. + metadata (Optional[Sequence[Tuple[str, str]]]): Additional metadata + that is provided to the method. Returns: A :class:`~google.cloud.datastore_v1.types.RollbackResponse` instance. @@ -420,15 +467,22 @@ def rollback(self, to a retryable error and retry attempts failed. ValueError: If the parameters are invalid. """ + if metadata is None: + metadata = [] + metadata = list(metadata) request = datastore_pb2.RollbackRequest( - project_id=project_id, transaction=transaction) - return self._rollback(request, retry=retry, timeout=timeout) + project_id=project_id, + transaction=transaction, + ) + return self._rollback( + request, retry=retry, timeout=timeout, metadata=metadata) def allocate_ids(self, project_id, keys, retry=google.api_core.gapic_v1.method.DEFAULT, - timeout=google.api_core.gapic_v1.method.DEFAULT): + timeout=google.api_core.gapic_v1.method.DEFAULT, + metadata=None): """ Allocates IDs for the given keys, which is useful for referencing an entity before it is inserted. @@ -455,6 +509,8 @@ def allocate_ids(self, 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. + metadata (Optional[Sequence[Tuple[str, str]]]): Additional metadata + that is provided to the method. Returns: A :class:`~google.cloud.datastore_v1.types.AllocateIdsResponse` instance. @@ -466,16 +522,23 @@ def allocate_ids(self, to a retryable error and retry attempts failed. ValueError: If the parameters are invalid. """ + if metadata is None: + metadata = [] + metadata = list(metadata) request = datastore_pb2.AllocateIdsRequest( - project_id=project_id, keys=keys) - return self._allocate_ids(request, retry=retry, timeout=timeout) + project_id=project_id, + keys=keys, + ) + return self._allocate_ids( + request, retry=retry, timeout=timeout, metadata=metadata) def reserve_ids(self, project_id, keys, database_id=None, retry=google.api_core.gapic_v1.method.DEFAULT, - timeout=google.api_core.gapic_v1.method.DEFAULT): + timeout=google.api_core.gapic_v1.method.DEFAULT, + metadata=None): """ Prevents the supplied keys' IDs from being auto-allocated by Cloud Datastore. @@ -503,6 +566,8 @@ def reserve_ids(self, 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. + metadata (Optional[Sequence[Tuple[str, str]]]): Additional metadata + that is provided to the method. Returns: A :class:`~google.cloud.datastore_v1.types.ReserveIdsResponse` instance. @@ -514,6 +579,13 @@ def reserve_ids(self, to a retryable error and retry attempts failed. ValueError: If the parameters are invalid. """ + if metadata is None: + metadata = [] + metadata = list(metadata) request = datastore_pb2.ReserveIdsRequest( - project_id=project_id, keys=keys, database_id=database_id) - return self._reserve_ids(request, retry=retry, timeout=timeout) + project_id=project_id, + keys=keys, + database_id=database_id, + ) + return self._reserve_ids( + request, retry=retry, timeout=timeout, metadata=metadata) diff --git a/datastore/google/cloud/datastore_v1/gapic/enums.py b/datastore/google/cloud/datastore_v1/gapic/enums.py index 31dc31d8e92f..893c098c92dc 100644 --- a/datastore/google/cloud/datastore_v1/gapic/enums.py +++ b/datastore/google/cloud/datastore_v1/gapic/enums.py @@ -1,10 +1,10 @@ -# Copyright 2017, Google LLC All rights reserved. +# Copyright 2018 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/datastore/google/cloud/datastore_v1/proto/datastore_pb2.py b/datastore/google/cloud/datastore_v1/proto/datastore_pb2.py index 688ff0bcfa4d..316bb6cce1eb 100644 --- a/datastore/google/cloud/datastore_v1/proto/datastore_pb2.py +++ b/datastore/google/cloud/datastore_v1/proto/datastore_pb2.py @@ -22,9 +22,10 @@ name='google/cloud/datastore_v1/proto/datastore.proto', package='google.datastore.v1', syntax='proto3', - serialized_pb=_b('\n/google/cloud/datastore_v1/proto/datastore.proto\x12\x13google.datastore.v1\x1a\x1cgoogle/api/annotations.proto\x1a,google/cloud/datastore_v1/proto/entity.proto\x1a+google/cloud/datastore_v1/proto/query.proto\"\x83\x01\n\rLookupRequest\x12\x12\n\nproject_id\x18\x08 \x01(\t\x12\x36\n\x0cread_options\x18\x01 \x01(\x0b\x32 .google.datastore.v1.ReadOptions\x12&\n\x04keys\x18\x03 \x03(\x0b\x32\x18.google.datastore.v1.Key\"\xa2\x01\n\x0eLookupResponse\x12\x30\n\x05\x66ound\x18\x01 \x03(\x0b\x32!.google.datastore.v1.EntityResult\x12\x32\n\x07missing\x18\x02 \x03(\x0b\x32!.google.datastore.v1.EntityResult\x12*\n\x08\x64\x65\x66\x65rred\x18\x03 \x03(\x0b\x32\x18.google.datastore.v1.Key\"\x84\x02\n\x0fRunQueryRequest\x12\x12\n\nproject_id\x18\x08 \x01(\t\x12\x36\n\x0cpartition_id\x18\x02 \x01(\x0b\x32 .google.datastore.v1.PartitionId\x12\x36\n\x0cread_options\x18\x01 \x01(\x0b\x32 .google.datastore.v1.ReadOptions\x12+\n\x05query\x18\x03 \x01(\x0b\x32\x1a.google.datastore.v1.QueryH\x00\x12\x32\n\tgql_query\x18\x07 \x01(\x0b\x32\x1d.google.datastore.v1.GqlQueryH\x00\x42\x0c\n\nquery_type\"s\n\x10RunQueryResponse\x12\x34\n\x05\x62\x61tch\x18\x01 \x01(\x0b\x32%.google.datastore.v1.QueryResultBatch\x12)\n\x05query\x18\x02 \x01(\x0b\x32\x1a.google.datastore.v1.Query\"s\n\x17\x42\x65ginTransactionRequest\x12\x12\n\nproject_id\x18\x08 \x01(\t\x12\x44\n\x13transaction_options\x18\n \x01(\x0b\x32\'.google.datastore.v1.TransactionOptions\"/\n\x18\x42\x65ginTransactionResponse\x12\x13\n\x0btransaction\x18\x01 \x01(\x0c\":\n\x0fRollbackRequest\x12\x12\n\nproject_id\x18\x08 \x01(\t\x12\x13\n\x0btransaction\x18\x01 \x01(\x0c\"\x12\n\x10RollbackResponse\"\x83\x02\n\rCommitRequest\x12\x12\n\nproject_id\x18\x08 \x01(\t\x12\x35\n\x04mode\x18\x05 \x01(\x0e\x32\'.google.datastore.v1.CommitRequest.Mode\x12\x15\n\x0btransaction\x18\x01 \x01(\x0cH\x00\x12\x30\n\tmutations\x18\x06 \x03(\x0b\x32\x1d.google.datastore.v1.Mutation\"F\n\x04Mode\x12\x14\n\x10MODE_UNSPECIFIED\x10\x00\x12\x11\n\rTRANSACTIONAL\x10\x01\x12\x15\n\x11NON_TRANSACTIONAL\x10\x02\x42\x16\n\x14transaction_selector\"f\n\x0e\x43ommitResponse\x12=\n\x10mutation_results\x18\x03 \x03(\x0b\x32#.google.datastore.v1.MutationResult\x12\x15\n\rindex_updates\x18\x04 \x01(\x05\"P\n\x12\x41llocateIdsRequest\x12\x12\n\nproject_id\x18\x08 \x01(\t\x12&\n\x04keys\x18\x01 \x03(\x0b\x32\x18.google.datastore.v1.Key\"=\n\x13\x41llocateIdsResponse\x12&\n\x04keys\x18\x01 \x03(\x0b\x32\x18.google.datastore.v1.Key\"d\n\x11ReserveIdsRequest\x12\x12\n\nproject_id\x18\x08 \x01(\t\x12\x13\n\x0b\x64\x61tabase_id\x18\t \x01(\t\x12&\n\x04keys\x18\x01 \x03(\x0b\x32\x18.google.datastore.v1.Key\"\x14\n\x12ReserveIdsResponse\"\x87\x02\n\x08Mutation\x12-\n\x06insert\x18\x04 \x01(\x0b\x32\x1b.google.datastore.v1.EntityH\x00\x12-\n\x06update\x18\x05 \x01(\x0b\x32\x1b.google.datastore.v1.EntityH\x00\x12-\n\x06upsert\x18\x06 \x01(\x0b\x32\x1b.google.datastore.v1.EntityH\x00\x12*\n\x06\x64\x65lete\x18\x07 \x01(\x0b\x32\x18.google.datastore.v1.KeyH\x00\x12\x16\n\x0c\x62\x61se_version\x18\x08 \x01(\x03H\x01\x42\x0b\n\toperationB\x1d\n\x1b\x63onflict_detection_strategy\"c\n\x0eMutationResult\x12%\n\x03key\x18\x03 \x01(\x0b\x32\x18.google.datastore.v1.Key\x12\x0f\n\x07version\x18\x04 \x01(\x03\x12\x19\n\x11\x63onflict_detected\x18\x05 \x01(\x08\"\xd5\x01\n\x0bReadOptions\x12L\n\x10read_consistency\x18\x01 \x01(\x0e\x32\x30.google.datastore.v1.ReadOptions.ReadConsistencyH\x00\x12\x15\n\x0btransaction\x18\x02 \x01(\x0cH\x00\"M\n\x0fReadConsistency\x12 \n\x1cREAD_CONSISTENCY_UNSPECIFIED\x10\x00\x12\n\n\x06STRONG\x10\x01\x12\x0c\n\x08\x45VENTUAL\x10\x02\x42\x12\n\x10\x63onsistency_type\"\xe3\x01\n\x12TransactionOptions\x12G\n\nread_write\x18\x01 \x01(\x0b\x32\x31.google.datastore.v1.TransactionOptions.ReadWriteH\x00\x12\x45\n\tread_only\x18\x02 \x01(\x0b\x32\x30.google.datastore.v1.TransactionOptions.ReadOnlyH\x00\x1a)\n\tReadWrite\x12\x1c\n\x14previous_transaction\x18\x01 \x01(\x0c\x1a\n\n\x08ReadOnlyB\x06\n\x04mode2\xec\x07\n\tDatastore\x12~\n\x06Lookup\x12\".google.datastore.v1.LookupRequest\x1a#.google.datastore.v1.LookupResponse\"+\x82\xd3\xe4\x93\x02%\" /v1/projects/{project_id}:lookup:\x01*\x12\x86\x01\n\x08RunQuery\x12$.google.datastore.v1.RunQueryRequest\x1a%.google.datastore.v1.RunQueryResponse\"-\x82\xd3\xe4\x93\x02\'\"\"/v1/projects/{project_id}:runQuery:\x01*\x12\xa6\x01\n\x10\x42\x65ginTransaction\x12,.google.datastore.v1.BeginTransactionRequest\x1a-.google.datastore.v1.BeginTransactionResponse\"5\x82\xd3\xe4\x93\x02/\"*/v1/projects/{project_id}:beginTransaction:\x01*\x12~\n\x06\x43ommit\x12\".google.datastore.v1.CommitRequest\x1a#.google.datastore.v1.CommitResponse\"+\x82\xd3\xe4\x93\x02%\" /v1/projects/{project_id}:commit:\x01*\x12\x86\x01\n\x08Rollback\x12$.google.datastore.v1.RollbackRequest\x1a%.google.datastore.v1.RollbackResponse\"-\x82\xd3\xe4\x93\x02\'\"\"/v1/projects/{project_id}:rollback:\x01*\x12\x92\x01\n\x0b\x41llocateIds\x12\'.google.datastore.v1.AllocateIdsRequest\x1a(.google.datastore.v1.AllocateIdsResponse\"0\x82\xd3\xe4\x93\x02*\"%/v1/projects/{project_id}:allocateIds:\x01*\x12\x8e\x01\n\nReserveIds\x12&.google.datastore.v1.ReserveIdsRequest\x1a\'.google.datastore.v1.ReserveIdsResponse\"/\x82\xd3\xe4\x93\x02)\"$/v1/projects/{project_id}:reserveIds:\x01*B\x85\x01\n\x17\x63om.google.datastore.v1B\x0e\x44\x61tastoreProtoP\x01Z\n\x0fproperty_filter\x18\x02 \x01(\x0b\x32#.google.datastore.v1.PropertyFilterH\x00\x42\r\n\x0b\x66ilter_type\"\xa9\x01\n\x0f\x43ompositeFilter\x12\x39\n\x02op\x18\x01 \x01(\x0e\x32-.google.datastore.v1.CompositeFilter.Operator\x12,\n\x07\x66ilters\x18\x02 \x03(\x0b\x32\x1b.google.datastore.v1.Filter\"-\n\x08Operator\x12\x18\n\x14OPERATOR_UNSPECIFIED\x10\x00\x12\x07\n\x03\x41ND\x10\x01\"\xc7\x02\n\x0ePropertyFilter\x12\x38\n\x08property\x18\x01 \x01(\x0b\x32&.google.datastore.v1.PropertyReference\x12\x38\n\x02op\x18\x02 \x01(\x0e\x32,.google.datastore.v1.PropertyFilter.Operator\x12)\n\x05value\x18\x03 \x01(\x0b\x32\x1a.google.datastore.v1.Value\"\x95\x01\n\x08Operator\x12\x18\n\x14OPERATOR_UNSPECIFIED\x10\x00\x12\r\n\tLESS_THAN\x10\x01\x12\x16\n\x12LESS_THAN_OR_EQUAL\x10\x02\x12\x10\n\x0cGREATER_THAN\x10\x03\x12\x19\n\x15GREATER_THAN_OR_EQUAL\x10\x04\x12\t\n\x05\x45QUAL\x10\x05\x12\x10\n\x0cHAS_ANCESTOR\x10\x0b\"\xa5\x02\n\x08GqlQuery\x12\x14\n\x0cquery_string\x18\x01 \x01(\t\x12\x16\n\x0e\x61llow_literals\x18\x02 \x01(\x08\x12H\n\x0enamed_bindings\x18\x05 \x03(\x0b\x32\x30.google.datastore.v1.GqlQuery.NamedBindingsEntry\x12\x43\n\x13positional_bindings\x18\x04 \x03(\x0b\x32&.google.datastore.v1.GqlQueryParameter\x1a\\\n\x12NamedBindingsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x35\n\x05value\x18\x02 \x01(\x0b\x32&.google.datastore.v1.GqlQueryParameter:\x02\x38\x01\"d\n\x11GqlQueryParameter\x12+\n\x05value\x18\x02 \x01(\x0b\x32\x1a.google.datastore.v1.ValueH\x00\x12\x10\n\x06\x63ursor\x18\x03 \x01(\x0cH\x00\x42\x10\n\x0eparameter_type\"\xde\x03\n\x10QueryResultBatch\x12\x17\n\x0fskipped_results\x18\x06 \x01(\x05\x12\x16\n\x0eskipped_cursor\x18\x03 \x01(\x0c\x12H\n\x12\x65ntity_result_type\x18\x01 \x01(\x0e\x32,.google.datastore.v1.EntityResult.ResultType\x12\x39\n\x0e\x65ntity_results\x18\x02 \x03(\x0b\x32!.google.datastore.v1.EntityResult\x12\x12\n\nend_cursor\x18\x04 \x01(\x0c\x12K\n\x0cmore_results\x18\x05 \x01(\x0e\x32\x35.google.datastore.v1.QueryResultBatch.MoreResultsType\x12\x18\n\x10snapshot_version\x18\x07 \x01(\x03\"\x98\x01\n\x0fMoreResultsType\x12!\n\x1dMORE_RESULTS_TYPE_UNSPECIFIED\x10\x00\x12\x10\n\x0cNOT_FINISHED\x10\x01\x12\x1c\n\x18MORE_RESULTS_AFTER_LIMIT\x10\x02\x12\x1d\n\x19MORE_RESULTS_AFTER_CURSOR\x10\x04\x12\x13\n\x0fNO_MORE_RESULTS\x10\x03\x42\x81\x01\n\x17\x63om.google.datastore.v1B\nQueryProtoP\x01Z\n\x0fproperty_filter\x18\x02 \x01(\x0b\x32#.google.datastore.v1.PropertyFilterH\x00\x42\r\n\x0b\x66ilter_type\"\xa9\x01\n\x0f\x43ompositeFilter\x12\x39\n\x02op\x18\x01 \x01(\x0e\x32-.google.datastore.v1.CompositeFilter.Operator\x12,\n\x07\x66ilters\x18\x02 \x03(\x0b\x32\x1b.google.datastore.v1.Filter\"-\n\x08Operator\x12\x18\n\x14OPERATOR_UNSPECIFIED\x10\x00\x12\x07\n\x03\x41ND\x10\x01\"\xc7\x02\n\x0ePropertyFilter\x12\x38\n\x08property\x18\x01 \x01(\x0b\x32&.google.datastore.v1.PropertyReference\x12\x38\n\x02op\x18\x02 \x01(\x0e\x32,.google.datastore.v1.PropertyFilter.Operator\x12)\n\x05value\x18\x03 \x01(\x0b\x32\x1a.google.datastore.v1.Value\"\x95\x01\n\x08Operator\x12\x18\n\x14OPERATOR_UNSPECIFIED\x10\x00\x12\r\n\tLESS_THAN\x10\x01\x12\x16\n\x12LESS_THAN_OR_EQUAL\x10\x02\x12\x10\n\x0cGREATER_THAN\x10\x03\x12\x19\n\x15GREATER_THAN_OR_EQUAL\x10\x04\x12\t\n\x05\x45QUAL\x10\x05\x12\x10\n\x0cHAS_ANCESTOR\x10\x0b\"\xa5\x02\n\x08GqlQuery\x12\x14\n\x0cquery_string\x18\x01 \x01(\t\x12\x16\n\x0e\x61llow_literals\x18\x02 \x01(\x08\x12H\n\x0enamed_bindings\x18\x05 \x03(\x0b\x32\x30.google.datastore.v1.GqlQuery.NamedBindingsEntry\x12\x43\n\x13positional_bindings\x18\x04 \x03(\x0b\x32&.google.datastore.v1.GqlQueryParameter\x1a\\\n\x12NamedBindingsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x35\n\x05value\x18\x02 \x01(\x0b\x32&.google.datastore.v1.GqlQueryParameter:\x02\x38\x01\"d\n\x11GqlQueryParameter\x12+\n\x05value\x18\x02 \x01(\x0b\x32\x1a.google.datastore.v1.ValueH\x00\x12\x10\n\x06\x63ursor\x18\x03 \x01(\x0cH\x00\x42\x10\n\x0eparameter_type\"\xde\x03\n\x10QueryResultBatch\x12\x17\n\x0fskipped_results\x18\x06 \x01(\x05\x12\x16\n\x0eskipped_cursor\x18\x03 \x01(\x0c\x12H\n\x12\x65ntity_result_type\x18\x01 \x01(\x0e\x32,.google.datastore.v1.EntityResult.ResultType\x12\x39\n\x0e\x65ntity_results\x18\x02 \x03(\x0b\x32!.google.datastore.v1.EntityResult\x12\x12\n\nend_cursor\x18\x04 \x01(\x0c\x12K\n\x0cmore_results\x18\x05 \x01(\x0e\x32\x35.google.datastore.v1.QueryResultBatch.MoreResultsType\x12\x18\n\x10snapshot_version\x18\x07 \x01(\x03\"\x98\x01\n\x0fMoreResultsType\x12!\n\x1dMORE_RESULTS_TYPE_UNSPECIFIED\x10\x00\x12\x10\n\x0cNOT_FINISHED\x10\x01\x12\x1c\n\x18MORE_RESULTS_AFTER_LIMIT\x10\x02\x12\x1d\n\x19MORE_RESULTS_AFTER_CURSOR\x10\x04\x12\x13\n\x0fNO_MORE_RESULTS\x10\x03\x42\x9d\x01\n\x17\x63om.google.datastore.v1B\nQueryProtoP\x01Z= 0.28.0, < 0.29dev', - 'google-api-core >= 0.1.1, < 0.2.0dev', - 'google-auth >= 1.0.2, < 2.0dev', - 'google-gax >= 0.15.15, < 0.16dev', - 'googleapis-common-protos[grpc] >= 1.5.2, < 2.0dev', - 'requests >= 2.18.4, < 3.0dev', + 'google-api-core[grpc] >= 0.1.1, < 0.2.0dev', ] setup( diff --git a/datastore/tests/unit/gapic/v1/test_datastore_client_v1.py b/datastore/tests/unit/gapic/v1/test_datastore_client_v1.py new file mode 100644 index 000000000000..0ac8a955480a --- /dev/null +++ b/datastore/tests/unit/gapic/v1/test_datastore_client_v1.py @@ -0,0 +1,305 @@ +# Copyright 2018 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 +# +# 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. +"""Unit tests.""" + +import pytest + +from google.cloud import datastore_v1 +from google.cloud.datastore_v1 import enums +from google.cloud.datastore_v1.proto import datastore_pb2 +from google.cloud.datastore_v1.proto import entity_pb2 + + +class MultiCallableStub(object): + """Stub for the grpc.UnaryUnaryMultiCallable interface.""" + + def __init__(self, method, channel_stub): + self.method = method + self.channel_stub = channel_stub + + def __call__(self, request, timeout=None, metadata=None, credentials=None): + self.channel_stub.requests.append((self.method, request)) + + response = None + if self.channel_stub.responses: + response = self.channel_stub.responses.pop() + + 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) + + +class CustomException(Exception): + pass + + +class TestDatastoreClient(object): + def test_lookup(self): + # Setup Expected Response + expected_response = {} + expected_response = datastore_pb2.LookupResponse(**expected_response) + + # Mock the API response + channel = ChannelStub(responses=[expected_response]) + client = datastore_v1.DatastoreClient(channel=channel) + + # Setup Request + project_id = 'projectId-1969970175' + keys = [] + + response = client.lookup(project_id, keys) + assert expected_response == response + + assert len(channel.requests) == 1 + expected_request = datastore_pb2.LookupRequest( + project_id=project_id, keys=keys) + actual_request = channel.requests[0][1] + assert expected_request == actual_request + + def test_lookup_exception(self): + # Mock the API response + channel = ChannelStub(responses=[CustomException()]) + client = datastore_v1.DatastoreClient(channel=channel) + + # Setup request + project_id = 'projectId-1969970175' + keys = [] + + with pytest.raises(CustomException): + client.lookup(project_id, keys) + + def test_run_query(self): + # Setup Expected Response + expected_response = {} + expected_response = datastore_pb2.RunQueryResponse(**expected_response) + + # Mock the API response + channel = ChannelStub(responses=[expected_response]) + client = datastore_v1.DatastoreClient(channel=channel) + + # Setup Request + project_id = 'projectId-1969970175' + partition_id = {} + + response = client.run_query(project_id, partition_id) + assert expected_response == response + + assert len(channel.requests) == 1 + expected_request = datastore_pb2.RunQueryRequest( + project_id=project_id, partition_id=partition_id) + actual_request = channel.requests[0][1] + assert expected_request == actual_request + + def test_run_query_exception(self): + # Mock the API response + channel = ChannelStub(responses=[CustomException()]) + client = datastore_v1.DatastoreClient(channel=channel) + + # Setup request + project_id = 'projectId-1969970175' + partition_id = {} + + with pytest.raises(CustomException): + client.run_query(project_id, partition_id) + + def test_begin_transaction(self): + # Setup Expected Response + transaction = b'-34' + expected_response = {'transaction': transaction} + expected_response = datastore_pb2.BeginTransactionResponse( + **expected_response) + + # Mock the API response + channel = ChannelStub(responses=[expected_response]) + client = datastore_v1.DatastoreClient(channel=channel) + + # Setup Request + project_id = 'projectId-1969970175' + + response = client.begin_transaction(project_id) + assert expected_response == response + + assert len(channel.requests) == 1 + expected_request = datastore_pb2.BeginTransactionRequest( + project_id=project_id) + actual_request = channel.requests[0][1] + assert expected_request == actual_request + + def test_begin_transaction_exception(self): + # Mock the API response + channel = ChannelStub(responses=[CustomException()]) + client = datastore_v1.DatastoreClient(channel=channel) + + # Setup request + project_id = 'projectId-1969970175' + + with pytest.raises(CustomException): + client.begin_transaction(project_id) + + def test_commit(self): + # Setup Expected Response + index_updates = 1425228195 + expected_response = {'index_updates': index_updates} + expected_response = datastore_pb2.CommitResponse(**expected_response) + + # Mock the API response + channel = ChannelStub(responses=[expected_response]) + client = datastore_v1.DatastoreClient(channel=channel) + + # Setup Request + project_id = 'projectId-1969970175' + mode = enums.CommitRequest.Mode.MODE_UNSPECIFIED + mutations = [] + + response = client.commit(project_id, mode, mutations) + assert expected_response == response + + assert len(channel.requests) == 1 + expected_request = datastore_pb2.CommitRequest( + project_id=project_id, mode=mode, mutations=mutations) + actual_request = channel.requests[0][1] + assert expected_request == actual_request + + def test_commit_exception(self): + # Mock the API response + channel = ChannelStub(responses=[CustomException()]) + client = datastore_v1.DatastoreClient(channel=channel) + + # Setup request + project_id = 'projectId-1969970175' + mode = enums.CommitRequest.Mode.MODE_UNSPECIFIED + mutations = [] + + with pytest.raises(CustomException): + client.commit(project_id, mode, mutations) + + def test_rollback(self): + # Setup Expected Response + expected_response = {} + expected_response = datastore_pb2.RollbackResponse(**expected_response) + + # Mock the API response + channel = ChannelStub(responses=[expected_response]) + client = datastore_v1.DatastoreClient(channel=channel) + + # Setup Request + project_id = 'projectId-1969970175' + transaction = b'-34' + + response = client.rollback(project_id, transaction) + assert expected_response == response + + assert len(channel.requests) == 1 + expected_request = datastore_pb2.RollbackRequest( + project_id=project_id, transaction=transaction) + actual_request = channel.requests[0][1] + assert expected_request == actual_request + + def test_rollback_exception(self): + # Mock the API response + channel = ChannelStub(responses=[CustomException()]) + client = datastore_v1.DatastoreClient(channel=channel) + + # Setup request + project_id = 'projectId-1969970175' + transaction = b'-34' + + with pytest.raises(CustomException): + client.rollback(project_id, transaction) + + def test_allocate_ids(self): + # Setup Expected Response + expected_response = {} + expected_response = datastore_pb2.AllocateIdsResponse( + **expected_response) + + # Mock the API response + channel = ChannelStub(responses=[expected_response]) + client = datastore_v1.DatastoreClient(channel=channel) + + # Setup Request + project_id = 'projectId-1969970175' + keys = [] + + response = client.allocate_ids(project_id, keys) + assert expected_response == response + + assert len(channel.requests) == 1 + expected_request = datastore_pb2.AllocateIdsRequest( + project_id=project_id, keys=keys) + actual_request = channel.requests[0][1] + assert expected_request == actual_request + + def test_allocate_ids_exception(self): + # Mock the API response + channel = ChannelStub(responses=[CustomException()]) + client = datastore_v1.DatastoreClient(channel=channel) + + # Setup request + project_id = 'projectId-1969970175' + keys = [] + + with pytest.raises(CustomException): + client.allocate_ids(project_id, keys) + + def test_reserve_ids(self): + # Setup Expected Response + expected_response = {} + expected_response = datastore_pb2.ReserveIdsResponse( + **expected_response) + + # Mock the API response + channel = ChannelStub(responses=[expected_response]) + client = datastore_v1.DatastoreClient(channel=channel) + + # Setup Request + project_id = 'projectId-1969970175' + keys = [] + + response = client.reserve_ids(project_id, keys) + assert expected_response == response + + assert len(channel.requests) == 1 + expected_request = datastore_pb2.ReserveIdsRequest( + project_id=project_id, keys=keys) + actual_request = channel.requests[0][1] + assert expected_request == actual_request + + def test_reserve_ids_exception(self): + # Mock the API response + channel = ChannelStub(responses=[CustomException()]) + client = datastore_v1.DatastoreClient(channel=channel) + + # Setup request + project_id = 'projectId-1969970175' + keys = [] + + with pytest.raises(CustomException): + client.reserve_ids(project_id, keys) diff --git a/datastore/tests/unit/test__gapic.py b/datastore/tests/unit/test__gapic.py new file mode 100644 index 000000000000..f971eef7c4d9 --- /dev/null +++ b/datastore/tests/unit/test__gapic.py @@ -0,0 +1,75 @@ +# 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 +# +# 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. + +import unittest + +import mock + +from google.cloud.datastore.client import _HAVE_GRPC + + +@unittest.skipUnless(_HAVE_GRPC, 'No gRPC') +class Test_make_datastore_api(unittest.TestCase): + + def _call_fut(self, client): + from google.cloud.datastore._gapic import make_datastore_api + + return make_datastore_api(client) + + @mock.patch( + 'google.cloud.datastore_v1.gapic.datastore_client.DatastoreClient', + return_value=mock.sentinel.ds_client) + @mock.patch('google.cloud.datastore._gapic.make_secure_channel', + return_value=mock.sentinel.channel) + def test_live_api(self, make_chan, mock_klass): + from google.cloud._http import DEFAULT_USER_AGENT + + base_url = 'https://datastore.googleapis.com:443' + client = mock.Mock( + _base_url=base_url, + _credentials=mock.sentinel.credentials, + spec=['_base_url', '_credentials']) + ds_api = self._call_fut(client) + self.assertIs(ds_api, mock.sentinel.ds_client) + + make_chan.assert_called_once_with( + mock.sentinel.credentials, + DEFAULT_USER_AGENT, + 'datastore.googleapis.com:443') + mock_klass.assert_called_once_with( + channel=mock.sentinel.channel, + client_info=mock.ANY, + ) + + @mock.patch( + 'google.cloud.datastore_v1.gapic.datastore_client.DatastoreClient', + return_value=mock.sentinel.ds_client) + @mock.patch('google.cloud.datastore._gapic.insecure_channel', + return_value=mock.sentinel.channel) + def test_emulator(self, make_chan, mock_klass): + + host = 'localhost:8901' + base_url = 'http://' + host + client = mock.Mock( + _base_url=base_url, + _credentials=mock.sentinel.credentials, + spec=['_base_url', '_credentials']) + ds_api = self._call_fut(client) + self.assertIs(ds_api, mock.sentinel.ds_client) + + make_chan.assert_called_once_with(host) + mock_klass.assert_called_once_with( + channel=mock.sentinel.channel, + client_info=mock.ANY, + ) diff --git a/datastore/tests/unit/test__gax.py b/datastore/tests/unit/test__gax.py deleted file mode 100644 index 9f0896058fe3..000000000000 --- a/datastore/tests/unit/test__gax.py +++ /dev/null @@ -1,280 +0,0 @@ -# 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 -# -# 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. - -import unittest - -import mock - -from google.cloud.datastore.client import _HAVE_GRPC - - -@unittest.skipUnless(_HAVE_GRPC, 'No gRPC') -class Test__catch_remap_gax_error(unittest.TestCase): - - def _call_fut(self): - from google.cloud.datastore._gax import _catch_remap_gax_error - - return _catch_remap_gax_error() - - @staticmethod - def _fake_method(exc, result=None): - if exc is None: - return result - else: - raise exc - - @staticmethod - def _make_rendezvous(status_code, details): - from grpc._channel import _RPCState - from google.cloud.exceptions import GrpcRendezvous - - exc_state = _RPCState((), None, None, status_code, details) - return GrpcRendezvous(exc_state, None, None, None) - - def test_success(self): - expected = object() - with self._call_fut(): - result = self._fake_method(None, expected) - self.assertIs(result, expected) - - def test_non_grpc_err(self): - exc = RuntimeError('Not a gRPC error') - with self.assertRaises(RuntimeError): - with self._call_fut(): - self._fake_method(exc) - - def test_gax_error(self): - from google.gax.errors import GaxError - from grpc import StatusCode - from google.cloud.exceptions import Forbidden - - # First, create low-level GrpcRendezvous exception. - details = 'Some error details.' - cause = self._make_rendezvous(StatusCode.PERMISSION_DENIED, details) - # Then put it into a high-level GaxError. - msg = 'GAX Error content.' - exc = GaxError(msg, cause=cause) - - with self.assertRaises(Forbidden): - with self._call_fut(): - self._fake_method(exc) - - def test_gax_error_not_mapped(self): - from google.gax.errors import GaxError - from grpc import StatusCode - - cause = self._make_rendezvous(StatusCode.CANCELLED, None) - exc = GaxError(None, cause=cause) - - with self.assertRaises(GaxError): - with self._call_fut(): - self._fake_method(exc) - - -@unittest.skipUnless(_HAVE_GRPC, 'No gRPC') -class TestGAPICDatastoreAPI(unittest.TestCase): - - @staticmethod - def _get_target_class(): - from google.cloud.datastore._gax import GAPICDatastoreAPI - - return GAPICDatastoreAPI - - def _make_one(self, *args, **kwargs): - return self._get_target_class()(*args, **kwargs) - - def test_lookup(self): - from google.cloud.datastore_v1.gapic import datastore_client - - patch1 = mock.patch.object( - datastore_client.DatastoreClient, '__init__', - return_value=None) - patch2 = mock.patch.object(datastore_client.DatastoreClient, 'lookup') - patch3 = mock.patch( - 'google.cloud.datastore._gax._catch_remap_gax_error') - - with patch1 as mock_constructor: - ds_api = self._make_one() - mock_constructor.assert_called_once_with() - with patch2 as mock_lookup: - with patch3 as mock_catch_rendezvous: - mock_catch_rendezvous.assert_not_called() - ds_api.lookup(None, True, bb='cc') - mock_lookup.assert_called_once_with(None, True, bb='cc') - mock_catch_rendezvous.assert_called_once_with() - - def test_run_query(self): - from google.cloud.datastore_v1.gapic import datastore_client - - patch1 = mock.patch.object( - datastore_client.DatastoreClient, '__init__', - return_value=None) - patch2 = mock.patch.object( - datastore_client.DatastoreClient, 'run_query') - patch3 = mock.patch( - 'google.cloud.datastore._gax._catch_remap_gax_error') - - with patch1 as mock_constructor: - ds_api = self._make_one() - mock_constructor.assert_called_once_with() - with patch2 as mock_run_query: - with patch3 as mock_catch_rendezvous: - mock_catch_rendezvous.assert_not_called() - ds_api.run_query('47a', none=None) - mock_run_query.assert_called_once_with('47a', none=None) - mock_catch_rendezvous.assert_called_once_with() - - def test_begin_transaction(self): - from google.cloud.datastore_v1.gapic import datastore_client - - patch1 = mock.patch.object( - datastore_client.DatastoreClient, '__init__', - return_value=None) - patch2 = mock.patch.object( - datastore_client.DatastoreClient, 'begin_transaction') - patch3 = mock.patch( - 'google.cloud.datastore._gax._catch_remap_gax_error') - - with patch1 as mock_constructor: - ds_api = self._make_one() - mock_constructor.assert_called_once_with() - with patch2 as mock_begin_transaction: - with patch3 as mock_catch_rendezvous: - mock_catch_rendezvous.assert_not_called() - ds_api.begin_transaction('a', 'b', [], key='kei') - mock_begin_transaction.assert_called_once_with( - 'a', 'b', [], key='kei') - mock_catch_rendezvous.assert_called_once_with() - - def test_commit(self): - from google.cloud.datastore_v1.gapic import datastore_client - - patch1 = mock.patch.object( - datastore_client.DatastoreClient, '__init__', - return_value=None) - patch2 = mock.patch.object(datastore_client.DatastoreClient, 'commit') - patch3 = mock.patch( - 'google.cloud.datastore._gax._catch_remap_gax_error') - - with patch1 as mock_constructor: - ds_api = self._make_one() - mock_constructor.assert_called_once_with() - with patch2 as mock_commit: - with patch3 as mock_catch_rendezvous: - mock_catch_rendezvous.assert_not_called() - ds_api.commit(1, 2, a=3) - mock_commit.assert_called_once_with(1, 2, a=3) - mock_catch_rendezvous.assert_called_once_with() - - def test_rollback(self): - from google.cloud.datastore_v1.gapic import datastore_client - - patch1 = mock.patch.object( - datastore_client.DatastoreClient, '__init__', - return_value=None) - patch2 = mock.patch.object( - datastore_client.DatastoreClient, 'rollback') - patch3 = mock.patch( - 'google.cloud.datastore._gax._catch_remap_gax_error') - - with patch1 as mock_constructor: - ds_api = self._make_one() - mock_constructor.assert_called_once_with() - with patch2 as mock_rollback: - with patch3 as mock_catch_rendezvous: - mock_catch_rendezvous.assert_not_called() - ds_api.rollback(11, 12, arp='marp') - mock_rollback.assert_called_once_with(11, 12, arp='marp') - mock_catch_rendezvous.assert_called_once_with() - - def test_allocate_ids(self): - from google.cloud.datastore_v1.gapic import datastore_client - - patch1 = mock.patch.object( - datastore_client.DatastoreClient, '__init__', - return_value=None) - patch2 = mock.patch.object( - datastore_client.DatastoreClient, 'allocate_ids') - patch3 = mock.patch( - 'google.cloud.datastore._gax._catch_remap_gax_error') - - with patch1 as mock_constructor: - ds_api = self._make_one() - mock_constructor.assert_called_once_with() - with patch2 as mock_allocate_ids: - with patch3 as mock_catch_rendezvous: - mock_catch_rendezvous.assert_not_called() - ds_api.allocate_ids( - 'hey', 'bai', bye=(47, 4), shy={'a': 4}) - mock_allocate_ids.assert_called_once_with( - 'hey', 'bai', bye=(47, 4), shy={'a': 4}) - mock_catch_rendezvous.assert_called_once_with() - - -@unittest.skipUnless(_HAVE_GRPC, 'No gRPC') -class Test_make_datastore_api(unittest.TestCase): - - def _call_fut(self, client): - from google.cloud.datastore._gax import make_datastore_api - - return make_datastore_api(client) - - @mock.patch( - 'google.cloud.datastore._gax.GAPICDatastoreAPI', - return_value=mock.sentinel.ds_client) - @mock.patch('google.cloud.datastore._gax.make_secure_channel', - return_value=mock.sentinel.channel) - def test_live_api(self, make_chan, mock_klass): - from google.cloud.datastore_v1.gapic import datastore_client - from google.cloud._http import DEFAULT_USER_AGENT - from google.cloud.datastore import __version__ - - host = datastore_client.DatastoreClient.SERVICE_ADDRESS - base_url = 'https://' + host - client = mock.Mock( - _base_url=base_url, - _credentials=mock.sentinel.credentials, - spec=['_base_url', '_credentials']) - ds_api = self._call_fut(client) - self.assertIs(ds_api, mock.sentinel.ds_client) - - make_chan.assert_called_once_with( - mock.sentinel.credentials, DEFAULT_USER_AGENT, host) - mock_klass.assert_called_once_with( - channel=mock.sentinel.channel, - client_info=mock.ANY, - ) - - @mock.patch( - 'google.cloud.datastore._gax.GAPICDatastoreAPI', - return_value=mock.sentinel.ds_client) - @mock.patch('google.cloud.datastore._gax.insecure_channel', - return_value=mock.sentinel.channel) - def test_emulator(self, make_chan, mock_klass): - from google.cloud.datastore import __version__ - - host = 'localhost:8901' - base_url = 'http://' + host - client = mock.Mock( - _base_url=base_url, - _credentials=mock.sentinel.credentials, - spec=['_base_url', '_credentials']) - ds_api = self._call_fut(client) - self.assertIs(ds_api, mock.sentinel.ds_client) - - make_chan.assert_called_once_with(host) - mock_klass.assert_called_once_with( - channel=mock.sentinel.channel, - client_info=mock.ANY, - ) diff --git a/datastore/tests/unit/test_client.py b/datastore/tests/unit/test_client.py index 949753e75f3b..e43a61022ab6 100644 --- a/datastore/tests/unit/test_client.py +++ b/datastore/tests/unit/test_client.py @@ -232,7 +232,7 @@ def test_constructor_gcd_host(self): project=project, credentials=creds, _http=http) self.assertEqual(client._base_url, 'http://' + host) - def test__datastore_api_property_gax(self): + def test__datastore_api_property_gapic(self): client = self._make_one( project='prahj-ekt', credentials=_make_credentials(), _http=object(), _use_grpc=True)