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