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