From 55d2bc6580e5db0f837de1b245533a8f1f2e9beb Mon Sep 17 00:00:00 2001 From: Bu Sun Kim <8822365+busunkim96@users.noreply.github.com> Date: Mon, 10 Jan 2022 08:56:39 -0700 Subject: [PATCH] feat: add snippet index (#1121) This PR adds snippet_metadata.proto and another samplegen utils class to store the snippets so that they can be looked up by library template code. PRs to begin generating metadata and add the samples to the library docstrings will follow (I originally planned it for one PR, but the changeset was a bit too big). --- gapic/samplegen_utils/snippet_index.py | 175 ++++ gapic/samplegen_utils/snippet_metadata.proto | 319 +++++++ gapic/samplegen_utils/snippet_metadata_pb2.py | 840 ++++++++++++++++++ tests/unit/samplegen/common_types.py | 2 +- tests/unit/samplegen/test_snippet_index.py | 229 +++++ 5 files changed, 1564 insertions(+), 1 deletion(-) create mode 100644 gapic/samplegen_utils/snippet_index.py create mode 100644 gapic/samplegen_utils/snippet_metadata.proto create mode 100644 gapic/samplegen_utils/snippet_metadata_pb2.py create mode 100644 tests/unit/samplegen/test_snippet_index.py diff --git a/gapic/samplegen_utils/snippet_index.py b/gapic/samplegen_utils/snippet_index.py new file mode 100644 index 0000000000..a8594a92ee --- /dev/null +++ b/gapic/samplegen_utils/snippet_index.py @@ -0,0 +1,175 @@ +# Copyright 2022 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. + +from typing import Optional, Dict +import re + +from google.protobuf import json_format + +from gapic.schema import api, metadata +from gapic.samplegen_utils import snippet_metadata_pb2 # type: ignore +from gapic.samplegen_utils import types + + +CLIENT_INIT_RE = re.compile(r"^\s+# Create a client") +REQUEST_INIT_RE = re.compile(r"^\s+# Initialize request argument\(s\)") +REQUEST_EXEC_RE = re.compile(r"^\s+# Make the request") +RESPONSE_HANDLING_RE = re.compile(r"^\s+# Handle response") + + +class Snippet: + """A single snippet and its metadata. + + Attributes: + sample_str (str): The full text of the code snippet. + metadata (snippet_metadata_pb2.Snippet): The snippet's metadata. + """ + + def __init__(self, sample_str: str, sample_metadata): + self.sample_str = sample_str + self.metadata = sample_metadata + self._parse_snippet_segments() + + def _parse_snippet_segments(self): + """Parse sections of the sample string and update metadata""" + self.sample_lines = self.sample_str.splitlines(keepends=True) + + self._full_snippet = snippet_metadata_pb2.Snippet.Segment( + type=snippet_metadata_pb2.Snippet.Segment.SegmentType.FULL) + self._short_snippet = snippet_metadata_pb2.Snippet.Segment( + type=snippet_metadata_pb2.Snippet.Segment.SegmentType.SHORT) + self._client_init = snippet_metadata_pb2.Snippet.Segment( + type=snippet_metadata_pb2.Snippet.Segment.SegmentType.CLIENT_INITIALIZATION) + self._request_init = snippet_metadata_pb2.Snippet.Segment( + type=snippet_metadata_pb2.Snippet.Segment.SegmentType.REQUEST_INITIALIZATION) + self._request_exec = snippet_metadata_pb2.Snippet.Segment( + type=snippet_metadata_pb2.Snippet.Segment.SegmentType.REQUEST_EXECUTION) + self._response_handling = snippet_metadata_pb2.Snippet.Segment( + type=snippet_metadata_pb2.Snippet.Segment.SegmentType.RESPONSE_HANDLING, + end=len(self.sample_lines) + ) + + # Index starts at 1 since these represent line numbers + for i, line in enumerate(self.sample_lines, start=1): + if line.startswith("# [START"): # do not include region tag lines + self._full_snippet.start = i + 1 + self._short_snippet.start = self._full_snippet.start + elif line.startswith("# [END"): + self._full_snippet.end = i - 1 + self._short_snippet.end = self._full_snippet.end + elif CLIENT_INIT_RE.match(line): + self._client_init.start = i + elif REQUEST_INIT_RE.match(line): + self._client_init.end = i - 1 + self._request_init.start = i + elif REQUEST_EXEC_RE.match(line): + self._request_init.end = i - 1 + self._request_exec.start = i + elif RESPONSE_HANDLING_RE.match(line): + self._request_exec.end = i - 1 + self._response_handling.start = i + + self.metadata.segments.extend([self._full_snippet, self._short_snippet, self._client_init, + self._request_init, self._request_exec, self._response_handling]) + + @property + def full_snippet(self) -> str: + """The portion between the START and END region tags.""" + start_idx = self._full_snippet.start - 1 + end_idx = self._full_snippet.end + return "".join(self.sample_lines[start_idx:end_idx]) + + +class SnippetIndex: + """An index of all the snippets for an API. + + Attributes: + metadata_index (snippet_metadata_pb2.Index): The snippet metadata index. + """ + + def __init__(self, api_schema: api.API): + self.metadata_index = snippet_metadata_pb2.Index() # type: ignore + + # Construct a dictionary to insert samples into based on the API schema + # NOTE: In the future we expect the generator to support configured samples, + # which will result in more than one sample variant per RPC. At that + # time a different data structure (and re-writes of add_snippet and get_snippet) + # will be needed. + self._index: Dict[str, Dict[str, Dict[str, Optional[Snippet]]]] = {} + + self._index = { + s.name: {m: {"sync": None, "async": None} for m in s.methods} + for s in api_schema.services.values() + } + + def add_snippet(self, snippet: Snippet) -> None: + """Add a single snippet to the snippet index. + + Args: + snippet (Snippet): The code snippet to be added. + + Raises: + UnknownService: If the service indicated by the snippet metadata is not found. + RpcMethodNotFound: If the method indicated by the snippet metadata is not found. + """ + service_name = snippet.metadata.client_method.method.service.short_name + rpc_name = snippet.metadata.client_method.method.full_name + + service = self._index.get(service_name) + if service is None: + raise types.UnknownService( + "API does not have a service named '{}'.".format(service_name)) + + method = service.get(rpc_name) + if method is None: + raise types.RpcMethodNotFound( + "API does not have method '{}' in service '{}'".format(rpc_name, service_name)) + + if getattr(snippet.metadata.client_method, "async"): + method["async"] = snippet + else: + method["sync"] = snippet + + self.metadata_index.snippets.append(snippet.metadata) + + def get_snippet(self, service_name: str, rpc_name: str, sync: bool = True) -> Optional[Snippet]: + """Fetch a single snippet from the index. + + Args: + service_name (str): The name of the service. + rpc_name (str): The name of the RPC. + sync (bool): True for the sync version of the snippet, False for the async version. + + Returns: + Optional[Snippet]: The snippet if it exists, or None. + + Raises: + UnknownService: If the service is not found. + RpcMethodNotFound: If the method is not found. + """ + # Fetch a snippet from the snippet metadata index + service = self._index.get(service_name) + if service is None: + raise types.UnknownService( + "API does not have a service named '{}'.".format(service_name)) + method = service.get(rpc_name) + if method is None: + raise types.RpcMethodNotFound( + "API does not have method '{}' in service '{}'".format(rpc_name, service_name)) + + return method["sync" if sync else "async"] + + def get_metadata_json(self) -> str: + """JSON representation of Snippet Index.""" + return json_format.MessageToJson(self.metadata_index, sort_keys=True) diff --git a/gapic/samplegen_utils/snippet_metadata.proto b/gapic/samplegen_utils/snippet_metadata.proto new file mode 100644 index 0000000000..398dc9b27c --- /dev/null +++ b/gapic/samplegen_utils/snippet_metadata.proto @@ -0,0 +1,319 @@ +// Copyright 2021 Google Inc. 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 +// +// 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. + +// NOTE(busunkim): This is a temporary home for this file and the corresponding +// snippet_metadata_pb2.py. + +syntax = "proto3"; + +package google.cloud.tools.snippetgen.snippetindex.v1; + +option csharp_namespace = "Google.Cloud.Tools.SnippetGen.SnippetIndex.V1"; +option php_namespace = "Google\\Cloud\\Tools\\SnippetGen\\SnippetIndex\\V1"; +option ruby_package = "Google::Cloud::Tools::SnippetGen::SnippetIndex::V1"; + +// The snippet index for a single client library. +message Index { + // The Client Library these snippets are for. + ClientLibrary client_library = 1; + + // The list of snippets. + repeated Snippet snippets = 2; +} + +// One sample. +// Parts of this information will be language specific. +message Snippet { + // The region tag name. Does not include the square brackets or the START or + // END indicators. + string region_tag = 1; + + // The title of the snippet, for human consumption mostly. For generated + // snippets this may be the snippet method or file name, or obtained from + /// snippet configuration. + string title = 2; + + // A description of the snippet, for human consumption mostly. For generated + // snippets this may be the description of the service method, or obtained + // from snippet configuration. + string description = 3; + + // The file where the snippet code lives. + // The path should be relative to where this metadata file is stored on the + // GitHub repo root and should not include branch, tag, commitish, etc., + // as those will be the same as for the metadata file. + string file = 4; + + // The programming language the snippet is written in. + // This will match the client library language most of the time, but not + // always. For instance, in .NET, libraries are written in C# but some samples + // may be written in F# or VB .NET. + // Note that this does not contain information about the snippet supported + // platforms or language versions, etc. This is just a quick way to identify + // the generally supported langauge. + Language language = 5; + + // The client library method this snippet is for. + ClientMethod client_method = 6; + + // Wether this is the canonical snippet for the corresponding service method. + // This is to be interpreted in conjunction with origin as follows: + // For a given service method: + // - A handwritten canonical takes precedence over + // - A config canonical which in turn takes precedence over + // - A baseline canonical. + bool canonical = 7; + + // The origin of the snippet. + Origin origin = 8; + + // The different segments of the snippet. + // Must contain the FULL segment always. + // There may be overlap between segments. + repeated Segment segments = 9; + + // The origin of the snippet. + enum Origin { + // The origin has not been specified. Consumers should not see this value. + ORIGIN_UNSPECIFIED = 0; + + // The snippet is generated from the API definition only, including protos + // and descriptive information, i.e. the same information used to generate + // the client libraries themselves. + // No snippet configuration has been specified. This refers to SnippetGen + // phase 1. + API_DEFINITION = 1; + + // The snippet is generated from the API definition and a specific snippet + // configuration. This refers to SnippetGen phase 2. + CONFIG = 2; + + // The snippet is handwritten. + HANDWRITTEN = 3; + } + + // A segment of the snippet. + message Segment { + // The line where this segment begins, inclusive. + // For the FULL segment, this will be the START region tag line + 1. + int32 start = 1; + + // The line where this segment ends, inclusive. + // For the FULL segment, this will be the END region tag line - 1. + int32 end = 2; + + // The type of the segment. + SegmentType type = 3; + + // The type of the segment. + // Basically describes what this segment shows. + enum SegmentType { + // The segment type has not been specified. Consumers should not see this + // value. + SEGMENT_TYPE_UNSPECIFIED = 0; + + // The full sample including import statements. + // This corresponds to the sample as determined by the region tags. + FULL = 1; + + // A shorter version of the full sample, may not include imports and some + // langauge specific initialization code. This is to be used in contexts + // in which the full aspects of the sample are made clear outside the + // code. + SHORT = 2; + + // The segment contains the service client initialization code only. + // To be used in tutorials, codelabs, etc. + CLIENT_INITIALIZATION = 3; + + // The segment contains the request initialization code only. + // To be used in tutorials, codelabs, etc. + REQUEST_INITIALIZATION = 4; + + // The segment contains the request execution code only. + // To be used in tutorials, codelabs, etc. + REQUEST_EXECUTION = 5; + + // The segment contains the response handling code only. + // To be used in tutorials, codelabs, etc. + RESPONSE_HANDLING = 6; + } + } +} + +// A client library method. +// Will contain language specific information. +message ClientMethod { + // The short name of the method, usually the name it is declared with. + // This may not be unique within the service client because of overloads. + string short_name = 1; + + // The fully qualified name of the method, which is the short_name qualified + // by the full_name of the service client. + // This value is redundant, but present to make it easier for consumers to + // obtain it. + // This may not be unique within the service client because of overloads. + string full_name = 2; + + // Indicates wether this method is synchronous or asynchronous. + // Some languages may support only one of the variants, in which case, this + // field will always have the same value (for that language). + bool async = 3; + + // Parameters of this method in the same order as they appear on the method + // declaration. Must be empty if the method has no parameters. + repeated Parameter parameters = 4; + + // Fully qualified type name of this method result, if any. + string result_type = 5; + + // The service client this method is declared in. + ServiceClient client = 6; + + // The service method this client method is for. + Method method = 7; + + // A method parameter as described by its type and name. + message Parameter { + // Fully qualified type name of this parameter. + // May be empty for languages that don't specify a type. + string type = 1; + + // Name of the parameter as it appears on the method declaration. + string name = 2; + } +} + +// A service client defined in the client library specified in Index. +// Will contain language specific information. +message ServiceClient { + // The short name of the service client, usually the name it is declared with. + // This may not be unique within the client library because of + // namespaces/packages. + string short_name = 1; + + // The fully qualified name of the service client, which is the short_name + // qualified by the namespace/package/type name this client is declared in. + // This will be unique within the client libray. + string full_name = 2; +} + +// A client library. +// Will contain language specific information. +message ClientLibrary { + // The name of the client library. This value will be language dependent + // and may or may not include the library version. + // Usually this will be the name used to identify the library on per-language + // package managers. + // Examples: "Google.Cloud.Translate.V3", + // "cloud.google.com/go/translate/apiv3". + string name = 1; + + // The full version of the client library. May also be language dependent. + // Cannot be updated on metadata generation, but on library release. + // Examples: "4.3.0", "2.5.2-beta01" + string version = 2; + + // The programming language the library is written in. + // Note that this does not contain information about the library supported + // platforms or language versions, etc. This is just a quick way to identify + // the generally supported langauge. + Language language = 3; + + // The APIs this client library is for. + // Some languages bundle several APIs on the same client library. + repeated Api apis = 4; +} + +message Method { + // The short name of the method, which is the name used to + // declare it within the proto file. This is unique within the service, + // but may not be unique within the API. + string short_name = 1; + + // The full name of the method, which is the short name qualified + // by the full name of the service in which it is declared. + // This is globally unique. + string full_name = 2; + + // The service this method is declared in. + Service service = 3; +} + +// A service defined in the API the client library referenced in Index is for. +message Service { + // The short name of the service, which is the name used to + // declare it within the proto file. This is usually, but not + // absolutely necessarily, unique within an API. + // Example: "TranslationService" + string short_name = 1; + + // The full name of the service, which is the short name qualified + // by the package of the proto in which it is declared. + // This is globally unique. + // Example: "google.cloud.translate.v3.TranslationService" + string full_name = 2; +} + +// An API +message Api { + // The ID of the API, identical to the protobuf package + // ending with a version number. + // Example: "google.cloud.translate.v3" + string id = 1; + + // The full version inferred from the end of the ID. + // Examples: "v3", "v2beta1", "v1beta" + string version = 2; +} + +// A programming language +enum Language { + // The language has not been specified. Consumers should not see this value. + LANGUAGE_UNSPECIFIED = 0; + + C_PLUS_PLUS = 1; + + C_SHARP = 2; + + DART = 3; + + ELIXIR = 4; + + ERLANG = 5; + + F_SHARP = 6; + + GO = 7; + + JAVA = 8; + + JAVASCRIPT = 9; + + KOTLIN = 10; + + PHP = 11; + + PYTHON = 12; + + RUBY = 13; + + RUST = 14; + + SWIFT = 15; + + TYPESCRIPT = 16; + + VB_NET = 17; +} \ No newline at end of file diff --git a/gapic/samplegen_utils/snippet_metadata_pb2.py b/gapic/samplegen_utils/snippet_metadata_pb2.py new file mode 100644 index 0000000000..73a75da6c2 --- /dev/null +++ b/gapic/samplegen_utils/snippet_metadata_pb2.py @@ -0,0 +1,840 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: snippet_metadata.proto + +# type: ignore + +"""Generated protocol buffer code.""" +from google.protobuf.internal import enum_type_wrapper +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +DESCRIPTOR = _descriptor.FileDescriptor( + name='snippet_metadata.proto', + package='google.cloud.tools.snippetgen.snippetindex.v1', + syntax='proto3', + serialized_options=b'\252\002-Google.Cloud.Tools.SnippetGen.SnippetIndex.V1\312\002-Google\\Cloud\\Tools\\SnippetGen\\SnippetIndex\\V1\352\0022Google::Cloud::Tools::SnippetGen::SnippetIndex::V1', + create_key=_descriptor._internal_create_key, + serialized_pb=b'\n\x16snippet_metadata.proto\x12-google.cloud.tools.snippetgen.snippetindex.v1\"\xa7\x01\n\x05Index\x12T\n\x0e\x63lient_library\x18\x01 \x01(\x0b\x32<.google.cloud.tools.snippetgen.snippetindex.v1.ClientLibrary\x12H\n\x08snippets\x18\x02 \x03(\x0b\x32\x36.google.cloud.tools.snippetgen.snippetindex.v1.Snippet\"\x9f\x06\n\x07Snippet\x12\x12\n\nregion_tag\x18\x01 \x01(\t\x12\r\n\x05title\x18\x02 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x03 \x01(\t\x12\x0c\n\x04\x66ile\x18\x04 \x01(\t\x12I\n\x08language\x18\x05 \x01(\x0e\x32\x37.google.cloud.tools.snippetgen.snippetindex.v1.Language\x12R\n\rclient_method\x18\x06 \x01(\x0b\x32;.google.cloud.tools.snippetgen.snippetindex.v1.ClientMethod\x12\x11\n\tcanonical\x18\x07 \x01(\x08\x12M\n\x06origin\x18\x08 \x01(\x0e\x32=.google.cloud.tools.snippetgen.snippetindex.v1.Snippet.Origin\x12P\n\x08segments\x18\t \x03(\x0b\x32>.google.cloud.tools.snippetgen.snippetindex.v1.Snippet.Segment\x1a\xa7\x02\n\x07Segment\x12\r\n\x05start\x18\x01 \x01(\x05\x12\x0b\n\x03\x65nd\x18\x02 \x01(\x05\x12X\n\x04type\x18\x03 \x01(\x0e\x32J.google.cloud.tools.snippetgen.snippetindex.v1.Snippet.Segment.SegmentType\"\xa5\x01\n\x0bSegmentType\x12\x1c\n\x18SEGMENT_TYPE_UNSPECIFIED\x10\x00\x12\x08\n\x04\x46ULL\x10\x01\x12\t\n\x05SHORT\x10\x02\x12\x19\n\x15\x43LIENT_INITIALIZATION\x10\x03\x12\x1a\n\x16REQUEST_INITIALIZATION\x10\x04\x12\x15\n\x11REQUEST_EXECUTION\x10\x05\x12\x15\n\x11RESPONSE_HANDLING\x10\x06\"Q\n\x06Origin\x12\x16\n\x12ORIGIN_UNSPECIFIED\x10\x00\x12\x12\n\x0e\x41PI_DEFINITION\x10\x01\x12\n\n\x06\x43ONFIG\x10\x02\x12\x0f\n\x0bHANDWRITTEN\x10\x03\"\xf2\x02\n\x0c\x43lientMethod\x12\x12\n\nshort_name\x18\x01 \x01(\t\x12\x11\n\tfull_name\x18\x02 \x01(\t\x12\r\n\x05\x61sync\x18\x03 \x01(\x08\x12Y\n\nparameters\x18\x04 \x03(\x0b\x32\x45.google.cloud.tools.snippetgen.snippetindex.v1.ClientMethod.Parameter\x12\x13\n\x0bresult_type\x18\x05 \x01(\t\x12L\n\x06\x63lient\x18\x06 \x01(\x0b\x32<.google.cloud.tools.snippetgen.snippetindex.v1.ServiceClient\x12\x45\n\x06method\x18\x07 \x01(\x0b\x32\x35.google.cloud.tools.snippetgen.snippetindex.v1.Method\x1a\'\n\tParameter\x12\x0c\n\x04type\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\"6\n\rServiceClient\x12\x12\n\nshort_name\x18\x01 \x01(\t\x12\x11\n\tfull_name\x18\x02 \x01(\t\"\xbb\x01\n\rClientLibrary\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0f\n\x07version\x18\x02 \x01(\t\x12I\n\x08language\x18\x03 \x01(\x0e\x32\x37.google.cloud.tools.snippetgen.snippetindex.v1.Language\x12@\n\x04\x61pis\x18\x04 \x03(\x0b\x32\x32.google.cloud.tools.snippetgen.snippetindex.v1.Api\"x\n\x06Method\x12\x12\n\nshort_name\x18\x01 \x01(\t\x12\x11\n\tfull_name\x18\x02 \x01(\t\x12G\n\x07service\x18\x03 \x01(\x0b\x32\x36.google.cloud.tools.snippetgen.snippetindex.v1.Service\"0\n\x07Service\x12\x12\n\nshort_name\x18\x01 \x01(\t\x12\x11\n\tfull_name\x18\x02 \x01(\t\"\"\n\x03\x41pi\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0f\n\x07version\x18\x02 \x01(\t*\xef\x01\n\x08Language\x12\x18\n\x14LANGUAGE_UNSPECIFIED\x10\x00\x12\x0f\n\x0b\x43_PLUS_PLUS\x10\x01\x12\x0b\n\x07\x43_SHARP\x10\x02\x12\x08\n\x04\x44\x41RT\x10\x03\x12\n\n\x06\x45LIXIR\x10\x04\x12\n\n\x06\x45RLANG\x10\x05\x12\x0b\n\x07\x46_SHARP\x10\x06\x12\x06\n\x02GO\x10\x07\x12\x08\n\x04JAVA\x10\x08\x12\x0e\n\nJAVASCRIPT\x10\t\x12\n\n\x06KOTLIN\x10\n\x12\x07\n\x03PHP\x10\x0b\x12\n\n\x06PYTHON\x10\x0c\x12\x08\n\x04RUBY\x10\r\x12\x08\n\x04RUST\x10\x0e\x12\t\n\x05SWIFT\x10\x0f\x12\x0e\n\nTYPESCRIPT\x10\x10\x12\n\n\x06VB_NET\x10\x11\x42\x95\x01\xaa\x02-Google.Cloud.Tools.SnippetGen.SnippetIndex.V1\xca\x02-Google\\Cloud\\Tools\\SnippetGen\\SnippetIndex\\V1\xea\x02\x32Google::Cloud::Tools::SnippetGen::SnippetIndex::V1b\x06proto3' +) + +_LANGUAGE = _descriptor.EnumDescriptor( + name='Language', + full_name='google.cloud.tools.snippetgen.snippetindex.v1.Language', + filename=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + values=[ + _descriptor.EnumValueDescriptor( + name='LANGUAGE_UNSPECIFIED', index=0, number=0, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='C_PLUS_PLUS', index=1, number=1, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='C_SHARP', index=2, number=2, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='DART', index=3, number=3, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='ELIXIR', index=4, number=4, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='ERLANG', index=5, number=5, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='F_SHARP', index=6, number=6, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='GO', index=7, number=7, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='JAVA', index=8, number=8, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='JAVASCRIPT', index=9, number=9, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='KOTLIN', index=10, number=10, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='PHP', index=11, number=11, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='PYTHON', index=12, number=12, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='RUBY', index=13, number=13, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='RUST', index=14, number=14, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='SWIFT', index=15, number=15, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='TYPESCRIPT', index=16, number=16, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='VB_NET', index=17, number=17, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + ], + containing_type=None, + serialized_options=None, + serialized_start=1873, + serialized_end=2112, +) +_sym_db.RegisterEnumDescriptor(_LANGUAGE) + +Language = enum_type_wrapper.EnumTypeWrapper(_LANGUAGE) +LANGUAGE_UNSPECIFIED = 0 +C_PLUS_PLUS = 1 +C_SHARP = 2 +DART = 3 +ELIXIR = 4 +ERLANG = 5 +F_SHARP = 6 +GO = 7 +JAVA = 8 +JAVASCRIPT = 9 +KOTLIN = 10 +PHP = 11 +PYTHON = 12 +RUBY = 13 +RUST = 14 +SWIFT = 15 +TYPESCRIPT = 16 +VB_NET = 17 + + +_SNIPPET_SEGMENT_SEGMENTTYPE = _descriptor.EnumDescriptor( + name='SegmentType', + full_name='google.cloud.tools.snippetgen.snippetindex.v1.Snippet.Segment.SegmentType', + filename=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + values=[ + _descriptor.EnumValueDescriptor( + name='SEGMENT_TYPE_UNSPECIFIED', index=0, number=0, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='FULL', index=1, number=1, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='SHORT', index=2, number=2, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='CLIENT_INITIALIZATION', index=3, number=3, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='REQUEST_INITIALIZATION', index=4, number=4, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='REQUEST_EXECUTION', index=5, number=5, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='RESPONSE_HANDLING', index=6, number=6, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + ], + containing_type=None, + serialized_options=None, + serialized_start=795, + serialized_end=960, +) +_sym_db.RegisterEnumDescriptor(_SNIPPET_SEGMENT_SEGMENTTYPE) + +_SNIPPET_ORIGIN = _descriptor.EnumDescriptor( + name='Origin', + full_name='google.cloud.tools.snippetgen.snippetindex.v1.Snippet.Origin', + filename=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + values=[ + _descriptor.EnumValueDescriptor( + name='ORIGIN_UNSPECIFIED', index=0, number=0, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='API_DEFINITION', index=1, number=1, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='CONFIG', index=2, number=2, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='HANDWRITTEN', index=3, number=3, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + ], + containing_type=None, + serialized_options=None, + serialized_start=962, + serialized_end=1043, +) +_sym_db.RegisterEnumDescriptor(_SNIPPET_ORIGIN) + + +_INDEX = _descriptor.Descriptor( + name='Index', + full_name='google.cloud.tools.snippetgen.snippetindex.v1.Index', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='client_library', full_name='google.cloud.tools.snippetgen.snippetindex.v1.Index.client_library', index=0, + number=1, 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, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='snippets', full_name='google.cloud.tools.snippetgen.snippetindex.v1.Index.snippets', 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, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=74, + serialized_end=241, +) + + +_SNIPPET_SEGMENT = _descriptor.Descriptor( + name='Segment', + full_name='google.cloud.tools.snippetgen.snippetindex.v1.Snippet.Segment', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='start', full_name='google.cloud.tools.snippetgen.snippetindex.v1.Snippet.Segment.start', index=0, + number=1, 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, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='end', full_name='google.cloud.tools.snippetgen.snippetindex.v1.Snippet.Segment.end', 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, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='type', full_name='google.cloud.tools.snippetgen.snippetindex.v1.Snippet.Segment.type', index=2, + number=3, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + _SNIPPET_SEGMENT_SEGMENTTYPE, + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=665, + serialized_end=960, +) + +_SNIPPET = _descriptor.Descriptor( + name='Snippet', + full_name='google.cloud.tools.snippetgen.snippetindex.v1.Snippet', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='region_tag', full_name='google.cloud.tools.snippetgen.snippetindex.v1.Snippet.region_tag', 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, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='title', full_name='google.cloud.tools.snippetgen.snippetindex.v1.Snippet.title', 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, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='description', full_name='google.cloud.tools.snippetgen.snippetindex.v1.Snippet.description', 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, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='file', full_name='google.cloud.tools.snippetgen.snippetindex.v1.Snippet.file', 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, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='language', full_name='google.cloud.tools.snippetgen.snippetindex.v1.Snippet.language', index=4, + number=5, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='client_method', full_name='google.cloud.tools.snippetgen.snippetindex.v1.Snippet.client_method', index=5, + number=6, 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, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='canonical', full_name='google.cloud.tools.snippetgen.snippetindex.v1.Snippet.canonical', index=6, + number=7, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='origin', full_name='google.cloud.tools.snippetgen.snippetindex.v1.Snippet.origin', index=7, + number=8, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='segments', full_name='google.cloud.tools.snippetgen.snippetindex.v1.Snippet.segments', index=8, + number=9, 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, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[_SNIPPET_SEGMENT, ], + enum_types=[ + _SNIPPET_ORIGIN, + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=244, + serialized_end=1043, +) + + +_CLIENTMETHOD_PARAMETER = _descriptor.Descriptor( + name='Parameter', + full_name='google.cloud.tools.snippetgen.snippetindex.v1.ClientMethod.Parameter', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='type', full_name='google.cloud.tools.snippetgen.snippetindex.v1.ClientMethod.Parameter.type', 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, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='name', full_name='google.cloud.tools.snippetgen.snippetindex.v1.ClientMethod.Parameter.name', 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, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1377, + serialized_end=1416, +) + +_CLIENTMETHOD = _descriptor.Descriptor( + name='ClientMethod', + full_name='google.cloud.tools.snippetgen.snippetindex.v1.ClientMethod', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='short_name', full_name='google.cloud.tools.snippetgen.snippetindex.v1.ClientMethod.short_name', 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, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='full_name', full_name='google.cloud.tools.snippetgen.snippetindex.v1.ClientMethod.full_name', 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, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='async', full_name='google.cloud.tools.snippetgen.snippetindex.v1.ClientMethod.async', index=2, + number=3, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='parameters', full_name='google.cloud.tools.snippetgen.snippetindex.v1.ClientMethod.parameters', index=3, + number=4, 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, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='result_type', full_name='google.cloud.tools.snippetgen.snippetindex.v1.ClientMethod.result_type', index=4, + number=5, 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, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='client', full_name='google.cloud.tools.snippetgen.snippetindex.v1.ClientMethod.client', index=5, + number=6, 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, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='method', full_name='google.cloud.tools.snippetgen.snippetindex.v1.ClientMethod.method', index=6, + number=7, 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, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[_CLIENTMETHOD_PARAMETER, ], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1046, + serialized_end=1416, +) + + +_SERVICECLIENT = _descriptor.Descriptor( + name='ServiceClient', + full_name='google.cloud.tools.snippetgen.snippetindex.v1.ServiceClient', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='short_name', full_name='google.cloud.tools.snippetgen.snippetindex.v1.ServiceClient.short_name', 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, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='full_name', full_name='google.cloud.tools.snippetgen.snippetindex.v1.ServiceClient.full_name', 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, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1418, + serialized_end=1472, +) + + +_CLIENTLIBRARY = _descriptor.Descriptor( + name='ClientLibrary', + full_name='google.cloud.tools.snippetgen.snippetindex.v1.ClientLibrary', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='name', full_name='google.cloud.tools.snippetgen.snippetindex.v1.ClientLibrary.name', 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, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='version', full_name='google.cloud.tools.snippetgen.snippetindex.v1.ClientLibrary.version', 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, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='language', full_name='google.cloud.tools.snippetgen.snippetindex.v1.ClientLibrary.language', index=2, + number=3, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='apis', full_name='google.cloud.tools.snippetgen.snippetindex.v1.ClientLibrary.apis', index=3, + number=4, 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, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1475, + serialized_end=1662, +) + + +_METHOD = _descriptor.Descriptor( + name='Method', + full_name='google.cloud.tools.snippetgen.snippetindex.v1.Method', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='short_name', full_name='google.cloud.tools.snippetgen.snippetindex.v1.Method.short_name', 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, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='full_name', full_name='google.cloud.tools.snippetgen.snippetindex.v1.Method.full_name', 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, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='service', full_name='google.cloud.tools.snippetgen.snippetindex.v1.Method.service', 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, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1664, + serialized_end=1784, +) + + +_SERVICE = _descriptor.Descriptor( + name='Service', + full_name='google.cloud.tools.snippetgen.snippetindex.v1.Service', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='short_name', full_name='google.cloud.tools.snippetgen.snippetindex.v1.Service.short_name', 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, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='full_name', full_name='google.cloud.tools.snippetgen.snippetindex.v1.Service.full_name', 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, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1786, + serialized_end=1834, +) + + +_API = _descriptor.Descriptor( + name='Api', + full_name='google.cloud.tools.snippetgen.snippetindex.v1.Api', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='id', full_name='google.cloud.tools.snippetgen.snippetindex.v1.Api.id', 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, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='version', full_name='google.cloud.tools.snippetgen.snippetindex.v1.Api.version', 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, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1836, + serialized_end=1870, +) + +_INDEX.fields_by_name['client_library'].message_type = _CLIENTLIBRARY +_INDEX.fields_by_name['snippets'].message_type = _SNIPPET +_SNIPPET_SEGMENT.fields_by_name['type'].enum_type = _SNIPPET_SEGMENT_SEGMENTTYPE +_SNIPPET_SEGMENT.containing_type = _SNIPPET +_SNIPPET_SEGMENT_SEGMENTTYPE.containing_type = _SNIPPET_SEGMENT +_SNIPPET.fields_by_name['language'].enum_type = _LANGUAGE +_SNIPPET.fields_by_name['client_method'].message_type = _CLIENTMETHOD +_SNIPPET.fields_by_name['origin'].enum_type = _SNIPPET_ORIGIN +_SNIPPET.fields_by_name['segments'].message_type = _SNIPPET_SEGMENT +_SNIPPET_ORIGIN.containing_type = _SNIPPET +_CLIENTMETHOD_PARAMETER.containing_type = _CLIENTMETHOD +_CLIENTMETHOD.fields_by_name['parameters'].message_type = _CLIENTMETHOD_PARAMETER +_CLIENTMETHOD.fields_by_name['client'].message_type = _SERVICECLIENT +_CLIENTMETHOD.fields_by_name['method'].message_type = _METHOD +_CLIENTLIBRARY.fields_by_name['language'].enum_type = _LANGUAGE +_CLIENTLIBRARY.fields_by_name['apis'].message_type = _API +_METHOD.fields_by_name['service'].message_type = _SERVICE +DESCRIPTOR.message_types_by_name['Index'] = _INDEX +DESCRIPTOR.message_types_by_name['Snippet'] = _SNIPPET +DESCRIPTOR.message_types_by_name['ClientMethod'] = _CLIENTMETHOD +DESCRIPTOR.message_types_by_name['ServiceClient'] = _SERVICECLIENT +DESCRIPTOR.message_types_by_name['ClientLibrary'] = _CLIENTLIBRARY +DESCRIPTOR.message_types_by_name['Method'] = _METHOD +DESCRIPTOR.message_types_by_name['Service'] = _SERVICE +DESCRIPTOR.message_types_by_name['Api'] = _API +DESCRIPTOR.enum_types_by_name['Language'] = _LANGUAGE +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + +Index = _reflection.GeneratedProtocolMessageType('Index', (_message.Message,), { + 'DESCRIPTOR': _INDEX, + '__module__': 'snippet_metadata_pb2' + # @@protoc_insertion_point(class_scope:google.cloud.tools.snippetgen.snippetindex.v1.Index) + }) +_sym_db.RegisterMessage(Index) + +Snippet = _reflection.GeneratedProtocolMessageType('Snippet', (_message.Message,), { + + 'Segment': _reflection.GeneratedProtocolMessageType('Segment', (_message.Message,), { + 'DESCRIPTOR': _SNIPPET_SEGMENT, + '__module__': 'snippet_metadata_pb2' + # @@protoc_insertion_point(class_scope:google.cloud.tools.snippetgen.snippetindex.v1.Snippet.Segment) + }), + 'DESCRIPTOR': _SNIPPET, + '__module__': 'snippet_metadata_pb2' + # @@protoc_insertion_point(class_scope:google.cloud.tools.snippetgen.snippetindex.v1.Snippet) + }) +_sym_db.RegisterMessage(Snippet) +_sym_db.RegisterMessage(Snippet.Segment) + +ClientMethod = _reflection.GeneratedProtocolMessageType('ClientMethod', (_message.Message,), { + + 'Parameter': _reflection.GeneratedProtocolMessageType('Parameter', (_message.Message,), { + 'DESCRIPTOR': _CLIENTMETHOD_PARAMETER, + '__module__': 'snippet_metadata_pb2' + # @@protoc_insertion_point(class_scope:google.cloud.tools.snippetgen.snippetindex.v1.ClientMethod.Parameter) + }), + 'DESCRIPTOR': _CLIENTMETHOD, + '__module__': 'snippet_metadata_pb2' + # @@protoc_insertion_point(class_scope:google.cloud.tools.snippetgen.snippetindex.v1.ClientMethod) + }) +_sym_db.RegisterMessage(ClientMethod) +_sym_db.RegisterMessage(ClientMethod.Parameter) + +ServiceClient = _reflection.GeneratedProtocolMessageType('ServiceClient', (_message.Message,), { + 'DESCRIPTOR': _SERVICECLIENT, + '__module__': 'snippet_metadata_pb2' + # @@protoc_insertion_point(class_scope:google.cloud.tools.snippetgen.snippetindex.v1.ServiceClient) + }) +_sym_db.RegisterMessage(ServiceClient) + +ClientLibrary = _reflection.GeneratedProtocolMessageType('ClientLibrary', (_message.Message,), { + 'DESCRIPTOR': _CLIENTLIBRARY, + '__module__': 'snippet_metadata_pb2' + # @@protoc_insertion_point(class_scope:google.cloud.tools.snippetgen.snippetindex.v1.ClientLibrary) + }) +_sym_db.RegisterMessage(ClientLibrary) + +Method = _reflection.GeneratedProtocolMessageType('Method', (_message.Message,), { + 'DESCRIPTOR': _METHOD, + '__module__': 'snippet_metadata_pb2' + # @@protoc_insertion_point(class_scope:google.cloud.tools.snippetgen.snippetindex.v1.Method) + }) +_sym_db.RegisterMessage(Method) + +Service = _reflection.GeneratedProtocolMessageType('Service', (_message.Message,), { + 'DESCRIPTOR': _SERVICE, + '__module__': 'snippet_metadata_pb2' + # @@protoc_insertion_point(class_scope:google.cloud.tools.snippetgen.snippetindex.v1.Service) + }) +_sym_db.RegisterMessage(Service) + +Api = _reflection.GeneratedProtocolMessageType('Api', (_message.Message,), { + 'DESCRIPTOR': _API, + '__module__': 'snippet_metadata_pb2' + # @@protoc_insertion_point(class_scope:google.cloud.tools.snippetgen.snippetindex.v1.Api) + }) +_sym_db.RegisterMessage(Api) + + +DESCRIPTOR._options = None +# @@protoc_insertion_point(module_scope) diff --git a/tests/unit/samplegen/common_types.py b/tests/unit/samplegen/common_types.py index 538b9d6864..1d10553b7d 100644 --- a/tests/unit/samplegen/common_types.py +++ b/tests/unit/samplegen/common_types.py @@ -91,7 +91,7 @@ def resource_path_args(self): DummyService = namedtuple("DummyService", [ - "methods", "client_name", "async_client_name", "resource_messages_dict"]) + "name", "methods", "client_name", "async_client_name", "resource_messages_dict"]) DummyService.__new__.__defaults__ = (False,) * len(DummyService._fields) DummyApiSchema = namedtuple("DummyApiSchema", diff --git a/tests/unit/samplegen/test_snippet_index.py b/tests/unit/samplegen/test_snippet_index.py new file mode 100644 index 0000000000..09f782a099 --- /dev/null +++ b/tests/unit/samplegen/test_snippet_index.py @@ -0,0 +1,229 @@ +# Copyright 2022 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 json + +from google.protobuf import json_format +import pytest + +from gapic.samplegen_utils import snippet_metadata_pb2 +from gapic.samplegen_utils import snippet_index, types +from common_types import DummyApiSchema, DummyService, DummyMethod + + +@pytest.fixture +def sample_str(): + return """# [START mollusc_classify_sync] +from molluscs.v1 import molluscclient + + +def sample_classify(video, location): + # Create a client + client = molluscclient.MolluscServiceClient() + + # Initialize request argument(s) + classify_target = molluscclient.ClassifyTarget() + + # video = "path/to/mollusc/video.mkv" + with open(video, "rb") as f: + classify_target.video = f.read() + + # location = "New Zealand" + classify_target.location_annotation = location + + request = molluscclient.molluscs.v1.ClassifyRequest( + classify_target=classify_target, + ) + + # Make the request + response = client.classify(request=request) + + # Handle response + print(f"Mollusc is a \"{response.taxonomy}\"") + +# [END mollusc_classify_sync]""" + + +def test_snippet_init(sample_str): + # We are not trying to exhaustively test the snippet metadata protobuf, + # just checking that fields are not unset + sample_metadata = snippet_metadata_pb2.Snippet(title="classify_squid.py") + sample_metadata.language = snippet_metadata_pb2.Language.PYTHON + snippet = snippet_index.Snippet(sample_str, sample_metadata) + + assert snippet.sample_str == sample_str + + # It's easier to eyeball diffs on the dictionary representation + assert json_format.MessageToDict(snippet.metadata) == { + "language": "PYTHON", + "title": "classify_squid.py", + "segments": [ + {"end": 28, "start": 2, "type": "FULL"}, + {"end": 28, "start": 2, "type": "SHORT"}, + {"end": 8, "start": 6, "type": "CLIENT_INITIALIZATION"}, + {"end": 22, "start": 9, "type": "REQUEST_INITIALIZATION"}, + {"end": 25, "start": 23, "type": "REQUEST_EXECUTION"}, + {"end": 29, "start": 26, "type": "RESPONSE_HANDLING"}, + ] + } + + # This is the same as the sample_str above, minus the # [START ...] + # and # [END ...] lines + expected_full_snipppet = """from molluscs.v1 import molluscclient + + +def sample_classify(video, location): + # Create a client + client = molluscclient.MolluscServiceClient() + + # Initialize request argument(s) + classify_target = molluscclient.ClassifyTarget() + + # video = "path/to/mollusc/video.mkv" + with open(video, "rb") as f: + classify_target.video = f.read() + + # location = "New Zealand" + classify_target.location_annotation = location + + request = molluscclient.molluscs.v1.ClassifyRequest( + classify_target=classify_target, + ) + + # Make the request + response = client.classify(request=request) + + # Handle response + print(f"Mollusc is a \"{response.taxonomy}\"") + +""" + + assert snippet.full_snippet == expected_full_snipppet + + +def test_add_snippet_no_matching_service(sample_str): + snippet_metadata = snippet_metadata_pb2.Snippet( + ) + snippet_metadata.client_method.method.service.short_name = "Clam" + snippet = snippet_index.Snippet(sample_str, snippet_metadata) + + # No 'Clam' service in API Schema + index = snippet_index.SnippetIndex(api_schema=DummyApiSchema( + services={"Squid": DummyService(name="Squid", methods={})} + )) + with pytest.raises(types.UnknownService): + index.add_snippet(snippet) + + +def test_add_snippet_no_matching_rpc(sample_str): + snippet_metadata = snippet_metadata_pb2.Snippet( + ) + snippet_metadata.client_method.method.service.short_name = "Squid" + snippet_metadata.client_method.full_name = "classify" + snippet = snippet_index.Snippet(sample_str, snippet_metadata) + + # No 'classify' method in 'Squid' service + index = snippet_index.SnippetIndex(api_schema=DummyApiSchema( + services={"Squid": DummyService(name="Squid", methods={"list": None})} + )) + with pytest.raises(types.RpcMethodNotFound): + index.add_snippet(snippet) + + +def test_get_snippet_no_matching_service(): + index = snippet_index.SnippetIndex(api_schema=DummyApiSchema( + services={"Squid": DummyService( + name="Squid", methods={"classify": DummyMethod()})} + )) + + # No 'Clam' service in API Schema + with pytest.raises(types.UnknownService): + index.get_snippet(service_name="Clam", rpc_name="classify") + + +def test_get_snippet_no_matching_rpc(): + index = snippet_index.SnippetIndex(api_schema=DummyApiSchema( + services={"Squid": DummyService( + name="Squid", methods={"classify": DummyMethod()})} + )) + + # No 'list' RPC in 'Squid' service + with pytest.raises(types.RpcMethodNotFound): + index.get_snippet(service_name="Squid", rpc_name="list") + + +def test_add_and_get_snippet_sync(sample_str): + snippet_metadata = snippet_metadata_pb2.Snippet() + snippet_metadata.client_method.method.service.short_name = "Squid" + snippet_metadata.client_method.method.full_name = "classify" + snippet = snippet_index.Snippet(sample_str, snippet_metadata) + + index = snippet_index.SnippetIndex(api_schema=DummyApiSchema( + services={"Squid": DummyService( + name="Squid", methods={"classify": DummyMethod()})} + )) + + index.add_snippet(snippet) + + index.get_snippet(service_name="Squid", rpc_name="classify") + + +def test_add_and_get_snippet_async(sample_str): + snippet_metadata = snippet_metadata_pb2.Snippet() + snippet_metadata.client_method.method.service.short_name = "Squid" + snippet_metadata.client_method.method.full_name = "classify" + setattr(snippet_metadata.client_method, "async", True) + snippet = snippet_index.Snippet(sample_str, snippet_metadata) + + index = snippet_index.SnippetIndex(api_schema=DummyApiSchema( + services={"Squid": DummyService( + name="Squid", methods={"classify": DummyMethod()})} + )) + + index.add_snippet(snippet) + + index.get_snippet(service_name="Squid", rpc_name="classify", sync=False) + + +def test_get_metadata_json(sample_str): + snippet_metadata = snippet_metadata_pb2.Snippet() + snippet_metadata.client_method.method.service.short_name = "Squid" + snippet_metadata.client_method.method.full_name = "classify" + snippet = snippet_index.Snippet(sample_str, snippet_metadata) + + index = snippet_index.SnippetIndex(api_schema=DummyApiSchema( + services={"Squid": DummyService( + name="Squid", methods={"classify": DummyMethod()})} + )) + + index.add_snippet(snippet) + + assert json.loads(index.get_metadata_json()) == { + 'snippets': [{'clientMethod': {'method': {'fullName': 'classify', + 'service': {'shortName': 'Squid'}}}, + 'segments': [{'end': 28, 'start': 2, 'type': 'FULL'}, + {'end': 28, 'start': 2, 'type': 'SHORT'}, + {'end': 8, + 'start': 6, + 'type': 'CLIENT_INITIALIZATION'}, + {'end': 22, + 'start': 9, + 'type': 'REQUEST_INITIALIZATION'}, + {'end': 25, + 'start': 23, + 'type': 'REQUEST_EXECUTION'}, + {'end': 29, + 'start': 26, + 'type': 'RESPONSE_HANDLING'}]}] + }