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# Needs to stay compatible with Python 2.5 due to GAE. 32# 33# Copyright 2007 Google Inc. All Rights Reserved. 34 35"""Descriptors essentially contain exactly the information found in a .proto 36file, in types that make this information accessible in Python. 37""" 38 39__author__ = 'robinson@google.com (Will Robinson)' 40 41from google.protobuf.internal import api_implementation 42 43 44if api_implementation.Type() == 'cpp': 45 # Used by MakeDescriptor in cpp mode 46 import os 47 import uuid 48 49 if api_implementation.Version() == 2: 50 from google.protobuf.pyext import _message 51 else: 52 from google.protobuf.internal import cpp_message 53 54 55class Error(Exception): 56 """Base error for this module.""" 57 58 59class TypeTransformationError(Error): 60 """Error transforming between python proto type and corresponding C++ type.""" 61 62 63class DescriptorBase(object): 64 65 """Descriptors base class. 66 67 This class is the base of all descriptor classes. It provides common options 68 related functionaility. 69 70 Attributes: 71 has_options: True if the descriptor has non-default options. Usually it 72 is not necessary to read this -- just call GetOptions() which will 73 happily return the default instance. However, it's sometimes useful 74 for efficiency, and also useful inside the protobuf implementation to 75 avoid some bootstrapping issues. 76 """ 77 78 def __init__(self, options, options_class_name): 79 """Initialize the descriptor given its options message and the name of the 80 class of the options message. The name of the class is required in case 81 the options message is None and has to be created. 82 """ 83 self._options = options 84 self._options_class_name = options_class_name 85 86 # Does this descriptor have non-default options? 87 self.has_options = options is not None 88 89 def _SetOptions(self, options, options_class_name): 90 """Sets the descriptor's options 91 92 This function is used in generated proto2 files to update descriptor 93 options. It must not be used outside proto2. 94 """ 95 self._options = options 96 self._options_class_name = options_class_name 97 98 # Does this descriptor have non-default options? 99 self.has_options = options is not None 100 101 def GetOptions(self): 102 """Retrieves descriptor options. 103 104 This method returns the options set or creates the default options for the 105 descriptor. 106 """ 107 if self._options: 108 return self._options 109 from google.protobuf import descriptor_pb2 110 try: 111 options_class = getattr(descriptor_pb2, self._options_class_name) 112 except AttributeError: 113 raise RuntimeError('Unknown options class name %s!' % 114 (self._options_class_name)) 115 self._options = options_class() 116 return self._options 117 118 119class _NestedDescriptorBase(DescriptorBase): 120 """Common class for descriptors that can be nested.""" 121 122 def __init__(self, options, options_class_name, name, full_name, 123 file, containing_type, serialized_start=None, 124 serialized_end=None): 125 """Constructor. 126 127 Args: 128 options: Protocol message options or None 129 to use default message options. 130 options_class_name: (str) The class name of the above options. 131 132 name: (str) Name of this protocol message type. 133 full_name: (str) Fully-qualified name of this protocol message type, 134 which will include protocol "package" name and the name of any 135 enclosing types. 136 file: (FileDescriptor) Reference to file info. 137 containing_type: if provided, this is a nested descriptor, with this 138 descriptor as parent, otherwise None. 139 serialized_start: The start index (inclusive) in block in the 140 file.serialized_pb that describes this descriptor. 141 serialized_end: The end index (exclusive) in block in the 142 file.serialized_pb that describes this descriptor. 143 """ 144 super(_NestedDescriptorBase, self).__init__( 145 options, options_class_name) 146 147 self.name = name 148 # TODO(falk): Add function to calculate full_name instead of having it in 149 # memory? 150 self.full_name = full_name 151 self.file = file 152 self.containing_type = containing_type 153 154 self._serialized_start = serialized_start 155 self._serialized_end = serialized_end 156 157 def GetTopLevelContainingType(self): 158 """Returns the root if this is a nested type, or itself if its the root.""" 159 desc = self 160 while desc.containing_type is not None: 161 desc = desc.containing_type 162 return desc 163 164 def CopyToProto(self, proto): 165 """Copies this to the matching proto in descriptor_pb2. 166 167 Args: 168 proto: An empty proto instance from descriptor_pb2. 169 170 Raises: 171 Error: If self couldnt be serialized, due to to few constructor arguments. 172 """ 173 if (self.file is not None and 174 self._serialized_start is not None and 175 self._serialized_end is not None): 176 proto.ParseFromString(self.file.serialized_pb[ 177 self._serialized_start:self._serialized_end]) 178 else: 179 raise Error('Descriptor does not contain serialization.') 180 181 182class Descriptor(_NestedDescriptorBase): 183 184 """Descriptor for a protocol message type. 185 186 A Descriptor instance has the following attributes: 187 188 name: (str) Name of this protocol message type. 189 full_name: (str) Fully-qualified name of this protocol message type, 190 which will include protocol "package" name and the name of any 191 enclosing types. 192 193 containing_type: (Descriptor) Reference to the descriptor of the 194 type containing us, or None if this is top-level. 195 196 fields: (list of FieldDescriptors) Field descriptors for all 197 fields in this type. 198 fields_by_number: (dict int -> FieldDescriptor) Same FieldDescriptor 199 objects as in |fields|, but indexed by "number" attribute in each 200 FieldDescriptor. 201 fields_by_name: (dict str -> FieldDescriptor) Same FieldDescriptor 202 objects as in |fields|, but indexed by "name" attribute in each 203 FieldDescriptor. 204 205 nested_types: (list of Descriptors) Descriptor references 206 for all protocol message types nested within this one. 207 nested_types_by_name: (dict str -> Descriptor) Same Descriptor 208 objects as in |nested_types|, but indexed by "name" attribute 209 in each Descriptor. 210 211 enum_types: (list of EnumDescriptors) EnumDescriptor references 212 for all enums contained within this type. 213 enum_types_by_name: (dict str ->EnumDescriptor) Same EnumDescriptor 214 objects as in |enum_types|, but indexed by "name" attribute 215 in each EnumDescriptor. 216 enum_values_by_name: (dict str -> EnumValueDescriptor) Dict mapping 217 from enum value name to EnumValueDescriptor for that value. 218 219 extensions: (list of FieldDescriptor) All extensions defined directly 220 within this message type (NOT within a nested type). 221 extensions_by_name: (dict, string -> FieldDescriptor) Same FieldDescriptor 222 objects as |extensions|, but indexed by "name" attribute of each 223 FieldDescriptor. 224 225 is_extendable: Does this type define any extension ranges? 226 227 options: (descriptor_pb2.MessageOptions) Protocol message options or None 228 to use default message options. 229 230 oneofs: (list of OneofDescriptor) The list of descriptors for oneof fields 231 in this message. 232 oneofs_by_name: (dict str -> OneofDescriptor) Same objects as in |oneofs|, 233 but indexed by "name" attribute. 234 235 file: (FileDescriptor) Reference to file descriptor. 236 """ 237 238 # NOTE(tmarek): The file argument redefining a builtin is nothing we can 239 # fix right now since we don't know how many clients already rely on the 240 # name of the argument. 241 def __init__(self, name, full_name, filename, containing_type, fields, 242 nested_types, enum_types, extensions, options=None, 243 is_extendable=True, extension_ranges=None, oneofs=None, 244 file=None, serialized_start=None, serialized_end=None): # pylint:disable=redefined-builtin 245 """Arguments to __init__() are as described in the description 246 of Descriptor fields above. 247 248 Note that filename is an obsolete argument, that is not used anymore. 249 Please use file.name to access this as an attribute. 250 """ 251 super(Descriptor, self).__init__( 252 options, 'MessageOptions', name, full_name, file, 253 containing_type, serialized_start=serialized_start, 254 serialized_end=serialized_end) 255 256 # We have fields in addition to fields_by_name and fields_by_number, 257 # so that: 258 # 1. Clients can index fields by "order in which they're listed." 259 # 2. Clients can easily iterate over all fields with the terse 260 # syntax: for f in descriptor.fields: ... 261 self.fields = fields 262 for field in self.fields: 263 field.containing_type = self 264 self.fields_by_number = dict((f.number, f) for f in fields) 265 self.fields_by_name = dict((f.name, f) for f in fields) 266 267 self.nested_types = nested_types 268 for nested_type in nested_types: 269 nested_type.containing_type = self 270 self.nested_types_by_name = dict((t.name, t) for t in nested_types) 271 272 self.enum_types = enum_types 273 for enum_type in self.enum_types: 274 enum_type.containing_type = self 275 self.enum_types_by_name = dict((t.name, t) for t in enum_types) 276 self.enum_values_by_name = dict( 277 (v.name, v) for t in enum_types for v in t.values) 278 279 self.extensions = extensions 280 for extension in self.extensions: 281 extension.extension_scope = self 282 self.extensions_by_name = dict((f.name, f) for f in extensions) 283 self.is_extendable = is_extendable 284 self.extension_ranges = extension_ranges 285 self.oneofs = oneofs if oneofs is not None else [] 286 self.oneofs_by_name = dict((o.name, o) for o in self.oneofs) 287 for oneof in self.oneofs: 288 oneof.containing_type = self 289 290 def EnumValueName(self, enum, value): 291 """Returns the string name of an enum value. 292 293 This is just a small helper method to simplify a common operation. 294 295 Args: 296 enum: string name of the Enum. 297 value: int, value of the enum. 298 299 Returns: 300 string name of the enum value. 301 302 Raises: 303 KeyError if either the Enum doesn't exist or the value is not a valid 304 value for the enum. 305 """ 306 return self.enum_types_by_name[enum].values_by_number[value].name 307 308 def CopyToProto(self, proto): 309 """Copies this to a descriptor_pb2.DescriptorProto. 310 311 Args: 312 proto: An empty descriptor_pb2.DescriptorProto. 313 """ 314 # This function is overriden to give a better doc comment. 315 super(Descriptor, self).CopyToProto(proto) 316 317 318# TODO(robinson): We should have aggressive checking here, 319# for example: 320# * If you specify a repeated field, you should not be allowed 321# to specify a default value. 322# * [Other examples here as needed]. 323# 324# TODO(robinson): for this and other *Descriptor classes, we 325# might also want to lock things down aggressively (e.g., 326# prevent clients from setting the attributes). Having 327# stronger invariants here in general will reduce the number 328# of runtime checks we must do in reflection.py... 329class FieldDescriptor(DescriptorBase): 330 331 """Descriptor for a single field in a .proto file. 332 333 A FieldDescriptor instance has the following attributes: 334 335 name: (str) Name of this field, exactly as it appears in .proto. 336 full_name: (str) Name of this field, including containing scope. This is 337 particularly relevant for extensions. 338 index: (int) Dense, 0-indexed index giving the order that this 339 field textually appears within its message in the .proto file. 340 number: (int) Tag number declared for this field in the .proto file. 341 342 type: (One of the TYPE_* constants below) Declared type. 343 cpp_type: (One of the CPPTYPE_* constants below) C++ type used to 344 represent this field. 345 346 label: (One of the LABEL_* constants below) Tells whether this 347 field is optional, required, or repeated. 348 has_default_value: (bool) True if this field has a default value defined, 349 otherwise false. 350 default_value: (Varies) Default value of this field. Only 351 meaningful for non-repeated scalar fields. Repeated fields 352 should always set this to [], and non-repeated composite 353 fields should always set this to None. 354 355 containing_type: (Descriptor) Descriptor of the protocol message 356 type that contains this field. Set by the Descriptor constructor 357 if we're passed into one. 358 Somewhat confusingly, for extension fields, this is the 359 descriptor of the EXTENDED message, not the descriptor 360 of the message containing this field. (See is_extension and 361 extension_scope below). 362 message_type: (Descriptor) If a composite field, a descriptor 363 of the message type contained in this field. Otherwise, this is None. 364 enum_type: (EnumDescriptor) If this field contains an enum, a 365 descriptor of that enum. Otherwise, this is None. 366 367 is_extension: True iff this describes an extension field. 368 extension_scope: (Descriptor) Only meaningful if is_extension is True. 369 Gives the message that immediately contains this extension field. 370 Will be None iff we're a top-level (file-level) extension field. 371 372 options: (descriptor_pb2.FieldOptions) Protocol message field options or 373 None to use default field options. 374 375 containing_oneof: (OneofDescriptor) If the field is a member of a oneof 376 union, contains its descriptor. Otherwise, None. 377 """ 378 379 # Must be consistent with C++ FieldDescriptor::Type enum in 380 # descriptor.h. 381 # 382 # TODO(robinson): Find a way to eliminate this repetition. 383 TYPE_DOUBLE = 1 384 TYPE_FLOAT = 2 385 TYPE_INT64 = 3 386 TYPE_UINT64 = 4 387 TYPE_INT32 = 5 388 TYPE_FIXED64 = 6 389 TYPE_FIXED32 = 7 390 TYPE_BOOL = 8 391 TYPE_STRING = 9 392 TYPE_GROUP = 10 393 TYPE_MESSAGE = 11 394 TYPE_BYTES = 12 395 TYPE_UINT32 = 13 396 TYPE_ENUM = 14 397 TYPE_SFIXED32 = 15 398 TYPE_SFIXED64 = 16 399 TYPE_SINT32 = 17 400 TYPE_SINT64 = 18 401 MAX_TYPE = 18 402 403 # Must be consistent with C++ FieldDescriptor::CppType enum in 404 # descriptor.h. 405 # 406 # TODO(robinson): Find a way to eliminate this repetition. 407 CPPTYPE_INT32 = 1 408 CPPTYPE_INT64 = 2 409 CPPTYPE_UINT32 = 3 410 CPPTYPE_UINT64 = 4 411 CPPTYPE_DOUBLE = 5 412 CPPTYPE_FLOAT = 6 413 CPPTYPE_BOOL = 7 414 CPPTYPE_ENUM = 8 415 CPPTYPE_STRING = 9 416 CPPTYPE_MESSAGE = 10 417 MAX_CPPTYPE = 10 418 419 _PYTHON_TO_CPP_PROTO_TYPE_MAP = { 420 TYPE_DOUBLE: CPPTYPE_DOUBLE, 421 TYPE_FLOAT: CPPTYPE_FLOAT, 422 TYPE_ENUM: CPPTYPE_ENUM, 423 TYPE_INT64: CPPTYPE_INT64, 424 TYPE_SINT64: CPPTYPE_INT64, 425 TYPE_SFIXED64: CPPTYPE_INT64, 426 TYPE_UINT64: CPPTYPE_UINT64, 427 TYPE_FIXED64: CPPTYPE_UINT64, 428 TYPE_INT32: CPPTYPE_INT32, 429 TYPE_SFIXED32: CPPTYPE_INT32, 430 TYPE_SINT32: CPPTYPE_INT32, 431 TYPE_UINT32: CPPTYPE_UINT32, 432 TYPE_FIXED32: CPPTYPE_UINT32, 433 TYPE_BYTES: CPPTYPE_STRING, 434 TYPE_STRING: CPPTYPE_STRING, 435 TYPE_BOOL: CPPTYPE_BOOL, 436 TYPE_MESSAGE: CPPTYPE_MESSAGE, 437 TYPE_GROUP: CPPTYPE_MESSAGE 438 } 439 440 # Must be consistent with C++ FieldDescriptor::Label enum in 441 # descriptor.h. 442 # 443 # TODO(robinson): Find a way to eliminate this repetition. 444 LABEL_OPTIONAL = 1 445 LABEL_REQUIRED = 2 446 LABEL_REPEATED = 3 447 MAX_LABEL = 3 448 449 # Must be consistent with C++ constants kMaxNumber, kFirstReservedNumber, 450 # and kLastReservedNumber in descriptor.h 451 MAX_FIELD_NUMBER = (1 << 29) - 1 452 FIRST_RESERVED_FIELD_NUMBER = 19000 453 LAST_RESERVED_FIELD_NUMBER = 19999 454 455 def __init__(self, name, full_name, index, number, type, cpp_type, label, 456 default_value, message_type, enum_type, containing_type, 457 is_extension, extension_scope, options=None, 458 has_default_value=True, containing_oneof=None): 459 """The arguments are as described in the description of FieldDescriptor 460 attributes above. 461 462 Note that containing_type may be None, and may be set later if necessary 463 (to deal with circular references between message types, for example). 464 Likewise for extension_scope. 465 """ 466 super(FieldDescriptor, self).__init__(options, 'FieldOptions') 467 self.name = name 468 self.full_name = full_name 469 self.index = index 470 self.number = number 471 self.type = type 472 self.cpp_type = cpp_type 473 self.label = label 474 self.has_default_value = has_default_value 475 self.default_value = default_value 476 self.containing_type = containing_type 477 self.message_type = message_type 478 self.enum_type = enum_type 479 self.is_extension = is_extension 480 self.extension_scope = extension_scope 481 self.containing_oneof = containing_oneof 482 if api_implementation.Type() == 'cpp': 483 if is_extension: 484 if api_implementation.Version() == 2: 485 # pylint: disable=protected-access 486 self._cdescriptor = ( 487 _message.Message._GetExtensionDescriptor(full_name)) 488 # pylint: enable=protected-access 489 else: 490 self._cdescriptor = cpp_message.GetExtensionDescriptor(full_name) 491 else: 492 if api_implementation.Version() == 2: 493 # pylint: disable=protected-access 494 self._cdescriptor = _message.Message._GetFieldDescriptor(full_name) 495 # pylint: enable=protected-access 496 else: 497 self._cdescriptor = cpp_message.GetFieldDescriptor(full_name) 498 else: 499 self._cdescriptor = None 500 501 @staticmethod 502 def ProtoTypeToCppProtoType(proto_type): 503 """Converts from a Python proto type to a C++ Proto Type. 504 505 The Python ProtocolBuffer classes specify both the 'Python' datatype and the 506 'C++' datatype - and they're not the same. This helper method should 507 translate from one to another. 508 509 Args: 510 proto_type: the Python proto type (descriptor.FieldDescriptor.TYPE_*) 511 Returns: 512 descriptor.FieldDescriptor.CPPTYPE_*, the C++ type. 513 Raises: 514 TypeTransformationError: when the Python proto type isn't known. 515 """ 516 try: 517 return FieldDescriptor._PYTHON_TO_CPP_PROTO_TYPE_MAP[proto_type] 518 except KeyError: 519 raise TypeTransformationError('Unknown proto_type: %s' % proto_type) 520 521 522class EnumDescriptor(_NestedDescriptorBase): 523 524 """Descriptor for an enum defined in a .proto file. 525 526 An EnumDescriptor instance has the following attributes: 527 528 name: (str) Name of the enum type. 529 full_name: (str) Full name of the type, including package name 530 and any enclosing type(s). 531 532 values: (list of EnumValueDescriptors) List of the values 533 in this enum. 534 values_by_name: (dict str -> EnumValueDescriptor) Same as |values|, 535 but indexed by the "name" field of each EnumValueDescriptor. 536 values_by_number: (dict int -> EnumValueDescriptor) Same as |values|, 537 but indexed by the "number" field of each EnumValueDescriptor. 538 containing_type: (Descriptor) Descriptor of the immediate containing 539 type of this enum, or None if this is an enum defined at the 540 top level in a .proto file. Set by Descriptor's constructor 541 if we're passed into one. 542 file: (FileDescriptor) Reference to file descriptor. 543 options: (descriptor_pb2.EnumOptions) Enum options message or 544 None to use default enum options. 545 """ 546 547 def __init__(self, name, full_name, filename, values, 548 containing_type=None, options=None, file=None, 549 serialized_start=None, serialized_end=None): 550 """Arguments are as described in the attribute description above. 551 552 Note that filename is an obsolete argument, that is not used anymore. 553 Please use file.name to access this as an attribute. 554 """ 555 super(EnumDescriptor, self).__init__( 556 options, 'EnumOptions', name, full_name, file, 557 containing_type, serialized_start=serialized_start, 558 serialized_end=serialized_end) 559 560 self.values = values 561 for value in self.values: 562 value.type = self 563 self.values_by_name = dict((v.name, v) for v in values) 564 self.values_by_number = dict((v.number, v) for v in values) 565 566 def CopyToProto(self, proto): 567 """Copies this to a descriptor_pb2.EnumDescriptorProto. 568 569 Args: 570 proto: An empty descriptor_pb2.EnumDescriptorProto. 571 """ 572 # This function is overriden to give a better doc comment. 573 super(EnumDescriptor, self).CopyToProto(proto) 574 575 576class EnumValueDescriptor(DescriptorBase): 577 578 """Descriptor for a single value within an enum. 579 580 name: (str) Name of this value. 581 index: (int) Dense, 0-indexed index giving the order that this 582 value appears textually within its enum in the .proto file. 583 number: (int) Actual number assigned to this enum value. 584 type: (EnumDescriptor) EnumDescriptor to which this value 585 belongs. Set by EnumDescriptor's constructor if we're 586 passed into one. 587 options: (descriptor_pb2.EnumValueOptions) Enum value options message or 588 None to use default enum value options options. 589 """ 590 591 def __init__(self, name, index, number, type=None, options=None): 592 """Arguments are as described in the attribute description above.""" 593 super(EnumValueDescriptor, self).__init__(options, 'EnumValueOptions') 594 self.name = name 595 self.index = index 596 self.number = number 597 self.type = type 598 599 600class OneofDescriptor(object): 601 """Descriptor for a oneof field. 602 603 name: (str) Name of the oneof field. 604 full_name: (str) Full name of the oneof field, including package name. 605 index: (int) 0-based index giving the order of the oneof field inside 606 its containing type. 607 containing_type: (Descriptor) Descriptor of the protocol message 608 type that contains this field. Set by the Descriptor constructor 609 if we're passed into one. 610 fields: (list of FieldDescriptor) The list of field descriptors this 611 oneof can contain. 612 """ 613 614 def __init__(self, name, full_name, index, containing_type, fields): 615 """Arguments are as described in the attribute description above.""" 616 self.name = name 617 self.full_name = full_name 618 self.index = index 619 self.containing_type = containing_type 620 self.fields = fields 621 622 623class ServiceDescriptor(_NestedDescriptorBase): 624 625 """Descriptor for a service. 626 627 name: (str) Name of the service. 628 full_name: (str) Full name of the service, including package name. 629 index: (int) 0-indexed index giving the order that this services 630 definition appears withing the .proto file. 631 methods: (list of MethodDescriptor) List of methods provided by this 632 service. 633 options: (descriptor_pb2.ServiceOptions) Service options message or 634 None to use default service options. 635 file: (FileDescriptor) Reference to file info. 636 """ 637 638 def __init__(self, name, full_name, index, methods, options=None, file=None, 639 serialized_start=None, serialized_end=None): 640 super(ServiceDescriptor, self).__init__( 641 options, 'ServiceOptions', name, full_name, file, 642 None, serialized_start=serialized_start, 643 serialized_end=serialized_end) 644 self.index = index 645 self.methods = methods 646 # Set the containing service for each method in this service. 647 for method in self.methods: 648 method.containing_service = self 649 650 def FindMethodByName(self, name): 651 """Searches for the specified method, and returns its descriptor.""" 652 for method in self.methods: 653 if name == method.name: 654 return method 655 return None 656 657 def CopyToProto(self, proto): 658 """Copies this to a descriptor_pb2.ServiceDescriptorProto. 659 660 Args: 661 proto: An empty descriptor_pb2.ServiceDescriptorProto. 662 """ 663 # This function is overriden to give a better doc comment. 664 super(ServiceDescriptor, self).CopyToProto(proto) 665 666 667class MethodDescriptor(DescriptorBase): 668 669 """Descriptor for a method in a service. 670 671 name: (str) Name of the method within the service. 672 full_name: (str) Full name of method. 673 index: (int) 0-indexed index of the method inside the service. 674 containing_service: (ServiceDescriptor) The service that contains this 675 method. 676 input_type: The descriptor of the message that this method accepts. 677 output_type: The descriptor of the message that this method returns. 678 options: (descriptor_pb2.MethodOptions) Method options message or 679 None to use default method options. 680 """ 681 682 def __init__(self, name, full_name, index, containing_service, 683 input_type, output_type, options=None): 684 """The arguments are as described in the description of MethodDescriptor 685 attributes above. 686 687 Note that containing_service may be None, and may be set later if necessary. 688 """ 689 super(MethodDescriptor, self).__init__(options, 'MethodOptions') 690 self.name = name 691 self.full_name = full_name 692 self.index = index 693 self.containing_service = containing_service 694 self.input_type = input_type 695 self.output_type = output_type 696 697 698class FileDescriptor(DescriptorBase): 699 """Descriptor for a file. Mimics the descriptor_pb2.FileDescriptorProto. 700 701 Note that enum_types_by_name, extensions_by_name, and dependencies 702 fields are only set by the message_factory module, and not by the 703 generated proto code. 704 705 name: name of file, relative to root of source tree. 706 package: name of the package 707 serialized_pb: (str) Byte string of serialized 708 descriptor_pb2.FileDescriptorProto. 709 dependencies: List of other FileDescriptors this FileDescriptor depends on. 710 message_types_by_name: Dict of message names of their descriptors. 711 enum_types_by_name: Dict of enum names and their descriptors. 712 extensions_by_name: Dict of extension names and their descriptors. 713 """ 714 715 def __init__(self, name, package, options=None, serialized_pb=None, 716 dependencies=None): 717 """Constructor.""" 718 super(FileDescriptor, self).__init__(options, 'FileOptions') 719 720 self.message_types_by_name = {} 721 self.name = name 722 self.package = package 723 self.serialized_pb = serialized_pb 724 725 self.enum_types_by_name = {} 726 self.extensions_by_name = {} 727 self.dependencies = (dependencies or []) 728 729 if (api_implementation.Type() == 'cpp' and 730 self.serialized_pb is not None): 731 if api_implementation.Version() == 2: 732 # pylint: disable=protected-access 733 _message.Message._BuildFile(self.serialized_pb) 734 # pylint: enable=protected-access 735 else: 736 cpp_message.BuildFile(self.serialized_pb) 737 738 def CopyToProto(self, proto): 739 """Copies this to a descriptor_pb2.FileDescriptorProto. 740 741 Args: 742 proto: An empty descriptor_pb2.FileDescriptorProto. 743 """ 744 proto.ParseFromString(self.serialized_pb) 745 746 747def _ParseOptions(message, string): 748 """Parses serialized options. 749 750 This helper function is used to parse serialized options in generated 751 proto2 files. It must not be used outside proto2. 752 """ 753 message.ParseFromString(string) 754 return message 755 756 757def MakeDescriptor(desc_proto, package='', build_file_if_cpp=True): 758 """Make a protobuf Descriptor given a DescriptorProto protobuf. 759 760 Handles nested descriptors. Note that this is limited to the scope of defining 761 a message inside of another message. Composite fields can currently only be 762 resolved if the message is defined in the same scope as the field. 763 764 Args: 765 desc_proto: The descriptor_pb2.DescriptorProto protobuf message. 766 package: Optional package name for the new message Descriptor (string). 767 build_file_if_cpp: Update the C++ descriptor pool if api matches. 768 Set to False on recursion, so no duplicates are created. 769 Returns: 770 A Descriptor for protobuf messages. 771 """ 772 if api_implementation.Type() == 'cpp' and build_file_if_cpp: 773 # The C++ implementation requires all descriptors to be backed by the same 774 # definition in the C++ descriptor pool. To do this, we build a 775 # FileDescriptorProto with the same definition as this descriptor and build 776 # it into the pool. 777 from google.protobuf import descriptor_pb2 778 file_descriptor_proto = descriptor_pb2.FileDescriptorProto() 779 file_descriptor_proto.message_type.add().MergeFrom(desc_proto) 780 781 # Generate a random name for this proto file to prevent conflicts with 782 # any imported ones. We need to specify a file name so BuildFile accepts 783 # our FileDescriptorProto, but it is not important what that file name 784 # is actually set to. 785 proto_name = str(uuid.uuid4()) 786 787 if package: 788 file_descriptor_proto.name = os.path.join(package.replace('.', '/'), 789 proto_name + '.proto') 790 file_descriptor_proto.package = package 791 else: 792 file_descriptor_proto.name = proto_name + '.proto' 793 794 if api_implementation.Version() == 2: 795 # pylint: disable=protected-access 796 _message.Message._BuildFile(file_descriptor_proto.SerializeToString()) 797 # pylint: enable=protected-access 798 else: 799 cpp_message.BuildFile(file_descriptor_proto.SerializeToString()) 800 801 full_message_name = [desc_proto.name] 802 if package: full_message_name.insert(0, package) 803 804 # Create Descriptors for enum types 805 enum_types = {} 806 for enum_proto in desc_proto.enum_type: 807 full_name = '.'.join(full_message_name + [enum_proto.name]) 808 enum_desc = EnumDescriptor( 809 enum_proto.name, full_name, None, [ 810 EnumValueDescriptor(enum_val.name, ii, enum_val.number) 811 for ii, enum_val in enumerate(enum_proto.value)]) 812 enum_types[full_name] = enum_desc 813 814 # Create Descriptors for nested types 815 nested_types = {} 816 for nested_proto in desc_proto.nested_type: 817 full_name = '.'.join(full_message_name + [nested_proto.name]) 818 # Nested types are just those defined inside of the message, not all types 819 # used by fields in the message, so no loops are possible here. 820 nested_desc = MakeDescriptor(nested_proto, 821 package='.'.join(full_message_name), 822 build_file_if_cpp=False) 823 nested_types[full_name] = nested_desc 824 825 fields = [] 826 for field_proto in desc_proto.field: 827 full_name = '.'.join(full_message_name + [field_proto.name]) 828 enum_desc = None 829 nested_desc = None 830 if field_proto.HasField('type_name'): 831 type_name = field_proto.type_name 832 full_type_name = '.'.join(full_message_name + 833 [type_name[type_name.rfind('.')+1:]]) 834 if full_type_name in nested_types: 835 nested_desc = nested_types[full_type_name] 836 elif full_type_name in enum_types: 837 enum_desc = enum_types[full_type_name] 838 # Else type_name references a non-local type, which isn't implemented 839 field = FieldDescriptor( 840 field_proto.name, full_name, field_proto.number - 1, 841 field_proto.number, field_proto.type, 842 FieldDescriptor.ProtoTypeToCppProtoType(field_proto.type), 843 field_proto.label, None, nested_desc, enum_desc, None, False, None, 844 has_default_value=False) 845 fields.append(field) 846 847 desc_name = '.'.join(full_message_name) 848 return Descriptor(desc_proto.name, desc_name, None, None, fields, 849 nested_types.values(), enum_types.values(), []) 850