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