1# Protocol Buffers - Google's data interchange format 2# Copyright 2008 Google Inc. All rights reserved. 3# https://developers.google.com/protocol-buffers/ 4# 5# Redistribution and use in source and binary forms, with or without 6# modification, are permitted provided that the following conditions are 7# met: 8# 9# * Redistributions of source code must retain the above copyright 10# notice, this list of conditions and the following disclaimer. 11# * Redistributions in binary form must reproduce the above 12# copyright notice, this list of conditions and the following disclaimer 13# in the documentation and/or other materials provided with the 14# distribution. 15# * Neither the name of Google Inc. nor the names of its 16# contributors may be used to endorse or promote products derived from 17# this software without specific prior written permission. 18# 19# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31"""Provides DescriptorPool to use as a container for proto2 descriptors. 32 33The DescriptorPool is used in conjection with a DescriptorDatabase to maintain 34a collection of protocol buffer descriptors for use when dynamically creating 35message types at runtime. 36 37For most applications protocol buffers should be used via modules generated by 38the protocol buffer compiler tool. This should only be used when the type of 39protocol buffers used in an application or library cannot be predetermined. 40 41Below is a straightforward example on how to use this class: 42 43 pool = DescriptorPool() 44 file_descriptor_protos = [ ... ] 45 for file_descriptor_proto in file_descriptor_protos: 46 pool.Add(file_descriptor_proto) 47 my_message_descriptor = pool.FindMessageTypeByName('some.package.MessageType') 48 49The message descriptor can be used in conjunction with the message_factory 50module in order to create a protocol buffer class that can be encoded and 51decoded. 52 53If you want to get a Python class for the specified proto, use the 54helper functions inside google.protobuf.message_factory 55directly instead of this class. 56""" 57 58__author__ = 'matthewtoia@google.com (Matt Toia)' 59 60from google.protobuf import descriptor 61from google.protobuf import descriptor_database 62from google.protobuf import text_encoding 63 64 65_USE_C_DESCRIPTORS = descriptor._USE_C_DESCRIPTORS 66 67 68def _NormalizeFullyQualifiedName(name): 69 """Remove leading period from fully-qualified type name. 70 71 Due to b/13860351 in descriptor_database.py, types in the root namespace are 72 generated with a leading period. This function removes that prefix. 73 74 Args: 75 name: A str, the fully-qualified symbol name. 76 77 Returns: 78 A str, the normalized fully-qualified symbol name. 79 """ 80 return name.lstrip('.') 81 82 83class DescriptorPool(object): 84 """A collection of protobufs dynamically constructed by descriptor protos.""" 85 86 if _USE_C_DESCRIPTORS: 87 88 def __new__(cls, descriptor_db=None): 89 # pylint: disable=protected-access 90 return descriptor._message.DescriptorPool(descriptor_db) 91 92 def __init__(self, descriptor_db=None): 93 """Initializes a Pool of proto buffs. 94 95 The descriptor_db argument to the constructor is provided to allow 96 specialized file descriptor proto lookup code to be triggered on demand. An 97 example would be an implementation which will read and compile a file 98 specified in a call to FindFileByName() and not require the call to Add() 99 at all. Results from this database will be cached internally here as well. 100 101 Args: 102 descriptor_db: A secondary source of file descriptors. 103 """ 104 105 self._internal_db = descriptor_database.DescriptorDatabase() 106 self._descriptor_db = descriptor_db 107 self._descriptors = {} 108 self._enum_descriptors = {} 109 self._file_descriptors = {} 110 111 def Add(self, file_desc_proto): 112 """Adds the FileDescriptorProto and its types to this pool. 113 114 Args: 115 file_desc_proto: The FileDescriptorProto to add. 116 """ 117 118 self._internal_db.Add(file_desc_proto) 119 120 def AddSerializedFile(self, serialized_file_desc_proto): 121 """Adds the FileDescriptorProto and its types to this pool. 122 123 Args: 124 serialized_file_desc_proto: A bytes string, serialization of the 125 FileDescriptorProto to add. 126 """ 127 128 # pylint: disable=g-import-not-at-top 129 from google.protobuf import descriptor_pb2 130 file_desc_proto = descriptor_pb2.FileDescriptorProto.FromString( 131 serialized_file_desc_proto) 132 self.Add(file_desc_proto) 133 134 def AddDescriptor(self, desc): 135 """Adds a Descriptor to the pool, non-recursively. 136 137 If the Descriptor contains nested messages or enums, the caller must 138 explicitly register them. This method also registers the FileDescriptor 139 associated with the message. 140 141 Args: 142 desc: A Descriptor. 143 """ 144 if not isinstance(desc, descriptor.Descriptor): 145 raise TypeError('Expected instance of descriptor.Descriptor.') 146 147 self._descriptors[desc.full_name] = desc 148 self.AddFileDescriptor(desc.file) 149 150 def AddEnumDescriptor(self, enum_desc): 151 """Adds an EnumDescriptor to the pool. 152 153 This method also registers the FileDescriptor associated with the message. 154 155 Args: 156 enum_desc: An EnumDescriptor. 157 """ 158 159 if not isinstance(enum_desc, descriptor.EnumDescriptor): 160 raise TypeError('Expected instance of descriptor.EnumDescriptor.') 161 162 self._enum_descriptors[enum_desc.full_name] = enum_desc 163 self.AddFileDescriptor(enum_desc.file) 164 165 def AddFileDescriptor(self, file_desc): 166 """Adds a FileDescriptor to the pool, non-recursively. 167 168 If the FileDescriptor contains messages or enums, the caller must explicitly 169 register them. 170 171 Args: 172 file_desc: A FileDescriptor. 173 """ 174 175 if not isinstance(file_desc, descriptor.FileDescriptor): 176 raise TypeError('Expected instance of descriptor.FileDescriptor.') 177 self._file_descriptors[file_desc.name] = file_desc 178 179 def FindFileByName(self, file_name): 180 """Gets a FileDescriptor by file name. 181 182 Args: 183 file_name: The path to the file to get a descriptor for. 184 185 Returns: 186 A FileDescriptor for the named file. 187 188 Raises: 189 KeyError: if the file can not be found in the pool. 190 """ 191 192 try: 193 return self._file_descriptors[file_name] 194 except KeyError: 195 pass 196 197 try: 198 file_proto = self._internal_db.FindFileByName(file_name) 199 except KeyError as error: 200 if self._descriptor_db: 201 file_proto = self._descriptor_db.FindFileByName(file_name) 202 else: 203 raise error 204 if not file_proto: 205 raise KeyError('Cannot find a file named %s' % file_name) 206 return self._ConvertFileProtoToFileDescriptor(file_proto) 207 208 def FindFileContainingSymbol(self, symbol): 209 """Gets the FileDescriptor for the file containing the specified symbol. 210 211 Args: 212 symbol: The name of the symbol to search for. 213 214 Returns: 215 A FileDescriptor that contains the specified symbol. 216 217 Raises: 218 KeyError: if the file can not be found in the pool. 219 """ 220 221 symbol = _NormalizeFullyQualifiedName(symbol) 222 try: 223 return self._descriptors[symbol].file 224 except KeyError: 225 pass 226 227 try: 228 return self._enum_descriptors[symbol].file 229 except KeyError: 230 pass 231 232 try: 233 file_proto = self._internal_db.FindFileContainingSymbol(symbol) 234 except KeyError as error: 235 if self._descriptor_db: 236 file_proto = self._descriptor_db.FindFileContainingSymbol(symbol) 237 else: 238 raise error 239 if not file_proto: 240 raise KeyError('Cannot find a file containing %s' % symbol) 241 return self._ConvertFileProtoToFileDescriptor(file_proto) 242 243 def FindMessageTypeByName(self, full_name): 244 """Loads the named descriptor from the pool. 245 246 Args: 247 full_name: The full name of the descriptor to load. 248 249 Returns: 250 The descriptor for the named type. 251 """ 252 253 full_name = _NormalizeFullyQualifiedName(full_name) 254 if full_name not in self._descriptors: 255 self.FindFileContainingSymbol(full_name) 256 return self._descriptors[full_name] 257 258 def FindEnumTypeByName(self, full_name): 259 """Loads the named enum descriptor from the pool. 260 261 Args: 262 full_name: The full name of the enum descriptor to load. 263 264 Returns: 265 The enum descriptor for the named type. 266 """ 267 268 full_name = _NormalizeFullyQualifiedName(full_name) 269 if full_name not in self._enum_descriptors: 270 self.FindFileContainingSymbol(full_name) 271 return self._enum_descriptors[full_name] 272 273 def FindFieldByName(self, full_name): 274 """Loads the named field descriptor from the pool. 275 276 Args: 277 full_name: The full name of the field descriptor to load. 278 279 Returns: 280 The field descriptor for the named field. 281 """ 282 full_name = _NormalizeFullyQualifiedName(full_name) 283 message_name, _, field_name = full_name.rpartition('.') 284 message_descriptor = self.FindMessageTypeByName(message_name) 285 return message_descriptor.fields_by_name[field_name] 286 287 def FindExtensionByName(self, full_name): 288 """Loads the named extension descriptor from the pool. 289 290 Args: 291 full_name: The full name of the extension descriptor to load. 292 293 Returns: 294 A FieldDescriptor, describing the named extension. 295 """ 296 full_name = _NormalizeFullyQualifiedName(full_name) 297 message_name, _, extension_name = full_name.rpartition('.') 298 try: 299 # Most extensions are nested inside a message. 300 scope = self.FindMessageTypeByName(message_name) 301 except KeyError: 302 # Some extensions are defined at file scope. 303 scope = self.FindFileContainingSymbol(full_name) 304 return scope.extensions_by_name[extension_name] 305 306 def _ConvertFileProtoToFileDescriptor(self, file_proto): 307 """Creates a FileDescriptor from a proto or returns a cached copy. 308 309 This method also has the side effect of loading all the symbols found in 310 the file into the appropriate dictionaries in the pool. 311 312 Args: 313 file_proto: The proto to convert. 314 315 Returns: 316 A FileDescriptor matching the passed in proto. 317 """ 318 319 if file_proto.name not in self._file_descriptors: 320 built_deps = list(self._GetDeps(file_proto.dependency)) 321 direct_deps = [self.FindFileByName(n) for n in file_proto.dependency] 322 public_deps = [direct_deps[i] for i in file_proto.public_dependency] 323 324 file_descriptor = descriptor.FileDescriptor( 325 pool=self, 326 name=file_proto.name, 327 package=file_proto.package, 328 syntax=file_proto.syntax, 329 options=file_proto.options, 330 serialized_pb=file_proto.SerializeToString(), 331 dependencies=direct_deps, 332 public_dependencies=public_deps) 333 if _USE_C_DESCRIPTORS: 334 # When using C++ descriptors, all objects defined in the file were added 335 # to the C++ database when the FileDescriptor was built above. 336 # Just add them to this descriptor pool. 337 def _AddMessageDescriptor(message_desc): 338 self._descriptors[message_desc.full_name] = message_desc 339 for nested in message_desc.nested_types: 340 _AddMessageDescriptor(nested) 341 for enum_type in message_desc.enum_types: 342 _AddEnumDescriptor(enum_type) 343 def _AddEnumDescriptor(enum_desc): 344 self._enum_descriptors[enum_desc.full_name] = enum_desc 345 for message_type in file_descriptor.message_types_by_name.values(): 346 _AddMessageDescriptor(message_type) 347 for enum_type in file_descriptor.enum_types_by_name.values(): 348 _AddEnumDescriptor(enum_type) 349 else: 350 scope = {} 351 352 # This loop extracts all the message and enum types from all the 353 # dependencies of the file_proto. This is necessary to create the 354 # scope of available message types when defining the passed in 355 # file proto. 356 for dependency in built_deps: 357 scope.update(self._ExtractSymbols( 358 dependency.message_types_by_name.values())) 359 scope.update((_PrefixWithDot(enum.full_name), enum) 360 for enum in dependency.enum_types_by_name.values()) 361 362 for message_type in file_proto.message_type: 363 message_desc = self._ConvertMessageDescriptor( 364 message_type, file_proto.package, file_descriptor, scope, 365 file_proto.syntax) 366 file_descriptor.message_types_by_name[message_desc.name] = ( 367 message_desc) 368 369 for enum_type in file_proto.enum_type: 370 file_descriptor.enum_types_by_name[enum_type.name] = ( 371 self._ConvertEnumDescriptor(enum_type, file_proto.package, 372 file_descriptor, None, scope)) 373 374 for index, extension_proto in enumerate(file_proto.extension): 375 extension_desc = self._MakeFieldDescriptor( 376 extension_proto, file_proto.package, index, is_extension=True) 377 extension_desc.containing_type = self._GetTypeFromScope( 378 file_descriptor.package, extension_proto.extendee, scope) 379 self._SetFieldType(extension_proto, extension_desc, 380 file_descriptor.package, scope) 381 file_descriptor.extensions_by_name[extension_desc.name] = ( 382 extension_desc) 383 384 for desc_proto in file_proto.message_type: 385 self._SetAllFieldTypes(file_proto.package, desc_proto, scope) 386 387 if file_proto.package: 388 desc_proto_prefix = _PrefixWithDot(file_proto.package) 389 else: 390 desc_proto_prefix = '' 391 392 for desc_proto in file_proto.message_type: 393 desc = self._GetTypeFromScope( 394 desc_proto_prefix, desc_proto.name, scope) 395 file_descriptor.message_types_by_name[desc_proto.name] = desc 396 397 for index, service_proto in enumerate(file_proto.service): 398 file_descriptor.services_by_name[service_proto.name] = ( 399 self._MakeServiceDescriptor(service_proto, index, scope, 400 file_proto.package, file_descriptor)) 401 402 self.Add(file_proto) 403 self._file_descriptors[file_proto.name] = file_descriptor 404 405 return self._file_descriptors[file_proto.name] 406 407 def _ConvertMessageDescriptor(self, desc_proto, package=None, file_desc=None, 408 scope=None, syntax=None): 409 """Adds the proto to the pool in the specified package. 410 411 Args: 412 desc_proto: The descriptor_pb2.DescriptorProto protobuf message. 413 package: The package the proto should be located in. 414 file_desc: The file containing this message. 415 scope: Dict mapping short and full symbols to message and enum types. 416 417 Returns: 418 The added descriptor. 419 """ 420 421 if package: 422 desc_name = '.'.join((package, desc_proto.name)) 423 else: 424 desc_name = desc_proto.name 425 426 if file_desc is None: 427 file_name = None 428 else: 429 file_name = file_desc.name 430 431 if scope is None: 432 scope = {} 433 434 nested = [ 435 self._ConvertMessageDescriptor( 436 nested, desc_name, file_desc, scope, syntax) 437 for nested in desc_proto.nested_type] 438 enums = [ 439 self._ConvertEnumDescriptor(enum, desc_name, file_desc, None, scope) 440 for enum in desc_proto.enum_type] 441 fields = [self._MakeFieldDescriptor(field, desc_name, index) 442 for index, field in enumerate(desc_proto.field)] 443 extensions = [ 444 self._MakeFieldDescriptor(extension, desc_name, index, 445 is_extension=True) 446 for index, extension in enumerate(desc_proto.extension)] 447 oneofs = [ 448 descriptor.OneofDescriptor(desc.name, '.'.join((desc_name, desc.name)), 449 index, None, [], desc.options) 450 for index, desc in enumerate(desc_proto.oneof_decl)] 451 extension_ranges = [(r.start, r.end) for r in desc_proto.extension_range] 452 if extension_ranges: 453 is_extendable = True 454 else: 455 is_extendable = False 456 desc = descriptor.Descriptor( 457 name=desc_proto.name, 458 full_name=desc_name, 459 filename=file_name, 460 containing_type=None, 461 fields=fields, 462 oneofs=oneofs, 463 nested_types=nested, 464 enum_types=enums, 465 extensions=extensions, 466 options=desc_proto.options, 467 is_extendable=is_extendable, 468 extension_ranges=extension_ranges, 469 file=file_desc, 470 serialized_start=None, 471 serialized_end=None, 472 syntax=syntax) 473 for nested in desc.nested_types: 474 nested.containing_type = desc 475 for enum in desc.enum_types: 476 enum.containing_type = desc 477 for field_index, field_desc in enumerate(desc_proto.field): 478 if field_desc.HasField('oneof_index'): 479 oneof_index = field_desc.oneof_index 480 oneofs[oneof_index].fields.append(fields[field_index]) 481 fields[field_index].containing_oneof = oneofs[oneof_index] 482 483 scope[_PrefixWithDot(desc_name)] = desc 484 self._descriptors[desc_name] = desc 485 return desc 486 487 def _ConvertEnumDescriptor(self, enum_proto, package=None, file_desc=None, 488 containing_type=None, scope=None): 489 """Make a protobuf EnumDescriptor given an EnumDescriptorProto protobuf. 490 491 Args: 492 enum_proto: The descriptor_pb2.EnumDescriptorProto protobuf message. 493 package: Optional package name for the new message EnumDescriptor. 494 file_desc: The file containing the enum descriptor. 495 containing_type: The type containing this enum. 496 scope: Scope containing available types. 497 498 Returns: 499 The added descriptor 500 """ 501 502 if package: 503 enum_name = '.'.join((package, enum_proto.name)) 504 else: 505 enum_name = enum_proto.name 506 507 if file_desc is None: 508 file_name = None 509 else: 510 file_name = file_desc.name 511 512 values = [self._MakeEnumValueDescriptor(value, index) 513 for index, value in enumerate(enum_proto.value)] 514 desc = descriptor.EnumDescriptor(name=enum_proto.name, 515 full_name=enum_name, 516 filename=file_name, 517 file=file_desc, 518 values=values, 519 containing_type=containing_type, 520 options=enum_proto.options) 521 scope['.%s' % enum_name] = desc 522 self._enum_descriptors[enum_name] = desc 523 return desc 524 525 def _MakeFieldDescriptor(self, field_proto, message_name, index, 526 is_extension=False): 527 """Creates a field descriptor from a FieldDescriptorProto. 528 529 For message and enum type fields, this method will do a look up 530 in the pool for the appropriate descriptor for that type. If it 531 is unavailable, it will fall back to the _source function to 532 create it. If this type is still unavailable, construction will 533 fail. 534 535 Args: 536 field_proto: The proto describing the field. 537 message_name: The name of the containing message. 538 index: Index of the field 539 is_extension: Indication that this field is for an extension. 540 541 Returns: 542 An initialized FieldDescriptor object 543 """ 544 545 if message_name: 546 full_name = '.'.join((message_name, field_proto.name)) 547 else: 548 full_name = field_proto.name 549 550 return descriptor.FieldDescriptor( 551 name=field_proto.name, 552 full_name=full_name, 553 index=index, 554 number=field_proto.number, 555 type=field_proto.type, 556 cpp_type=None, 557 message_type=None, 558 enum_type=None, 559 containing_type=None, 560 label=field_proto.label, 561 has_default_value=False, 562 default_value=None, 563 is_extension=is_extension, 564 extension_scope=None, 565 options=field_proto.options) 566 567 def _SetAllFieldTypes(self, package, desc_proto, scope): 568 """Sets all the descriptor's fields's types. 569 570 This method also sets the containing types on any extensions. 571 572 Args: 573 package: The current package of desc_proto. 574 desc_proto: The message descriptor to update. 575 scope: Enclosing scope of available types. 576 """ 577 578 package = _PrefixWithDot(package) 579 580 main_desc = self._GetTypeFromScope(package, desc_proto.name, scope) 581 582 if package == '.': 583 nested_package = _PrefixWithDot(desc_proto.name) 584 else: 585 nested_package = '.'.join([package, desc_proto.name]) 586 587 for field_proto, field_desc in zip(desc_proto.field, main_desc.fields): 588 self._SetFieldType(field_proto, field_desc, nested_package, scope) 589 590 for extension_proto, extension_desc in ( 591 zip(desc_proto.extension, main_desc.extensions)): 592 extension_desc.containing_type = self._GetTypeFromScope( 593 nested_package, extension_proto.extendee, scope) 594 self._SetFieldType(extension_proto, extension_desc, nested_package, scope) 595 596 for nested_type in desc_proto.nested_type: 597 self._SetAllFieldTypes(nested_package, nested_type, scope) 598 599 def _SetFieldType(self, field_proto, field_desc, package, scope): 600 """Sets the field's type, cpp_type, message_type and enum_type. 601 602 Args: 603 field_proto: Data about the field in proto format. 604 field_desc: The descriptor to modiy. 605 package: The package the field's container is in. 606 scope: Enclosing scope of available types. 607 """ 608 if field_proto.type_name: 609 desc = self._GetTypeFromScope(package, field_proto.type_name, scope) 610 else: 611 desc = None 612 613 if not field_proto.HasField('type'): 614 if isinstance(desc, descriptor.Descriptor): 615 field_proto.type = descriptor.FieldDescriptor.TYPE_MESSAGE 616 else: 617 field_proto.type = descriptor.FieldDescriptor.TYPE_ENUM 618 619 field_desc.cpp_type = descriptor.FieldDescriptor.ProtoTypeToCppProtoType( 620 field_proto.type) 621 622 if (field_proto.type == descriptor.FieldDescriptor.TYPE_MESSAGE 623 or field_proto.type == descriptor.FieldDescriptor.TYPE_GROUP): 624 field_desc.message_type = desc 625 626 if field_proto.type == descriptor.FieldDescriptor.TYPE_ENUM: 627 field_desc.enum_type = desc 628 629 if field_proto.label == descriptor.FieldDescriptor.LABEL_REPEATED: 630 field_desc.has_default_value = False 631 field_desc.default_value = [] 632 elif field_proto.HasField('default_value'): 633 field_desc.has_default_value = True 634 if (field_proto.type == descriptor.FieldDescriptor.TYPE_DOUBLE or 635 field_proto.type == descriptor.FieldDescriptor.TYPE_FLOAT): 636 field_desc.default_value = float(field_proto.default_value) 637 elif field_proto.type == descriptor.FieldDescriptor.TYPE_STRING: 638 field_desc.default_value = field_proto.default_value 639 elif field_proto.type == descriptor.FieldDescriptor.TYPE_BOOL: 640 field_desc.default_value = field_proto.default_value.lower() == 'true' 641 elif field_proto.type == descriptor.FieldDescriptor.TYPE_ENUM: 642 field_desc.default_value = field_desc.enum_type.values_by_name[ 643 field_proto.default_value].number 644 elif field_proto.type == descriptor.FieldDescriptor.TYPE_BYTES: 645 field_desc.default_value = text_encoding.CUnescape( 646 field_proto.default_value) 647 else: 648 # All other types are of the "int" type. 649 field_desc.default_value = int(field_proto.default_value) 650 else: 651 field_desc.has_default_value = False 652 if (field_proto.type == descriptor.FieldDescriptor.TYPE_DOUBLE or 653 field_proto.type == descriptor.FieldDescriptor.TYPE_FLOAT): 654 field_desc.default_value = 0.0 655 elif field_proto.type == descriptor.FieldDescriptor.TYPE_STRING: 656 field_desc.default_value = u'' 657 elif field_proto.type == descriptor.FieldDescriptor.TYPE_BOOL: 658 field_desc.default_value = False 659 elif field_proto.type == descriptor.FieldDescriptor.TYPE_ENUM: 660 field_desc.default_value = field_desc.enum_type.values[0].number 661 elif field_proto.type == descriptor.FieldDescriptor.TYPE_BYTES: 662 field_desc.default_value = b'' 663 else: 664 # All other types are of the "int" type. 665 field_desc.default_value = 0 666 667 field_desc.type = field_proto.type 668 669 def _MakeEnumValueDescriptor(self, value_proto, index): 670 """Creates a enum value descriptor object from a enum value proto. 671 672 Args: 673 value_proto: The proto describing the enum value. 674 index: The index of the enum value. 675 676 Returns: 677 An initialized EnumValueDescriptor object. 678 """ 679 680 return descriptor.EnumValueDescriptor( 681 name=value_proto.name, 682 index=index, 683 number=value_proto.number, 684 options=value_proto.options, 685 type=None) 686 687 def _MakeServiceDescriptor(self, service_proto, service_index, scope, 688 package, file_desc): 689 """Make a protobuf ServiceDescriptor given a ServiceDescriptorProto. 690 691 Args: 692 service_proto: The descriptor_pb2.ServiceDescriptorProto protobuf message. 693 service_index: The index of the service in the File. 694 scope: Dict mapping short and full symbols to message and enum types. 695 package: Optional package name for the new message EnumDescriptor. 696 file_desc: The file containing the service descriptor. 697 698 Returns: 699 The added descriptor. 700 """ 701 702 if package: 703 service_name = '.'.join((package, service_proto.name)) 704 else: 705 service_name = service_proto.name 706 707 methods = [self._MakeMethodDescriptor(method_proto, service_name, package, 708 scope, index) 709 for index, method_proto in enumerate(service_proto.method)] 710 desc = descriptor.ServiceDescriptor(name=service_proto.name, 711 full_name=service_name, 712 index=service_index, 713 methods=methods, 714 options=service_proto.options, 715 file=file_desc) 716 return desc 717 718 def _MakeMethodDescriptor(self, method_proto, service_name, package, scope, 719 index): 720 """Creates a method descriptor from a MethodDescriptorProto. 721 722 Args: 723 method_proto: The proto describing the method. 724 service_name: The name of the containing service. 725 package: Optional package name to look up for types. 726 scope: Scope containing available types. 727 index: Index of the method in the service. 728 729 Returns: 730 An initialized MethodDescriptor object. 731 """ 732 full_name = '.'.join((service_name, method_proto.name)) 733 input_type = self._GetTypeFromScope( 734 package, method_proto.input_type, scope) 735 output_type = self._GetTypeFromScope( 736 package, method_proto.output_type, scope) 737 return descriptor.MethodDescriptor(name=method_proto.name, 738 full_name=full_name, 739 index=index, 740 containing_service=None, 741 input_type=input_type, 742 output_type=output_type, 743 options=method_proto.options) 744 745 def _ExtractSymbols(self, descriptors): 746 """Pulls out all the symbols from descriptor protos. 747 748 Args: 749 descriptors: The messages to extract descriptors from. 750 Yields: 751 A two element tuple of the type name and descriptor object. 752 """ 753 754 for desc in descriptors: 755 yield (_PrefixWithDot(desc.full_name), desc) 756 for symbol in self._ExtractSymbols(desc.nested_types): 757 yield symbol 758 for enum in desc.enum_types: 759 yield (_PrefixWithDot(enum.full_name), enum) 760 761 def _GetDeps(self, dependencies): 762 """Recursively finds dependencies for file protos. 763 764 Args: 765 dependencies: The names of the files being depended on. 766 767 Yields: 768 Each direct and indirect dependency. 769 """ 770 771 for dependency in dependencies: 772 dep_desc = self.FindFileByName(dependency) 773 yield dep_desc 774 for parent_dep in dep_desc.dependencies: 775 yield parent_dep 776 777 def _GetTypeFromScope(self, package, type_name, scope): 778 """Finds a given type name in the current scope. 779 780 Args: 781 package: The package the proto should be located in. 782 type_name: The name of the type to be found in the scope. 783 scope: Dict mapping short and full symbols to message and enum types. 784 785 Returns: 786 The descriptor for the requested type. 787 """ 788 if type_name not in scope: 789 components = _PrefixWithDot(package).split('.') 790 while components: 791 possible_match = '.'.join(components + [type_name]) 792 if possible_match in scope: 793 type_name = possible_match 794 break 795 else: 796 components.pop(-1) 797 return scope[type_name] 798 799 800def _PrefixWithDot(name): 801 return name if name.startswith('.') else '.%s' % name 802 803 804if _USE_C_DESCRIPTORS: 805 # TODO(amauryfa): This pool could be constructed from Python code, when we 806 # support a flag like 'use_cpp_generated_pool=True'. 807 # pylint: disable=protected-access 808 _DEFAULT = descriptor._message.default_pool 809else: 810 _DEFAULT = DescriptorPool() 811 812 813def Default(): 814 return _DEFAULT 815