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