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