codekingpro/portable-devtools
114k
1# Protocol Buffers - Google's data interchange format2# Copyright 2008 Google Inc. All rights reserved.3#4# Use of this source code is governed by a BSD-style5# license that can be found in the LICENSE file or at6# https://developers.google.com/open-source/licenses/bsd7 8"""Provides a container for DescriptorProtos."""9 10__author__ = 'matthewtoia@google.com (Matt Toia)'11 12import warnings13 14 15class Error(Exception):16 pass17 18 19class DescriptorDatabaseConflictingDefinitionError(Error):20 """Raised when a proto is added with the same name & different descriptor."""21 22 23class DescriptorDatabase(object):24 """A container accepting FileDescriptorProtos and maps DescriptorProtos."""25 26 def __init__(self):27 self._file_desc_protos_by_file = {}28 self._file_desc_protos_by_symbol = {}29 30 def Add(self, file_desc_proto):31 """Adds the FileDescriptorProto and its types to this database.32 33 Args:34 file_desc_proto: The FileDescriptorProto to add.35 Raises:36 DescriptorDatabaseConflictingDefinitionError: if an attempt is made to37 add a proto with the same name but different definition than an38 existing proto in the database.39 """40 proto_name = file_desc_proto.name41 if proto_name not in self._file_desc_protos_by_file:42 self._file_desc_protos_by_file[proto_name] = file_desc_proto43 elif self._file_desc_protos_by_file[proto_name] != file_desc_proto:44 raise DescriptorDatabaseConflictingDefinitionError(45 '%s already added, but with different descriptor.' % proto_name)46 else:47 return48 49 # Add all the top-level descriptors to the index.50 package = file_desc_proto.package51 for message in file_desc_proto.message_type:52 for name in _ExtractSymbols(message, package):53 self._AddSymbol(name, file_desc_proto)54 for enum in file_desc_proto.enum_type:55 self._AddSymbol(('.'.join((package, enum.name))), file_desc_proto)56 for enum_value in enum.value:57 self._file_desc_protos_by_symbol[58 '.'.join((package, enum_value.name))] = file_desc_proto59 for extension in file_desc_proto.extension:60 self._AddSymbol(('.'.join((package, extension.name))), file_desc_proto)61 for service in file_desc_proto.service:62 self._AddSymbol(('.'.join((package, service.name))), file_desc_proto)63 64 def FindFileByName(self, name):65 """Finds the file descriptor proto by file name.66 67 Typically the file name is a relative path ending to a .proto file. The68 proto with the given name will have to have been added to this database69 using the Add method or else an error will be raised.70 71 Args:72 name: The file name to find.73 74 Returns:75 The file descriptor proto matching the name.76 77 Raises:78 KeyError if no file by the given name was added.79 """80 81 return self._file_desc_protos_by_file[name]82 83 def FindFileContainingSymbol(self, symbol):84 """Finds the file descriptor proto containing the specified symbol.85 86 The symbol should be a fully qualified name including the file descriptor's87 package and any containing messages. Some examples:88 89 'some.package.name.Message'90 'some.package.name.Message.NestedEnum'91 'some.package.name.Message.some_field'92 93 The file descriptor proto containing the specified symbol must be added to94 this database using the Add method or else an error will be raised.95 96 Args:97 symbol: The fully qualified symbol name.98 99 Returns:100 The file descriptor proto containing the symbol.101 102 Raises:103 KeyError if no file contains the specified symbol.104 """105 try:106 return self._file_desc_protos_by_symbol[symbol]107 except KeyError:108 # Fields, enum values, and nested extensions are not in109 # _file_desc_protos_by_symbol. Try to find the top level110 # descriptor. Non-existent nested symbol under a valid top level111 # descriptor can also be found. The behavior is the same with112 # protobuf C++.113 top_level, _, _ = symbol.rpartition('.')114 try:115 return self._file_desc_protos_by_symbol[top_level]116 except KeyError:117 # Raise the original symbol as a KeyError for better diagnostics.118 raise KeyError(symbol)119 120 def FindFileContainingExtension(self, extendee_name, extension_number):121 # TODO: implement this API.122 return None123 124 def FindAllExtensionNumbers(self, extendee_name):125 # TODO: implement this API.126 return []127 128 def _AddSymbol(self, name, file_desc_proto):129 if name in self._file_desc_protos_by_symbol:130 warn_msg = ('Conflict register for file "' + file_desc_proto.name +131 '": ' + name +132 ' is already defined in file "' +133 self._file_desc_protos_by_symbol[name].name + '"')134 warnings.warn(warn_msg, RuntimeWarning)135 self._file_desc_protos_by_symbol[name] = file_desc_proto136 137 138def _ExtractSymbols(desc_proto, package):139 """Pulls out all the symbols from a descriptor proto.140 141 Args:142 desc_proto: The proto to extract symbols from.143 package: The package containing the descriptor type.144 145 Yields:146 The fully qualified name found in the descriptor.147 """148 message_name = package + '.' + desc_proto.name if package else desc_proto.name149 yield message_name150 for nested_type in desc_proto.nested_type:151 for symbol in _ExtractSymbols(nested_type, message_name):152 yield symbol153 for enum_type in desc_proto.enum_type:154 yield '.'.join((message_name, enum_type.name))155 