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