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