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