proto_reflection_descriptor_database.py
Go to the documentation of this file.
1 # Copyright 2022 gRPC authors.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 """Reference implementation for reflection client in gRPC Python.
15 
16 For usage instructions, see the Python Reflection documentation at
17 ``doc/python/server_reflection.md``.
18 """
19 
20 import logging
21 from typing import Any, Dict, Iterable, List, Set
22 
23 from google.protobuf.descriptor_database import DescriptorDatabase
24 from google.protobuf.descriptor_pb2 import FileDescriptorProto
25 import grpc
26 from grpc_reflection.v1alpha.reflection_pb2 import ExtensionNumberResponse
27 from grpc_reflection.v1alpha.reflection_pb2 import ExtensionRequest
28 from grpc_reflection.v1alpha.reflection_pb2 import FileDescriptorResponse
29 from grpc_reflection.v1alpha.reflection_pb2 import ListServiceResponse
30 from grpc_reflection.v1alpha.reflection_pb2 import ServerReflectionRequest
31 from grpc_reflection.v1alpha.reflection_pb2 import ServerReflectionResponse
32 from grpc_reflection.v1alpha.reflection_pb2 import ServiceResponse
33 from grpc_reflection.v1alpha.reflection_pb2_grpc import ServerReflectionStub
34 
35 
37  """
38  A container and interface for receiving descriptors from a server's
39  Reflection service.
40 
41  ProtoReflectionDescriptorDatabase takes a channel to a server with
42  Reflection service, and provides an interface to retrieve the Reflection
43  information. It implements the DescriptorDatabase interface.
44 
45  It is typically used to feed a DescriptorPool instance.
46  """
47 
48  # Implementation based on C++ version found here (version tag 1.39.1):
49  # grpc/test/cpp/util/proto_reflection_descriptor_database.cc
50  # while implementing the Python interface given here:
51  # https://googleapis.dev/python/protobuf/3.17.0/google/protobuf/descriptor_database.html
52 
53  def __init__(self, channel: grpc.Channel):
54  DescriptorDatabase.__init__(self)
55  self._logger = logging.getLogger(__name__)
56  self._stub = ServerReflectionStub(channel)
57  self._known_files: Set[str] = set()
58  self._cached_extension_numbers: Dict[str, List[int]] = dict()
59 
60  def get_services(self) -> Iterable[str]:
61  """
62  Get list of full names of the registered services.
63 
64  Returns:
65  A list of strings corresponding to the names of the services.
66  """
67 
68  request = ServerReflectionRequest(list_services="")
69  response = self._do_one_request(request, key="")
70  list_services: ListServiceResponse = response.list_services_response
71  services: List[ServiceResponse] = list_services.service
72  return [service.name for service in services]
73 
74  def FindFileByName(self, name: str) -> FileDescriptorProto:
75  """
76  Find a file descriptor by file name.
77 
78  This function implements a DescriptorDatabase interface, and is
79  typically not called directly; prefer using a DescriptorPool instead.
80 
81  Args:
82  name: The name of the file. Typically this is a relative path ending in ".proto".
83 
84  Returns:
85  A FileDescriptorProto for the file.
86 
87  Raises:
88  KeyError: the file was not found.
89  """
90 
91  try:
92  return super().FindFileByName(name)
93  except KeyError:
94  pass
95  assert name not in self._known_files
96  request = ServerReflectionRequest(file_by_filename=name)
97  response = self._do_one_request(request, key=name)
98  self._add_file_from_response(response.file_descriptor_response)
99  return super().FindFileByName(name)
100 
101  def FindFileContainingSymbol(self, symbol: str) -> FileDescriptorProto:
102  """
103  Find the file containing the symbol, and return its file descriptor.
104 
105  The symbol should be a fully qualified name including the file
106  descriptor's package and any containing messages. Some examples:
107 
108  * "some.package.name.Message"
109  * "some.package.name.Message.NestedEnum"
110  * "some.package.name.Message.some_field"
111 
112  This function implements a DescriptorDatabase interface, and is
113  typically not called directly; prefer using a DescriptorPool instead.
114 
115  Args:
116  symbol: The fully-qualified name of the symbol.
117 
118  Returns:
119  FileDescriptorProto for the file containing the symbol.
120 
121  Raises:
122  KeyError: the symbol was not found.
123  """
124 
125  try:
126  return super().FindFileContainingSymbol(symbol)
127  except KeyError:
128  pass
129  # Query the server
130  request = ServerReflectionRequest(file_containing_symbol=symbol)
131  response = self._do_one_request(request, key=symbol)
132  self._add_file_from_response(response.file_descriptor_response)
133  return super().FindFileContainingSymbol(symbol)
134 
135  def FindAllExtensionNumbers(self, extendee_name: str) -> Iterable[int]:
136  """
137  Find the field numbers used by all known extensions of `extendee_name`.
138 
139  This function implements a DescriptorDatabase interface, and is
140  typically not called directly; prefer using a DescriptorPool instead.
141 
142  Args:
143  extendee_name: fully-qualified name of the extended message type.
144 
145  Returns:
146  A list of field numbers used by all known extensions.
147 
148  Raises:
149  KeyError: The message type `extendee_name` was not found.
150  """
151 
152  if extendee_name in self._cached_extension_numbers:
153  return self._cached_extension_numbers[extendee_name]
154  request = ServerReflectionRequest(
155  all_extension_numbers_of_type=extendee_name)
156  response = self._do_one_request(request, key=extendee_name)
157  all_extension_numbers: ExtensionNumberResponse = (
158  response.all_extension_numbers_response)
159  numbers = list(all_extension_numbers.extension_number)
160  self._cached_extension_numbers[extendee_name] = numbers
161  return numbers
162 
164  self, extendee_name: str,
165  extension_number: int) -> FileDescriptorProto:
166  """
167  Find the file which defines an extension for the given message type
168  and field number.
169 
170  This function implements a DescriptorDatabase interface, and is
171  typically not called directly; prefer using a DescriptorPool instead.
172 
173  Args:
174  extendee_name: fully-qualified name of the extended message type.
175  extension_number: the number of the extension field.
176 
177  Returns:
178  FileDescriptorProto for the file containing the extension.
179 
180  Raises:
181  KeyError: The message or the extension number were not found.
182  """
183 
184  try:
185  return super().FindFileContainingExtension(extendee_name,
186  extension_number)
187  except KeyError:
188  pass
189  request = ServerReflectionRequest(
190  file_containing_extension=ExtensionRequest(
191  containing_type=extendee_name,
192  extension_number=extension_number))
193  response = self._do_one_request(request,
194  key=(extendee_name, extension_number))
195  file_desc = response.file_descriptor_response
196  self._add_file_from_response(file_desc)
197  return super().FindFileContainingExtension(extendee_name,
198  extension_number)
199 
200  def _do_one_request(self, request: ServerReflectionRequest,
201  key: Any) -> ServerReflectionResponse:
202  response = self._stub.ServerReflectionInfo(iter([request]))
203  res = next(response)
204  if res.WhichOneof("message_response") == "error_response":
205  # Only NOT_FOUND errors are expected at this layer
206  error_code = res.error_response.error_code
207  assert (error_code == grpc.StatusCode.NOT_FOUND.value[0]
208  ), "unexpected error response: " + repr(res.error_response)
209  raise KeyError(key)
210  return res
211 
213  self, file_descriptor: FileDescriptorResponse) -> None:
214  protos: List[bytes] = file_descriptor.file_descriptor_proto
215  for proto in protos:
216  desc = FileDescriptorProto()
217  desc.ParseFromString(proto)
218  if desc.name not in self._known_files:
219  self._logger.info("Loading descriptors from file: %s",
220  desc.name)
221  self._known_files.add(desc.name)
222  self.Add(desc)
grpc_reflection.v1alpha.proto_reflection_descriptor_database.ProtoReflectionDescriptorDatabase
Definition: proto_reflection_descriptor_database.py:36
grpc_reflection.v1alpha.proto_reflection_descriptor_database.ProtoReflectionDescriptorDatabase.FindFileContainingExtension
FileDescriptorProto FindFileContainingExtension(self, str extendee_name, int extension_number)
Definition: proto_reflection_descriptor_database.py:163
google::protobuf.descriptor_database.DescriptorDatabase
Definition: bloaty/third_party/protobuf/python/google/protobuf/descriptor_database.py:46
grpc_reflection.v1alpha.proto_reflection_descriptor_database.ProtoReflectionDescriptorDatabase.FindAllExtensionNumbers
Iterable[int] FindAllExtensionNumbers(self, str extendee_name)
Definition: proto_reflection_descriptor_database.py:135
google::protobuf.descriptor_database.DescriptorDatabase.Add
def Add(self, file_desc_proto)
Definition: bloaty/third_party/protobuf/python/google/protobuf/descriptor_database.py:53
grpc_reflection.v1alpha.proto_reflection_descriptor_database.ProtoReflectionDescriptorDatabase._do_one_request
ServerReflectionResponse _do_one_request(self, ServerReflectionRequest request, Any key)
Definition: proto_reflection_descriptor_database.py:200
grpc_reflection.v1alpha.proto_reflection_descriptor_database.ProtoReflectionDescriptorDatabase._logger
_logger
Definition: proto_reflection_descriptor_database.py:55
grpc_reflection.v1alpha.proto_reflection_descriptor_database.ProtoReflectionDescriptorDatabase.FindFileContainingSymbol
FileDescriptorProto FindFileContainingSymbol(self, str symbol)
Definition: proto_reflection_descriptor_database.py:101
google::protobuf.descriptor_database
Definition: bloaty/third_party/protobuf/python/google/protobuf/descriptor_database.py:1
grpc_reflection.v1alpha.proto_reflection_descriptor_database.ProtoReflectionDescriptorDatabase.__init__
def __init__(self, grpc.Channel channel)
Definition: proto_reflection_descriptor_database.py:53
add
static void add(const char *beg, const char *end, char ***ss, size_t *ns)
Definition: debug/trace.cc:96
google::protobuf::descriptor_pb2
next
AllocList * next[kMaxLevel]
Definition: abseil-cpp/absl/base/internal/low_level_alloc.cc:100
cpp.gmock_class.set
set
Definition: bloaty/third_party/googletest/googlemock/scripts/generator/cpp/gmock_class.py:44
grpc::protobuf::FileDescriptorProto
GRPC_CUSTOM_FILEDESCRIPTORPROTO FileDescriptorProto
Definition: include/grpcpp/impl/codegen/config_protobuf.h:86
iter
Definition: test_winkernel.cpp:47
grpc_reflection.v1alpha.proto_reflection_descriptor_database.ProtoReflectionDescriptorDatabase._stub
_stub
Definition: proto_reflection_descriptor_database.py:56
grpc_reflection.v1alpha.proto_reflection_descriptor_database.ProtoReflectionDescriptorDatabase.FindFileByName
FileDescriptorProto FindFileByName(self, str name)
Definition: proto_reflection_descriptor_database.py:74
grpc_reflection.v1alpha.proto_reflection_descriptor_database.ProtoReflectionDescriptorDatabase._add_file_from_response
None _add_file_from_response(self, FileDescriptorResponse file_descriptor)
Definition: proto_reflection_descriptor_database.py:212
grpc_reflection.v1alpha.proto_reflection_descriptor_database.ProtoReflectionDescriptorDatabase.get_services
Iterable[str] get_services(self)
Definition: proto_reflection_descriptor_database.py:60


grpc
Author(s):
autogenerated on Thu Mar 13 2025 03:00:56