Package google :: Package protobuf :: Module descriptor_pool
[hide private]
[frames] | no frames]

Source Code for Module google.protobuf.descriptor_pool

   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   
  33  The DescriptorPool is used in conjection with a DescriptorDatabase to maintain 
  34  a collection of protocol buffer descriptors for use when dynamically creating 
  35  message types at runtime. 
  36   
  37  For most applications protocol buffers should be used via modules generated by 
  38  the protocol buffer compiler tool. This should only be used when the type of 
  39  protocol buffers used in an application or library cannot be predetermined. 
  40   
  41  Below 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   
  49  The message descriptor can be used in conjunction with the message_factory 
  50  module in order to create a protocol buffer class that can be encoded and 
  51  decoded. 
  52   
  53  If you want to get a Python class for the specified proto, use the 
  54  helper functions inside google.protobuf.message_factory 
  55  directly instead of this class. 
  56  """ 
  57   
  58  __author__ = 'matthewtoia@google.com (Matt Toia)' 
  59   
  60  import collections 
  61  import warnings 
  62   
  63  from google.protobuf import descriptor 
  64  from google.protobuf import descriptor_database 
  65  from google.protobuf import text_encoding 
  66   
  67   
  68  _USE_C_DESCRIPTORS = descriptor._USE_C_DESCRIPTORS  # pylint: disable=protected-access 
69 70 71 -def _Deprecated(func):
72 """Mark functions as deprecated.""" 73 74 def NewFunc(*args, **kwargs): 75 warnings.warn( 76 'Call to deprecated function %s(). Note: Do add unlinked descriptors ' 77 'to descriptor_pool is wrong. Use Add() or AddSerializedFile() ' 78 'instead.' % func.__name__, 79 category=DeprecationWarning) 80 return func(*args, **kwargs)
81 NewFunc.__name__ = func.__name__ 82 NewFunc.__doc__ = func.__doc__ 83 NewFunc.__dict__.update(func.__dict__) 84 return NewFunc 85
86 87 -def _NormalizeFullyQualifiedName(name):
88 """Remove leading period from fully-qualified type name. 89 90 Due to b/13860351 in descriptor_database.py, types in the root namespace are 91 generated with a leading period. This function removes that prefix. 92 93 Args: 94 name: A str, the fully-qualified symbol name. 95 96 Returns: 97 A str, the normalized fully-qualified symbol name. 98 """ 99 return name.lstrip('.')
100
101 102 -def _OptionsOrNone(descriptor_proto):
103 """Returns the value of the field `options`, or None if it is not set.""" 104 if descriptor_proto.HasField('options'): 105 return descriptor_proto.options 106 else: 107 return None
108
109 110 -def _IsMessageSetExtension(field):
111 return (field.is_extension and 112 field.containing_type.has_options and 113 field.containing_type.GetOptions().message_set_wire_format and 114 field.type == descriptor.FieldDescriptor.TYPE_MESSAGE and 115 field.label == descriptor.FieldDescriptor.LABEL_OPTIONAL)
116
117 118 -class DescriptorPool(object):
119 """A collection of protobufs dynamically constructed by descriptor protos.""" 120 121 if _USE_C_DESCRIPTORS: 122
123 - def __new__(cls, descriptor_db=None):
124 # pylint: disable=protected-access 125 return descriptor._message.DescriptorPool(descriptor_db)
126
127 - def __init__(self, descriptor_db=None):
128 """Initializes a Pool of proto buffs. 129 130 The descriptor_db argument to the constructor is provided to allow 131 specialized file descriptor proto lookup code to be triggered on demand. An 132 example would be an implementation which will read and compile a file 133 specified in a call to FindFileByName() and not require the call to Add() 134 at all. Results from this database will be cached internally here as well. 135 136 Args: 137 descriptor_db: A secondary source of file descriptors. 138 """ 139 140 self._internal_db = descriptor_database.DescriptorDatabase() 141 self._descriptor_db = descriptor_db 142 self._descriptors = {} 143 self._enum_descriptors = {} 144 self._service_descriptors = {} 145 self._file_descriptors = {} 146 self._toplevel_extensions = {} 147 # TODO(jieluo): Remove _file_desc_by_toplevel_extension after 148 # maybe year 2020 for compatibility issue (with 3.4.1 only). 149 self._file_desc_by_toplevel_extension = {} 150 self._top_enum_values = {} 151 # We store extensions in two two-level mappings: The first key is the 152 # descriptor of the message being extended, the second key is the extension 153 # full name or its tag number. 154 self._extensions_by_name = collections.defaultdict(dict) 155 self._extensions_by_number = collections.defaultdict(dict)
156
157 - def _CheckConflictRegister(self, desc, desc_name, file_name):
158 """Check if the descriptor name conflicts with another of the same name. 159 160 Args: 161 desc: Descriptor of a message, enum, service, extension or enum value. 162 desc_name: the full name of desc. 163 file_name: The file name of descriptor. 164 """ 165 for register, descriptor_type in [ 166 (self._descriptors, descriptor.Descriptor), 167 (self._enum_descriptors, descriptor.EnumDescriptor), 168 (self._service_descriptors, descriptor.ServiceDescriptor), 169 (self._toplevel_extensions, descriptor.FieldDescriptor), 170 (self._top_enum_values, descriptor.EnumValueDescriptor)]: 171 if desc_name in register: 172 old_desc = register[desc_name] 173 if isinstance(old_desc, descriptor.EnumValueDescriptor): 174 old_file = old_desc.type.file.name 175 else: 176 old_file = old_desc.file.name 177 178 if not isinstance(desc, descriptor_type) or ( 179 old_file != file_name): 180 error_msg = ('Conflict register for file "' + file_name + 181 '": ' + desc_name + 182 ' is already defined in file "' + 183 old_file + '". Please fix the conflict by adding ' 184 'package name on the proto file, or use different ' 185 'name for the duplication.') 186 if isinstance(desc, descriptor.EnumValueDescriptor): 187 error_msg += ('\nNote: enum values appear as ' 188 'siblings of the enum type instead of ' 189 'children of it.') 190 191 raise TypeError(error_msg) 192 193 return
194
195 - def Add(self, file_desc_proto):
196 """Adds the FileDescriptorProto and its types to this pool. 197 198 Args: 199 file_desc_proto: The FileDescriptorProto to add. 200 """ 201 202 self._internal_db.Add(file_desc_proto)
203
204 - def AddSerializedFile(self, serialized_file_desc_proto):
205 """Adds the FileDescriptorProto and its types to this pool. 206 207 Args: 208 serialized_file_desc_proto: A bytes string, serialization of the 209 FileDescriptorProto to add. 210 """ 211 212 # pylint: disable=g-import-not-at-top 213 from google.protobuf import descriptor_pb2 214 file_desc_proto = descriptor_pb2.FileDescriptorProto.FromString( 215 serialized_file_desc_proto) 216 self.Add(file_desc_proto)
217 218 # Add Descriptor to descriptor pool is dreprecated. Please use Add() 219 # or AddSerializedFile() to add a FileDescriptorProto instead. 220 @_Deprecated
221 - def AddDescriptor(self, desc):
222 self._AddDescriptor(desc)
223 224 # Never call this method. It is for internal usage only.
225 - def _AddDescriptor(self, desc):
226 """Adds a Descriptor to the pool, non-recursively. 227 228 If the Descriptor contains nested messages or enums, the caller must 229 explicitly register them. This method also registers the FileDescriptor 230 associated with the message. 231 232 Args: 233 desc: A Descriptor. 234 """ 235 if not isinstance(desc, descriptor.Descriptor): 236 raise TypeError('Expected instance of descriptor.Descriptor.') 237 238 self._CheckConflictRegister(desc, desc.full_name, desc.file.name) 239 240 self._descriptors[desc.full_name] = desc 241 self._AddFileDescriptor(desc.file)
242 243 # Add EnumDescriptor to descriptor pool is dreprecated. Please use Add() 244 # or AddSerializedFile() to add a FileDescriptorProto instead. 245 @_Deprecated
246 - def AddEnumDescriptor(self, enum_desc):
247 self._AddEnumDescriptor(enum_desc)
248 249 # Never call this method. It is for internal usage only.
250 - def _AddEnumDescriptor(self, enum_desc):
251 """Adds an EnumDescriptor to the pool. 252 253 This method also registers the FileDescriptor associated with the enum. 254 255 Args: 256 enum_desc: An EnumDescriptor. 257 """ 258 259 if not isinstance(enum_desc, descriptor.EnumDescriptor): 260 raise TypeError('Expected instance of descriptor.EnumDescriptor.') 261 262 file_name = enum_desc.file.name 263 self._CheckConflictRegister(enum_desc, enum_desc.full_name, file_name) 264 self._enum_descriptors[enum_desc.full_name] = enum_desc 265 266 # Top enum values need to be indexed. 267 # Count the number of dots to see whether the enum is toplevel or nested 268 # in a message. We cannot use enum_desc.containing_type at this stage. 269 if enum_desc.file.package: 270 top_level = (enum_desc.full_name.count('.') 271 - enum_desc.file.package.count('.') == 1) 272 else: 273 top_level = enum_desc.full_name.count('.') == 0 274 if top_level: 275 file_name = enum_desc.file.name 276 package = enum_desc.file.package 277 for enum_value in enum_desc.values: 278 full_name = _NormalizeFullyQualifiedName( 279 '.'.join((package, enum_value.name))) 280 self._CheckConflictRegister(enum_value, full_name, file_name) 281 self._top_enum_values[full_name] = enum_value 282 self._AddFileDescriptor(enum_desc.file)
283 284 # Add ServiceDescriptor to descriptor pool is dreprecated. Please use Add() 285 # or AddSerializedFile() to add a FileDescriptorProto instead. 286 @_Deprecated
287 - def AddServiceDescriptor(self, service_desc):
288 self._AddServiceDescriptor(service_desc)
289 290 # Never call this method. It is for internal usage only.
291 - def _AddServiceDescriptor(self, service_desc):
292 """Adds a ServiceDescriptor to the pool. 293 294 Args: 295 service_desc: A ServiceDescriptor. 296 """ 297 298 if not isinstance(service_desc, descriptor.ServiceDescriptor): 299 raise TypeError('Expected instance of descriptor.ServiceDescriptor.') 300 301 self._CheckConflictRegister(service_desc, service_desc.full_name, 302 service_desc.file.name) 303 self._service_descriptors[service_desc.full_name] = service_desc
304 305 # Add ExtensionDescriptor to descriptor pool is dreprecated. Please use Add() 306 # or AddSerializedFile() to add a FileDescriptorProto instead. 307 @_Deprecated
308 - def AddExtensionDescriptor(self, extension):
309 self._AddExtensionDescriptor(extension)
310 311 # Never call this method. It is for internal usage only.
312 - def _AddExtensionDescriptor(self, extension):
313 """Adds a FieldDescriptor describing an extension to the pool. 314 315 Args: 316 extension: A FieldDescriptor. 317 318 Raises: 319 AssertionError: when another extension with the same number extends the 320 same message. 321 TypeError: when the specified extension is not a 322 descriptor.FieldDescriptor. 323 """ 324 if not (isinstance(extension, descriptor.FieldDescriptor) and 325 extension.is_extension): 326 raise TypeError('Expected an extension descriptor.') 327 328 if extension.extension_scope is None: 329 self._toplevel_extensions[extension.full_name] = extension 330 331 try: 332 existing_desc = self._extensions_by_number[ 333 extension.containing_type][extension.number] 334 except KeyError: 335 pass 336 else: 337 if extension is not existing_desc: 338 raise AssertionError( 339 'Extensions "%s" and "%s" both try to extend message type "%s" ' 340 'with field number %d.' % 341 (extension.full_name, existing_desc.full_name, 342 extension.containing_type.full_name, extension.number)) 343 344 self._extensions_by_number[extension.containing_type][ 345 extension.number] = extension 346 self._extensions_by_name[extension.containing_type][ 347 extension.full_name] = extension 348 349 # Also register MessageSet extensions with the type name. 350 if _IsMessageSetExtension(extension): 351 self._extensions_by_name[extension.containing_type][ 352 extension.message_type.full_name] = extension
353 354 @_Deprecated
355 - def AddFileDescriptor(self, file_desc):
356 self._InternalAddFileDescriptor(file_desc)
357 358 # Never call this method. It is for internal usage only.
359 - def _InternalAddFileDescriptor(self, file_desc):
360 """Adds a FileDescriptor to the pool, non-recursively. 361 362 If the FileDescriptor contains messages or enums, the caller must explicitly 363 register them. 364 365 Args: 366 file_desc: A FileDescriptor. 367 """ 368 369 self._AddFileDescriptor(file_desc) 370 # TODO(jieluo): This is a temporary solution for FieldDescriptor.file. 371 # FieldDescriptor.file is added in code gen. Remove this solution after 372 # maybe 2020 for compatibility reason (with 3.4.1 only). 373 for extension in file_desc.extensions_by_name.values(): 374 self._file_desc_by_toplevel_extension[ 375 extension.full_name] = file_desc
376
377 - def _AddFileDescriptor(self, file_desc):
378 """Adds a FileDescriptor to the pool, non-recursively. 379 380 If the FileDescriptor contains messages or enums, the caller must explicitly 381 register them. 382 383 Args: 384 file_desc: A FileDescriptor. 385 """ 386 387 if not isinstance(file_desc, descriptor.FileDescriptor): 388 raise TypeError('Expected instance of descriptor.FileDescriptor.') 389 self._file_descriptors[file_desc.name] = file_desc
390
391 - def FindFileByName(self, file_name):
392 """Gets a FileDescriptor by file name. 393 394 Args: 395 file_name: The path to the file to get a descriptor for. 396 397 Returns: 398 A FileDescriptor for the named file. 399 400 Raises: 401 KeyError: if the file cannot be found in the pool. 402 """ 403 404 try: 405 return self._file_descriptors[file_name] 406 except KeyError: 407 pass 408 409 try: 410 file_proto = self._internal_db.FindFileByName(file_name) 411 except KeyError as error: 412 if self._descriptor_db: 413 file_proto = self._descriptor_db.FindFileByName(file_name) 414 else: 415 raise error 416 if not file_proto: 417 raise KeyError('Cannot find a file named %s' % file_name) 418 return self._ConvertFileProtoToFileDescriptor(file_proto)
419
420 - def FindFileContainingSymbol(self, symbol):
421 """Gets the FileDescriptor for the file containing the specified symbol. 422 423 Args: 424 symbol: The name of the symbol to search for. 425 426 Returns: 427 A FileDescriptor that contains the specified symbol. 428 429 Raises: 430 KeyError: if the file cannot be found in the pool. 431 """ 432 433 symbol = _NormalizeFullyQualifiedName(symbol) 434 try: 435 return self._InternalFindFileContainingSymbol(symbol) 436 except KeyError: 437 pass 438 439 try: 440 # Try fallback database. Build and find again if possible. 441 self._FindFileContainingSymbolInDb(symbol) 442 return self._InternalFindFileContainingSymbol(symbol) 443 except KeyError: 444 raise KeyError('Cannot find a file containing %s' % symbol)
445
446 - def _InternalFindFileContainingSymbol(self, symbol):
447 """Gets the already built FileDescriptor containing the specified symbol. 448 449 Args: 450 symbol: The name of the symbol to search for. 451 452 Returns: 453 A FileDescriptor that contains the specified symbol. 454 455 Raises: 456 KeyError: if the file cannot be found in the pool. 457 """ 458 try: 459 return self._descriptors[symbol].file 460 except KeyError: 461 pass 462 463 try: 464 return self._enum_descriptors[symbol].file 465 except KeyError: 466 pass 467 468 try: 469 return self._service_descriptors[symbol].file 470 except KeyError: 471 pass 472 473 try: 474 return self._top_enum_values[symbol].type.file 475 except KeyError: 476 pass 477 478 try: 479 return self._file_desc_by_toplevel_extension[symbol] 480 except KeyError: 481 pass 482 483 # Try fields, enum values and nested extensions inside a message. 484 top_name, _, sub_name = symbol.rpartition('.') 485 try: 486 message = self.FindMessageTypeByName(top_name) 487 assert (sub_name in message.extensions_by_name or 488 sub_name in message.fields_by_name or 489 sub_name in message.enum_values_by_name) 490 return message.file 491 except (KeyError, AssertionError): 492 raise KeyError('Cannot find a file containing %s' % symbol)
493
494 - def FindMessageTypeByName(self, full_name):
495 """Loads the named descriptor from the pool. 496 497 Args: 498 full_name: The full name of the descriptor to load. 499 500 Returns: 501 The descriptor for the named type. 502 503 Raises: 504 KeyError: if the message cannot be found in the pool. 505 """ 506 507 full_name = _NormalizeFullyQualifiedName(full_name) 508 if full_name not in self._descriptors: 509 self._FindFileContainingSymbolInDb(full_name) 510 return self._descriptors[full_name]
511
512 - def FindEnumTypeByName(self, full_name):
513 """Loads the named enum descriptor from the pool. 514 515 Args: 516 full_name: The full name of the enum descriptor to load. 517 518 Returns: 519 The enum descriptor for the named type. 520 521 Raises: 522 KeyError: if the enum cannot be found in the pool. 523 """ 524 525 full_name = _NormalizeFullyQualifiedName(full_name) 526 if full_name not in self._enum_descriptors: 527 self._FindFileContainingSymbolInDb(full_name) 528 return self._enum_descriptors[full_name]
529
530 - def FindFieldByName(self, full_name):
531 """Loads the named field descriptor from the pool. 532 533 Args: 534 full_name: The full name of the field descriptor to load. 535 536 Returns: 537 The field descriptor for the named field. 538 539 Raises: 540 KeyError: if the field cannot be found in the pool. 541 """ 542 full_name = _NormalizeFullyQualifiedName(full_name) 543 message_name, _, field_name = full_name.rpartition('.') 544 message_descriptor = self.FindMessageTypeByName(message_name) 545 return message_descriptor.fields_by_name[field_name]
546
547 - def FindOneofByName(self, full_name):
548 """Loads the named oneof descriptor from the pool. 549 550 Args: 551 full_name: The full name of the oneof descriptor to load. 552 553 Returns: 554 The oneof descriptor for the named oneof. 555 556 Raises: 557 KeyError: if the oneof cannot be found in the pool. 558 """ 559 full_name = _NormalizeFullyQualifiedName(full_name) 560 message_name, _, oneof_name = full_name.rpartition('.') 561 message_descriptor = self.FindMessageTypeByName(message_name) 562 return message_descriptor.oneofs_by_name[oneof_name]
563
564 - def FindExtensionByName(self, full_name):
565 """Loads the named extension descriptor from the pool. 566 567 Args: 568 full_name: The full name of the extension descriptor to load. 569 570 Returns: 571 A FieldDescriptor, describing the named extension. 572 573 Raises: 574 KeyError: if the extension cannot be found in the pool. 575 """ 576 full_name = _NormalizeFullyQualifiedName(full_name) 577 try: 578 # The proto compiler does not give any link between the FileDescriptor 579 # and top-level extensions unless the FileDescriptorProto is added to 580 # the DescriptorDatabase, but this can impact memory usage. 581 # So we registered these extensions by name explicitly. 582 return self._toplevel_extensions[full_name] 583 except KeyError: 584 pass 585 message_name, _, extension_name = full_name.rpartition('.') 586 try: 587 # Most extensions are nested inside a message. 588 scope = self.FindMessageTypeByName(message_name) 589 except KeyError: 590 # Some extensions are defined at file scope. 591 scope = self._FindFileContainingSymbolInDb(full_name) 592 return scope.extensions_by_name[extension_name]
593
594 - def FindExtensionByNumber(self, message_descriptor, number):
595 """Gets the extension of the specified message with the specified number. 596 597 Extensions have to be registered to this pool by calling 598 AddExtensionDescriptor. 599 600 Args: 601 message_descriptor: descriptor of the extended message. 602 number: integer, number of the extension field. 603 604 Returns: 605 A FieldDescriptor describing the extension. 606 607 Raises: 608 KeyError: when no extension with the given number is known for the 609 specified message. 610 """ 611 try: 612 return self._extensions_by_number[message_descriptor][number] 613 except KeyError: 614 self._TryLoadExtensionFromDB(message_descriptor, number) 615 return self._extensions_by_number[message_descriptor][number]
616
617 - def FindAllExtensions(self, message_descriptor):
618 """Gets all the known extension of a given message. 619 620 Extensions have to be registered to this pool by calling 621 AddExtensionDescriptor. 622 623 Args: 624 message_descriptor: descriptor of the extended message. 625 626 Returns: 627 A list of FieldDescriptor describing the extensions. 628 """ 629 # Fallback to descriptor db if FindAllExtensionNumbers is provided. 630 if self._descriptor_db and hasattr( 631 self._descriptor_db, 'FindAllExtensionNumbers'): 632 full_name = message_descriptor.full_name 633 all_numbers = self._descriptor_db.FindAllExtensionNumbers(full_name) 634 for number in all_numbers: 635 if number in self._extensions_by_number[message_descriptor]: 636 continue 637 self._TryLoadExtensionFromDB(message_descriptor, number) 638 639 return list(self._extensions_by_number[message_descriptor].values())
640
641 - def _TryLoadExtensionFromDB(self, message_descriptor, number):
642 """Try to Load extensions from decriptor db. 643 644 Args: 645 message_descriptor: descriptor of the extended message. 646 number: the extension number that needs to be loaded. 647 """ 648 if not self._descriptor_db: 649 return 650 # Only supported when FindFileContainingExtension is provided. 651 if not hasattr( 652 self._descriptor_db, 'FindFileContainingExtension'): 653 return 654 655 full_name = message_descriptor.full_name 656 file_proto = self._descriptor_db.FindFileContainingExtension( 657 full_name, number) 658 659 if file_proto is None: 660 return 661 662 try: 663 file_desc = self._ConvertFileProtoToFileDescriptor(file_proto) 664 for extension in file_desc.extensions_by_name.values(): 665 self._extensions_by_number[extension.containing_type][ 666 extension.number] = extension 667 self._extensions_by_name[extension.containing_type][ 668 extension.full_name] = extension 669 for message_type in file_desc.message_types_by_name.values(): 670 for extension in message_type.extensions: 671 self._extensions_by_number[extension.containing_type][ 672 extension.number] = extension 673 self._extensions_by_name[extension.containing_type][ 674 extension.full_name] = extension 675 except: 676 warn_msg = ('Unable to load proto file %s for extension number %d.' % 677 (file_proto.name, number)) 678 warnings.warn(warn_msg, RuntimeWarning)
679
680 - def FindServiceByName(self, full_name):
681 """Loads the named service descriptor from the pool. 682 683 Args: 684 full_name: The full name of the service descriptor to load. 685 686 Returns: 687 The service descriptor for the named service. 688 689 Raises: 690 KeyError: if the service cannot be found in the pool. 691 """ 692 full_name = _NormalizeFullyQualifiedName(full_name) 693 if full_name not in self._service_descriptors: 694 self._FindFileContainingSymbolInDb(full_name) 695 return self._service_descriptors[full_name]
696
697 - def FindMethodByName(self, full_name):
698 """Loads the named service method descriptor from the pool. 699 700 Args: 701 full_name: The full name of the method descriptor to load. 702 703 Returns: 704 The method descriptor for the service method. 705 706 Raises: 707 KeyError: if the method cannot be found in the pool. 708 """ 709 full_name = _NormalizeFullyQualifiedName(full_name) 710 service_name, _, method_name = full_name.rpartition('.') 711 service_descriptor = self.FindServiceByName(service_name) 712 return service_descriptor.methods_by_name[method_name]
713
714 - def _FindFileContainingSymbolInDb(self, symbol):
715 """Finds the file in descriptor DB containing the specified symbol. 716 717 Args: 718 symbol: The name of the symbol to search for. 719 720 Returns: 721 A FileDescriptor that contains the specified symbol. 722 723 Raises: 724 KeyError: if the file cannot be found in the descriptor database. 725 """ 726 try: 727 file_proto = self._internal_db.FindFileContainingSymbol(symbol) 728 except KeyError as error: 729 if self._descriptor_db: 730 file_proto = self._descriptor_db.FindFileContainingSymbol(symbol) 731 else: 732 raise error 733 if not file_proto: 734 raise KeyError('Cannot find a file containing %s' % symbol) 735 return self._ConvertFileProtoToFileDescriptor(file_proto)
736
737 - def _ConvertFileProtoToFileDescriptor(self, file_proto):
738 """Creates a FileDescriptor from a proto or returns a cached copy. 739 740 This method also has the side effect of loading all the symbols found in 741 the file into the appropriate dictionaries in the pool. 742 743 Args: 744 file_proto: The proto to convert. 745 746 Returns: 747 A FileDescriptor matching the passed in proto. 748 """ 749 if file_proto.name not in self._file_descriptors: 750 built_deps = list(self._GetDeps(file_proto.dependency)) 751 direct_deps = [self.FindFileByName(n) for n in file_proto.dependency] 752 public_deps = [direct_deps[i] for i in file_proto.public_dependency] 753 754 file_descriptor = descriptor.FileDescriptor( 755 pool=self, 756 name=file_proto.name, 757 package=file_proto.package, 758 syntax=file_proto.syntax, 759 options=_OptionsOrNone(file_proto), 760 serialized_pb=file_proto.SerializeToString(), 761 dependencies=direct_deps, 762 public_dependencies=public_deps) 763 scope = {} 764 765 # This loop extracts all the message and enum types from all the 766 # dependencies of the file_proto. This is necessary to create the 767 # scope of available message types when defining the passed in 768 # file proto. 769 for dependency in built_deps: 770 scope.update(self._ExtractSymbols( 771 dependency.message_types_by_name.values())) 772 scope.update((_PrefixWithDot(enum.full_name), enum) 773 for enum in dependency.enum_types_by_name.values()) 774 775 for message_type in file_proto.message_type: 776 message_desc = self._ConvertMessageDescriptor( 777 message_type, file_proto.package, file_descriptor, scope, 778 file_proto.syntax) 779 file_descriptor.message_types_by_name[message_desc.name] = ( 780 message_desc) 781 782 for enum_type in file_proto.enum_type: 783 file_descriptor.enum_types_by_name[enum_type.name] = ( 784 self._ConvertEnumDescriptor(enum_type, file_proto.package, 785 file_descriptor, None, scope, True)) 786 787 for index, extension_proto in enumerate(file_proto.extension): 788 extension_desc = self._MakeFieldDescriptor( 789 extension_proto, file_proto.package, index, file_descriptor, 790 is_extension=True) 791 extension_desc.containing_type = self._GetTypeFromScope( 792 file_descriptor.package, extension_proto.extendee, scope) 793 self._SetFieldType(extension_proto, extension_desc, 794 file_descriptor.package, scope) 795 file_descriptor.extensions_by_name[extension_desc.name] = ( 796 extension_desc) 797 self._file_desc_by_toplevel_extension[extension_desc.full_name] = ( 798 file_descriptor) 799 800 for desc_proto in file_proto.message_type: 801 self._SetAllFieldTypes(file_proto.package, desc_proto, scope) 802 803 if file_proto.package: 804 desc_proto_prefix = _PrefixWithDot(file_proto.package) 805 else: 806 desc_proto_prefix = '' 807 808 for desc_proto in file_proto.message_type: 809 desc = self._GetTypeFromScope( 810 desc_proto_prefix, desc_proto.name, scope) 811 file_descriptor.message_types_by_name[desc_proto.name] = desc 812 813 for index, service_proto in enumerate(file_proto.service): 814 file_descriptor.services_by_name[service_proto.name] = ( 815 self._MakeServiceDescriptor(service_proto, index, scope, 816 file_proto.package, file_descriptor)) 817 818 self.Add(file_proto) 819 self._file_descriptors[file_proto.name] = file_descriptor 820 821 return self._file_descriptors[file_proto.name]
822
823 - def _ConvertMessageDescriptor(self, desc_proto, package=None, file_desc=None, 824 scope=None, syntax=None):
825 """Adds the proto to the pool in the specified package. 826 827 Args: 828 desc_proto: The descriptor_pb2.DescriptorProto protobuf message. 829 package: The package the proto should be located in. 830 file_desc: The file containing this message. 831 scope: Dict mapping short and full symbols to message and enum types. 832 syntax: string indicating syntax of the file ("proto2" or "proto3") 833 834 Returns: 835 The added descriptor. 836 """ 837 838 if package: 839 desc_name = '.'.join((package, desc_proto.name)) 840 else: 841 desc_name = desc_proto.name 842 843 if file_desc is None: 844 file_name = None 845 else: 846 file_name = file_desc.name 847 848 if scope is None: 849 scope = {} 850 851 nested = [ 852 self._ConvertMessageDescriptor( 853 nested, desc_name, file_desc, scope, syntax) 854 for nested in desc_proto.nested_type] 855 enums = [ 856 self._ConvertEnumDescriptor(enum, desc_name, file_desc, None, 857 scope, False) 858 for enum in desc_proto.enum_type] 859 fields = [self._MakeFieldDescriptor(field, desc_name, index, file_desc) 860 for index, field in enumerate(desc_proto.field)] 861 extensions = [ 862 self._MakeFieldDescriptor(extension, desc_name, index, file_desc, 863 is_extension=True) 864 for index, extension in enumerate(desc_proto.extension)] 865 oneofs = [ 866 descriptor.OneofDescriptor(desc.name, '.'.join((desc_name, desc.name)), 867 index, None, [], desc.options) 868 for index, desc in enumerate(desc_proto.oneof_decl)] 869 extension_ranges = [(r.start, r.end) for r in desc_proto.extension_range] 870 if extension_ranges: 871 is_extendable = True 872 else: 873 is_extendable = False 874 desc = descriptor.Descriptor( 875 name=desc_proto.name, 876 full_name=desc_name, 877 filename=file_name, 878 containing_type=None, 879 fields=fields, 880 oneofs=oneofs, 881 nested_types=nested, 882 enum_types=enums, 883 extensions=extensions, 884 options=_OptionsOrNone(desc_proto), 885 is_extendable=is_extendable, 886 extension_ranges=extension_ranges, 887 file=file_desc, 888 serialized_start=None, 889 serialized_end=None, 890 syntax=syntax) 891 for nested in desc.nested_types: 892 nested.containing_type = desc 893 for enum in desc.enum_types: 894 enum.containing_type = desc 895 for field_index, field_desc in enumerate(desc_proto.field): 896 if field_desc.HasField('oneof_index'): 897 oneof_index = field_desc.oneof_index 898 oneofs[oneof_index].fields.append(fields[field_index]) 899 fields[field_index].containing_oneof = oneofs[oneof_index] 900 901 scope[_PrefixWithDot(desc_name)] = desc 902 self._CheckConflictRegister(desc, desc.full_name, desc.file.name) 903 self._descriptors[desc_name] = desc 904 return desc
905
906 - def _ConvertEnumDescriptor(self, enum_proto, package=None, file_desc=None, 907 containing_type=None, scope=None, top_level=False):
908 """Make a protobuf EnumDescriptor given an EnumDescriptorProto protobuf. 909 910 Args: 911 enum_proto: The descriptor_pb2.EnumDescriptorProto protobuf message. 912 package: Optional package name for the new message EnumDescriptor. 913 file_desc: The file containing the enum descriptor. 914 containing_type: The type containing this enum. 915 scope: Scope containing available types. 916 top_level: If True, the enum is a top level symbol. If False, the enum 917 is defined inside a message. 918 919 Returns: 920 The added descriptor 921 """ 922 923 if package: 924 enum_name = '.'.join((package, enum_proto.name)) 925 else: 926 enum_name = enum_proto.name 927 928 if file_desc is None: 929 file_name = None 930 else: 931 file_name = file_desc.name 932 933 values = [self._MakeEnumValueDescriptor(value, index) 934 for index, value in enumerate(enum_proto.value)] 935 desc = descriptor.EnumDescriptor(name=enum_proto.name, 936 full_name=enum_name, 937 filename=file_name, 938 file=file_desc, 939 values=values, 940 containing_type=containing_type, 941 options=_OptionsOrNone(enum_proto)) 942 scope['.%s' % enum_name] = desc 943 self._CheckConflictRegister(desc, desc.full_name, desc.file.name) 944 self._enum_descriptors[enum_name] = desc 945 946 # Add top level enum values. 947 if top_level: 948 for value in values: 949 full_name = _NormalizeFullyQualifiedName( 950 '.'.join((package, value.name))) 951 self._CheckConflictRegister(value, full_name, file_name) 952 self._top_enum_values[full_name] = value 953 954 return desc
955
956 - def _MakeFieldDescriptor(self, field_proto, message_name, index, 957 file_desc, is_extension=False):
958 """Creates a field descriptor from a FieldDescriptorProto. 959 960 For message and enum type fields, this method will do a look up 961 in the pool for the appropriate descriptor for that type. If it 962 is unavailable, it will fall back to the _source function to 963 create it. If this type is still unavailable, construction will 964 fail. 965 966 Args: 967 field_proto: The proto describing the field. 968 message_name: The name of the containing message. 969 index: Index of the field 970 file_desc: The file containing the field descriptor. 971 is_extension: Indication that this field is for an extension. 972 973 Returns: 974 An initialized FieldDescriptor object 975 """ 976 977 if message_name: 978 full_name = '.'.join((message_name, field_proto.name)) 979 else: 980 full_name = field_proto.name 981 982 return descriptor.FieldDescriptor( 983 name=field_proto.name, 984 full_name=full_name, 985 index=index, 986 number=field_proto.number, 987 type=field_proto.type, 988 cpp_type=None, 989 message_type=None, 990 enum_type=None, 991 containing_type=None, 992 label=field_proto.label, 993 has_default_value=False, 994 default_value=None, 995 is_extension=is_extension, 996 extension_scope=None, 997 options=_OptionsOrNone(field_proto), 998 file=file_desc)
999
1000 - def _SetAllFieldTypes(self, package, desc_proto, scope):
1001 """Sets all the descriptor's fields's types. 1002 1003 This method also sets the containing types on any extensions. 1004 1005 Args: 1006 package: The current package of desc_proto. 1007 desc_proto: The message descriptor to update. 1008 scope: Enclosing scope of available types. 1009 """ 1010 1011 package = _PrefixWithDot(package) 1012 1013 main_desc = self._GetTypeFromScope(package, desc_proto.name, scope) 1014 1015 if package == '.': 1016 nested_package = _PrefixWithDot(desc_proto.name) 1017 else: 1018 nested_package = '.'.join([package, desc_proto.name]) 1019 1020 for field_proto, field_desc in zip(desc_proto.field, main_desc.fields): 1021 self._SetFieldType(field_proto, field_desc, nested_package, scope) 1022 1023 for extension_proto, extension_desc in ( 1024 zip(desc_proto.extension, main_desc.extensions)): 1025 extension_desc.containing_type = self._GetTypeFromScope( 1026 nested_package, extension_proto.extendee, scope) 1027 self._SetFieldType(extension_proto, extension_desc, nested_package, scope) 1028 1029 for nested_type in desc_proto.nested_type: 1030 self._SetAllFieldTypes(nested_package, nested_type, scope)
1031
1032 - def _SetFieldType(self, field_proto, field_desc, package, scope):
1033 """Sets the field's type, cpp_type, message_type and enum_type. 1034 1035 Args: 1036 field_proto: Data about the field in proto format. 1037 field_desc: The descriptor to modiy. 1038 package: The package the field's container is in. 1039 scope: Enclosing scope of available types. 1040 """ 1041 if field_proto.type_name: 1042 desc = self._GetTypeFromScope(package, field_proto.type_name, scope) 1043 else: 1044 desc = None 1045 1046 if not field_proto.HasField('type'): 1047 if isinstance(desc, descriptor.Descriptor): 1048 field_proto.type = descriptor.FieldDescriptor.TYPE_MESSAGE 1049 else: 1050 field_proto.type = descriptor.FieldDescriptor.TYPE_ENUM 1051 1052 field_desc.cpp_type = descriptor.FieldDescriptor.ProtoTypeToCppProtoType( 1053 field_proto.type) 1054 1055 if (field_proto.type == descriptor.FieldDescriptor.TYPE_MESSAGE 1056 or field_proto.type == descriptor.FieldDescriptor.TYPE_GROUP): 1057 field_desc.message_type = desc 1058 1059 if field_proto.type == descriptor.FieldDescriptor.TYPE_ENUM: 1060 field_desc.enum_type = desc 1061 1062 if field_proto.label == descriptor.FieldDescriptor.LABEL_REPEATED: 1063 field_desc.has_default_value = False 1064 field_desc.default_value = [] 1065 elif field_proto.HasField('default_value'): 1066 field_desc.has_default_value = True 1067 if (field_proto.type == descriptor.FieldDescriptor.TYPE_DOUBLE or 1068 field_proto.type == descriptor.FieldDescriptor.TYPE_FLOAT): 1069 field_desc.default_value = float(field_proto.default_value) 1070 elif field_proto.type == descriptor.FieldDescriptor.TYPE_STRING: 1071 field_desc.default_value = field_proto.default_value 1072 elif field_proto.type == descriptor.FieldDescriptor.TYPE_BOOL: 1073 field_desc.default_value = field_proto.default_value.lower() == 'true' 1074 elif field_proto.type == descriptor.FieldDescriptor.TYPE_ENUM: 1075 field_desc.default_value = field_desc.enum_type.values_by_name[ 1076 field_proto.default_value].number 1077 elif field_proto.type == descriptor.FieldDescriptor.TYPE_BYTES: 1078 field_desc.default_value = text_encoding.CUnescape( 1079 field_proto.default_value) 1080 elif field_proto.type == descriptor.FieldDescriptor.TYPE_MESSAGE: 1081 field_desc.default_value = None 1082 else: 1083 # All other types are of the "int" type. 1084 field_desc.default_value = int(field_proto.default_value) 1085 else: 1086 field_desc.has_default_value = False 1087 if (field_proto.type == descriptor.FieldDescriptor.TYPE_DOUBLE or 1088 field_proto.type == descriptor.FieldDescriptor.TYPE_FLOAT): 1089 field_desc.default_value = 0.0 1090 elif field_proto.type == descriptor.FieldDescriptor.TYPE_STRING: 1091 field_desc.default_value = u'' 1092 elif field_proto.type == descriptor.FieldDescriptor.TYPE_BOOL: 1093 field_desc.default_value = False 1094 elif field_proto.type == descriptor.FieldDescriptor.TYPE_ENUM: 1095 field_desc.default_value = field_desc.enum_type.values[0].number 1096 elif field_proto.type == descriptor.FieldDescriptor.TYPE_BYTES: 1097 field_desc.default_value = b'' 1098 elif field_proto.type == descriptor.FieldDescriptor.TYPE_MESSAGE: 1099 field_desc.default_value = None 1100 else: 1101 # All other types are of the "int" type. 1102 field_desc.default_value = 0 1103 1104 field_desc.type = field_proto.type
1105
1106 - def _MakeEnumValueDescriptor(self, value_proto, index):
1107 """Creates a enum value descriptor object from a enum value proto. 1108 1109 Args: 1110 value_proto: The proto describing the enum value. 1111 index: The index of the enum value. 1112 1113 Returns: 1114 An initialized EnumValueDescriptor object. 1115 """ 1116 1117 return descriptor.EnumValueDescriptor( 1118 name=value_proto.name, 1119 index=index, 1120 number=value_proto.number, 1121 options=_OptionsOrNone(value_proto), 1122 type=None)
1123
1124 - def _MakeServiceDescriptor(self, service_proto, service_index, scope, 1125 package, file_desc):
1126 """Make a protobuf ServiceDescriptor given a ServiceDescriptorProto. 1127 1128 Args: 1129 service_proto: The descriptor_pb2.ServiceDescriptorProto protobuf message. 1130 service_index: The index of the service in the File. 1131 scope: Dict mapping short and full symbols to message and enum types. 1132 package: Optional package name for the new message EnumDescriptor. 1133 file_desc: The file containing the service descriptor. 1134 1135 Returns: 1136 The added descriptor. 1137 """ 1138 1139 if package: 1140 service_name = '.'.join((package, service_proto.name)) 1141 else: 1142 service_name = service_proto.name 1143 1144 methods = [self._MakeMethodDescriptor(method_proto, service_name, package, 1145 scope, index) 1146 for index, method_proto in enumerate(service_proto.method)] 1147 desc = descriptor.ServiceDescriptor(name=service_proto.name, 1148 full_name=service_name, 1149 index=service_index, 1150 methods=methods, 1151 options=_OptionsOrNone(service_proto), 1152 file=file_desc) 1153 self._CheckConflictRegister(desc, desc.full_name, desc.file.name) 1154 self._service_descriptors[service_name] = desc 1155 return desc
1156
1157 - def _MakeMethodDescriptor(self, method_proto, service_name, package, scope, 1158 index):
1159 """Creates a method descriptor from a MethodDescriptorProto. 1160 1161 Args: 1162 method_proto: The proto describing the method. 1163 service_name: The name of the containing service. 1164 package: Optional package name to look up for types. 1165 scope: Scope containing available types. 1166 index: Index of the method in the service. 1167 1168 Returns: 1169 An initialized MethodDescriptor object. 1170 """ 1171 full_name = '.'.join((service_name, method_proto.name)) 1172 input_type = self._GetTypeFromScope( 1173 package, method_proto.input_type, scope) 1174 output_type = self._GetTypeFromScope( 1175 package, method_proto.output_type, scope) 1176 return descriptor.MethodDescriptor(name=method_proto.name, 1177 full_name=full_name, 1178 index=index, 1179 containing_service=None, 1180 input_type=input_type, 1181 output_type=output_type, 1182 options=_OptionsOrNone(method_proto))
1183
1184 - def _ExtractSymbols(self, descriptors):
1185 """Pulls out all the symbols from descriptor protos. 1186 1187 Args: 1188 descriptors: The messages to extract descriptors from. 1189 Yields: 1190 A two element tuple of the type name and descriptor object. 1191 """ 1192 1193 for desc in descriptors: 1194 yield (_PrefixWithDot(desc.full_name), desc) 1195 for symbol in self._ExtractSymbols(desc.nested_types): 1196 yield symbol 1197 for enum in desc.enum_types: 1198 yield (_PrefixWithDot(enum.full_name), enum)
1199
1200 - def _GetDeps(self, dependencies):
1201 """Recursively finds dependencies for file protos. 1202 1203 Args: 1204 dependencies: The names of the files being depended on. 1205 1206 Yields: 1207 Each direct and indirect dependency. 1208 """ 1209 1210 for dependency in dependencies: 1211 dep_desc = self.FindFileByName(dependency) 1212 yield dep_desc 1213 for parent_dep in dep_desc.dependencies: 1214 yield parent_dep
1215
1216 - def _GetTypeFromScope(self, package, type_name, scope):
1217 """Finds a given type name in the current scope. 1218 1219 Args: 1220 package: The package the proto should be located in. 1221 type_name: The name of the type to be found in the scope. 1222 scope: Dict mapping short and full symbols to message and enum types. 1223 1224 Returns: 1225 The descriptor for the requested type. 1226 """ 1227 if type_name not in scope: 1228 components = _PrefixWithDot(package).split('.') 1229 while components: 1230 possible_match = '.'.join(components + [type_name]) 1231 if possible_match in scope: 1232 type_name = possible_match 1233 break 1234 else: 1235 components.pop(-1) 1236 return scope[type_name]
1237
1238 1239 -def _PrefixWithDot(name):
1240 return name if name.startswith('.') else '.%s' % name
1241 1242 1243 if _USE_C_DESCRIPTORS: 1244 # TODO(amauryfa): This pool could be constructed from Python code, when we 1245 # support a flag like 'use_cpp_generated_pool=True'. 1246 # pylint: disable=protected-access 1247 _DEFAULT = descriptor._message.default_pool 1248 else: 1249 _DEFAULT = DescriptorPool()
1250 1251 1252 -def Default():
1253 return _DEFAULT
1254