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__(
291        cls,
292        name=None,
293        full_name=None,
294        filename=None,
295        containing_type=None,
296        fields=None,
297        nested_types=None,
298        enum_types=None,
299        extensions=None,
300        options=None,
301        serialized_options=None,
302        is_extendable=True,
303        extension_ranges=None,
304        oneofs=None,
305        file=None,  # pylint: disable=redefined-builtin
306        serialized_start=None,
307        serialized_end=None,
308        syntax=None,
309        create_key=None):
310      _message.Message._CheckCalledFromGeneratedFile()
311      return _message.default_pool.FindMessageTypeByName(full_name)
312
313  # NOTE(tmarek): The file argument redefining a builtin is nothing we can
314  # fix right now since we don't know how many clients already rely on the
315  # name of the argument.
316  def __init__(self, name, full_name, filename, containing_type, fields,
317               nested_types, enum_types, extensions, options=None,
318               serialized_options=None,
319               is_extendable=True, extension_ranges=None, oneofs=None,
320               file=None, serialized_start=None, serialized_end=None,  # pylint: disable=redefined-builtin
321               syntax=None, create_key=None):
322    """Arguments to __init__() are as described in the description
323    of Descriptor fields above.
324
325    Note that filename is an obsolete argument, that is not used anymore.
326    Please use file.name to access this as an attribute.
327    """
328    if create_key is not _internal_create_key:
329      _Deprecated('Descriptor')
330
331    super(Descriptor, self).__init__(
332        options, 'MessageOptions', name, full_name, file,
333        containing_type, serialized_start=serialized_start,
334        serialized_end=serialized_end, serialized_options=serialized_options)
335
336    # We have fields in addition to fields_by_name and fields_by_number,
337    # so that:
338    #   1. Clients can index fields by "order in which they're listed."
339    #   2. Clients can easily iterate over all fields with the terse
340    #      syntax: for f in descriptor.fields: ...
341    self.fields = fields
342    for field in self.fields:
343      field.containing_type = self
344    self.fields_by_number = dict((f.number, f) for f in fields)
345    self.fields_by_name = dict((f.name, f) for f in fields)
346    self._fields_by_camelcase_name = None
347
348    self.nested_types = nested_types
349    for nested_type in nested_types:
350      nested_type.containing_type = self
351    self.nested_types_by_name = dict((t.name, t) for t in nested_types)
352
353    self.enum_types = enum_types
354    for enum_type in self.enum_types:
355      enum_type.containing_type = self
356    self.enum_types_by_name = dict((t.name, t) for t in enum_types)
357    self.enum_values_by_name = dict(
358        (v.name, v) for t in enum_types for v in t.values)
359
360    self.extensions = extensions
361    for extension in self.extensions:
362      extension.extension_scope = self
363    self.extensions_by_name = dict((f.name, f) for f in extensions)
364    self.is_extendable = is_extendable
365    self.extension_ranges = extension_ranges
366    self.oneofs = oneofs if oneofs is not None else []
367    self.oneofs_by_name = dict((o.name, o) for o in self.oneofs)
368    for oneof in self.oneofs:
369      oneof.containing_type = self
370    self.syntax = syntax or "proto2"
371
372  @property
373  def fields_by_camelcase_name(self):
374    """Same FieldDescriptor objects as in :attr:`fields`, but indexed by
375    :attr:`FieldDescriptor.camelcase_name`.
376    """
377    if self._fields_by_camelcase_name is None:
378      self._fields_by_camelcase_name = dict(
379          (f.camelcase_name, f) for f in self.fields)
380    return self._fields_by_camelcase_name
381
382  def EnumValueName(self, enum, value):
383    """Returns the string name of an enum value.
384
385    This is just a small helper method to simplify a common operation.
386
387    Args:
388      enum: string name of the Enum.
389      value: int, value of the enum.
390
391    Returns:
392      string name of the enum value.
393
394    Raises:
395      KeyError if either the Enum doesn't exist or the value is not a valid
396        value for the enum.
397    """
398    return self.enum_types_by_name[enum].values_by_number[value].name
399
400  def CopyToProto(self, proto):
401    """Copies this to a descriptor_pb2.DescriptorProto.
402
403    Args:
404      proto: An empty descriptor_pb2.DescriptorProto.
405    """
406    # This function is overridden to give a better doc comment.
407    super(Descriptor, self).CopyToProto(proto)
408
409
410# TODO(robinson): We should have aggressive checking here,
411# for example:
412#   * If you specify a repeated field, you should not be allowed
413#     to specify a default value.
414#   * [Other examples here as needed].
415#
416# TODO(robinson): for this and other *Descriptor classes, we
417# might also want to lock things down aggressively (e.g.,
418# prevent clients from setting the attributes).  Having
419# stronger invariants here in general will reduce the number
420# of runtime checks we must do in reflection.py...
421class FieldDescriptor(DescriptorBase):
422
423  """Descriptor for a single field in a .proto file.
424
425  Attributes:
426    name (str): Name of this field, exactly as it appears in .proto.
427    full_name (str): Name of this field, including containing scope.  This is
428      particularly relevant for extensions.
429    index (int): Dense, 0-indexed index giving the order that this
430      field textually appears within its message in the .proto file.
431    number (int): Tag number declared for this field in the .proto file.
432
433    type (int): (One of the TYPE_* constants below) Declared type.
434    cpp_type (int): (One of the CPPTYPE_* constants below) C++ type used to
435      represent this field.
436
437    label (int): (One of the LABEL_* constants below) Tells whether this
438      field is optional, required, or repeated.
439    has_default_value (bool): True if this field has a default value defined,
440      otherwise false.
441    default_value (Varies): Default value of this field.  Only
442      meaningful for non-repeated scalar fields.  Repeated fields
443      should always set this to [], and non-repeated composite
444      fields should always set this to None.
445
446    containing_type (Descriptor): Descriptor of the protocol message
447      type that contains this field.  Set by the Descriptor constructor
448      if we're passed into one.
449      Somewhat confusingly, for extension fields, this is the
450      descriptor of the EXTENDED message, not the descriptor
451      of the message containing this field.  (See is_extension and
452      extension_scope below).
453    message_type (Descriptor): If a composite field, a descriptor
454      of the message type contained in this field.  Otherwise, this is None.
455    enum_type (EnumDescriptor): If this field contains an enum, a
456      descriptor of that enum.  Otherwise, this is None.
457
458    is_extension: True iff this describes an extension field.
459    extension_scope (Descriptor): Only meaningful if is_extension is True.
460      Gives the message that immediately contains this extension field.
461      Will be None iff we're a top-level (file-level) extension field.
462
463    options (descriptor_pb2.FieldOptions): Protocol message field options or
464      None to use default field options.
465
466    containing_oneof (OneofDescriptor): If the field is a member of a oneof
467      union, contains its descriptor. Otherwise, None.
468
469    file (FileDescriptor): Reference to file descriptor.
470  """
471
472  # Must be consistent with C++ FieldDescriptor::Type enum in
473  # descriptor.h.
474  #
475  # TODO(robinson): Find a way to eliminate this repetition.
476  TYPE_DOUBLE         = 1
477  TYPE_FLOAT          = 2
478  TYPE_INT64          = 3
479  TYPE_UINT64         = 4
480  TYPE_INT32          = 5
481  TYPE_FIXED64        = 6
482  TYPE_FIXED32        = 7
483  TYPE_BOOL           = 8
484  TYPE_STRING         = 9
485  TYPE_GROUP          = 10
486  TYPE_MESSAGE        = 11
487  TYPE_BYTES          = 12
488  TYPE_UINT32         = 13
489  TYPE_ENUM           = 14
490  TYPE_SFIXED32       = 15
491  TYPE_SFIXED64       = 16
492  TYPE_SINT32         = 17
493  TYPE_SINT64         = 18
494  MAX_TYPE            = 18
495
496  # Must be consistent with C++ FieldDescriptor::CppType enum in
497  # descriptor.h.
498  #
499  # TODO(robinson): Find a way to eliminate this repetition.
500  CPPTYPE_INT32       = 1
501  CPPTYPE_INT64       = 2
502  CPPTYPE_UINT32      = 3
503  CPPTYPE_UINT64      = 4
504  CPPTYPE_DOUBLE      = 5
505  CPPTYPE_FLOAT       = 6
506  CPPTYPE_BOOL        = 7
507  CPPTYPE_ENUM        = 8
508  CPPTYPE_STRING      = 9
509  CPPTYPE_MESSAGE     = 10
510  MAX_CPPTYPE         = 10
511
512  _PYTHON_TO_CPP_PROTO_TYPE_MAP = {
513      TYPE_DOUBLE: CPPTYPE_DOUBLE,
514      TYPE_FLOAT: CPPTYPE_FLOAT,
515      TYPE_ENUM: CPPTYPE_ENUM,
516      TYPE_INT64: CPPTYPE_INT64,
517      TYPE_SINT64: CPPTYPE_INT64,
518      TYPE_SFIXED64: CPPTYPE_INT64,
519      TYPE_UINT64: CPPTYPE_UINT64,
520      TYPE_FIXED64: CPPTYPE_UINT64,
521      TYPE_INT32: CPPTYPE_INT32,
522      TYPE_SFIXED32: CPPTYPE_INT32,
523      TYPE_SINT32: CPPTYPE_INT32,
524      TYPE_UINT32: CPPTYPE_UINT32,
525      TYPE_FIXED32: CPPTYPE_UINT32,
526      TYPE_BYTES: CPPTYPE_STRING,
527      TYPE_STRING: CPPTYPE_STRING,
528      TYPE_BOOL: CPPTYPE_BOOL,
529      TYPE_MESSAGE: CPPTYPE_MESSAGE,
530      TYPE_GROUP: CPPTYPE_MESSAGE
531      }
532
533  # Must be consistent with C++ FieldDescriptor::Label enum in
534  # descriptor.h.
535  #
536  # TODO(robinson): Find a way to eliminate this repetition.
537  LABEL_OPTIONAL      = 1
538  LABEL_REQUIRED      = 2
539  LABEL_REPEATED      = 3
540  MAX_LABEL           = 3
541
542  # Must be consistent with C++ constants kMaxNumber, kFirstReservedNumber,
543  # and kLastReservedNumber in descriptor.h
544  MAX_FIELD_NUMBER = (1 << 29) - 1
545  FIRST_RESERVED_FIELD_NUMBER = 19000
546  LAST_RESERVED_FIELD_NUMBER = 19999
547
548  if _USE_C_DESCRIPTORS:
549    _C_DESCRIPTOR_CLASS = _message.FieldDescriptor
550
551    def __new__(cls, name, full_name, index, number, type, cpp_type, label,
552                default_value, message_type, enum_type, containing_type,
553                is_extension, extension_scope, options=None,
554                serialized_options=None,
555                has_default_value=True, containing_oneof=None, json_name=None,
556                file=None, create_key=None):  # pylint: disable=redefined-builtin
557      _message.Message._CheckCalledFromGeneratedFile()
558      if is_extension:
559        return _message.default_pool.FindExtensionByName(full_name)
560      else:
561        return _message.default_pool.FindFieldByName(full_name)
562
563  def __init__(self, name, full_name, index, number, type, cpp_type, label,
564               default_value, message_type, enum_type, containing_type,
565               is_extension, extension_scope, options=None,
566               serialized_options=None,
567               has_default_value=True, containing_oneof=None, json_name=None,
568               file=None, create_key=None):  # pylint: disable=redefined-builtin
569    """The arguments are as described in the description of FieldDescriptor
570    attributes above.
571
572    Note that containing_type may be None, and may be set later if necessary
573    (to deal with circular references between message types, for example).
574    Likewise for extension_scope.
575    """
576    if create_key is not _internal_create_key:
577      _Deprecated('FieldDescriptor')
578
579    super(FieldDescriptor, self).__init__(
580        options, serialized_options, 'FieldOptions')
581    self.name = name
582    self.full_name = full_name
583    self.file = file
584    self._camelcase_name = None
585    if json_name is None:
586      self.json_name = _ToJsonName(name)
587    else:
588      self.json_name = json_name
589    self.index = index
590    self.number = number
591    self.type = type
592    self.cpp_type = cpp_type
593    self.label = label
594    self.has_default_value = has_default_value
595    self.default_value = default_value
596    self.containing_type = containing_type
597    self.message_type = message_type
598    self.enum_type = enum_type
599    self.is_extension = is_extension
600    self.extension_scope = extension_scope
601    self.containing_oneof = containing_oneof
602    if api_implementation.Type() == 'cpp':
603      if is_extension:
604        self._cdescriptor = _message.default_pool.FindExtensionByName(full_name)
605      else:
606        self._cdescriptor = _message.default_pool.FindFieldByName(full_name)
607    else:
608      self._cdescriptor = None
609
610  @property
611  def camelcase_name(self):
612    """Camelcase name of this field.
613
614    Returns:
615      str: the name in CamelCase.
616    """
617    if self._camelcase_name is None:
618      self._camelcase_name = _ToCamelCase(self.name)
619    return self._camelcase_name
620
621  @staticmethod
622  def ProtoTypeToCppProtoType(proto_type):
623    """Converts from a Python proto type to a C++ Proto Type.
624
625    The Python ProtocolBuffer classes specify both the 'Python' datatype and the
626    'C++' datatype - and they're not the same. This helper method should
627    translate from one to another.
628
629    Args:
630      proto_type: the Python proto type (descriptor.FieldDescriptor.TYPE_*)
631    Returns:
632      int: descriptor.FieldDescriptor.CPPTYPE_*, the C++ type.
633    Raises:
634      TypeTransformationError: when the Python proto type isn't known.
635    """
636    try:
637      return FieldDescriptor._PYTHON_TO_CPP_PROTO_TYPE_MAP[proto_type]
638    except KeyError:
639      raise TypeTransformationError('Unknown proto_type: %s' % proto_type)
640
641
642class EnumDescriptor(_NestedDescriptorBase):
643
644  """Descriptor for an enum defined in a .proto file.
645
646  Attributes:
647    name (str): Name of the enum type.
648    full_name (str): Full name of the type, including package name
649      and any enclosing type(s).
650
651    values (list[EnumValueDescriptors]): List of the values
652      in this enum.
653    values_by_name (dict(str, EnumValueDescriptor)): Same as :attr:`values`,
654      but indexed by the "name" field of each EnumValueDescriptor.
655    values_by_number (dict(int, EnumValueDescriptor)): Same as :attr:`values`,
656      but indexed by the "number" field of each EnumValueDescriptor.
657    containing_type (Descriptor): Descriptor of the immediate containing
658      type of this enum, or None if this is an enum defined at the
659      top level in a .proto file.  Set by Descriptor's constructor
660      if we're passed into one.
661    file (FileDescriptor): Reference to file descriptor.
662    options (descriptor_pb2.EnumOptions): Enum options message or
663      None to use default enum options.
664  """
665
666  if _USE_C_DESCRIPTORS:
667    _C_DESCRIPTOR_CLASS = _message.EnumDescriptor
668
669    def __new__(cls, name, full_name, filename, values,
670                containing_type=None, options=None,
671                serialized_options=None, file=None,  # pylint: disable=redefined-builtin
672                serialized_start=None, serialized_end=None, create_key=None):
673      _message.Message._CheckCalledFromGeneratedFile()
674      return _message.default_pool.FindEnumTypeByName(full_name)
675
676  def __init__(self, name, full_name, filename, values,
677               containing_type=None, options=None,
678               serialized_options=None, file=None,  # pylint: disable=redefined-builtin
679               serialized_start=None, serialized_end=None, create_key=None):
680    """Arguments are as described in the attribute description above.
681
682    Note that filename is an obsolete argument, that is not used anymore.
683    Please use file.name to access this as an attribute.
684    """
685    if create_key is not _internal_create_key:
686      _Deprecated('EnumDescriptor')
687
688    super(EnumDescriptor, self).__init__(
689        options, 'EnumOptions', name, full_name, file,
690        containing_type, serialized_start=serialized_start,
691        serialized_end=serialized_end, serialized_options=serialized_options)
692
693    self.values = values
694    for value in self.values:
695      value.type = self
696    self.values_by_name = dict((v.name, v) for v in values)
697    # Values are reversed to ensure that the first alias is retained.
698    self.values_by_number = dict((v.number, v) for v in reversed(values))
699
700  def CopyToProto(self, proto):
701    """Copies this to a descriptor_pb2.EnumDescriptorProto.
702
703    Args:
704      proto (descriptor_pb2.EnumDescriptorProto): An empty descriptor proto.
705    """
706    # This function is overridden to give a better doc comment.
707    super(EnumDescriptor, self).CopyToProto(proto)
708
709
710class EnumValueDescriptor(DescriptorBase):
711
712  """Descriptor for a single value within an enum.
713
714  Attributes:
715    name (str): Name of this value.
716    index (int): Dense, 0-indexed index giving the order that this
717      value appears textually within its enum in the .proto file.
718    number (int): Actual number assigned to this enum value.
719    type (EnumDescriptor): :class:`EnumDescriptor` to which this value
720      belongs.  Set by :class:`EnumDescriptor`'s constructor if we're
721      passed into one.
722    options (descriptor_pb2.EnumValueOptions): Enum value options message or
723      None to use default enum value options options.
724  """
725
726  if _USE_C_DESCRIPTORS:
727    _C_DESCRIPTOR_CLASS = _message.EnumValueDescriptor
728
729    def __new__(cls, name, index, number,
730                type=None,  # pylint: disable=redefined-builtin
731                options=None, serialized_options=None, create_key=None):
732      _message.Message._CheckCalledFromGeneratedFile()
733      # There is no way we can build a complete EnumValueDescriptor with the
734      # given parameters (the name of the Enum is not known, for example).
735      # Fortunately generated files just pass it to the EnumDescriptor()
736      # constructor, which will ignore it, so returning None is good enough.
737      return None
738
739  def __init__(self, name, index, number,
740               type=None,  # pylint: disable=redefined-builtin
741               options=None, serialized_options=None, create_key=None):
742    """Arguments are as described in the attribute description above."""
743    if create_key is not _internal_create_key:
744      _Deprecated('EnumValueDescriptor')
745
746    super(EnumValueDescriptor, self).__init__(
747        options, serialized_options, 'EnumValueOptions')
748    self.name = name
749    self.index = index
750    self.number = number
751    self.type = type
752
753
754class OneofDescriptor(DescriptorBase):
755  """Descriptor for a oneof field.
756
757  Attributes:
758    name (str): Name of the oneof field.
759    full_name (str): Full name of the oneof field, including package name.
760    index (int): 0-based index giving the order of the oneof field inside
761      its containing type.
762    containing_type (Descriptor): :class:`Descriptor` of the protocol message
763      type that contains this field.  Set by the :class:`Descriptor` constructor
764      if we're passed into one.
765    fields (list[FieldDescriptor]): The list of field descriptors this
766      oneof can contain.
767  """
768
769  if _USE_C_DESCRIPTORS:
770    _C_DESCRIPTOR_CLASS = _message.OneofDescriptor
771
772    def __new__(
773        cls, name, full_name, index, containing_type, fields, options=None,
774        serialized_options=None, create_key=None):
775      _message.Message._CheckCalledFromGeneratedFile()
776      return _message.default_pool.FindOneofByName(full_name)
777
778  def __init__(
779      self, name, full_name, index, containing_type, fields, options=None,
780      serialized_options=None, create_key=None):
781    """Arguments are as described in the attribute description above."""
782    if create_key is not _internal_create_key:
783      _Deprecated('OneofDescriptor')
784
785    super(OneofDescriptor, self).__init__(
786        options, serialized_options, 'OneofOptions')
787    self.name = name
788    self.full_name = full_name
789    self.index = index
790    self.containing_type = containing_type
791    self.fields = fields
792
793
794class ServiceDescriptor(_NestedDescriptorBase):
795
796  """Descriptor for a service.
797
798  Attributes:
799    name (str): Name of the service.
800    full_name (str): Full name of the service, including package name.
801    index (int): 0-indexed index giving the order that this services
802      definition appears within the .proto file.
803    methods (list[MethodDescriptor]): List of methods provided by this
804      service.
805    methods_by_name (dict(str, MethodDescriptor)): Same
806      :class:`MethodDescriptor` objects as in :attr:`methods_by_name`, but
807      indexed by "name" attribute in each :class:`MethodDescriptor`.
808    options (descriptor_pb2.ServiceOptions): Service options message or
809      None to use default service options.
810    file (FileDescriptor): Reference to file info.
811  """
812
813  if _USE_C_DESCRIPTORS:
814    _C_DESCRIPTOR_CLASS = _message.ServiceDescriptor
815
816    def __new__(
817        cls,
818        name=None,
819        full_name=None,
820        index=None,
821        methods=None,
822        options=None,
823        serialized_options=None,
824        file=None,  # pylint: disable=redefined-builtin
825        serialized_start=None,
826        serialized_end=None,
827        create_key=None):
828      _message.Message._CheckCalledFromGeneratedFile()  # pylint: disable=protected-access
829      return _message.default_pool.FindServiceByName(full_name)
830
831  def __init__(self, name, full_name, index, methods, options=None,
832               serialized_options=None, file=None,  # pylint: disable=redefined-builtin
833               serialized_start=None, serialized_end=None, create_key=None):
834    if create_key is not _internal_create_key:
835      _Deprecated('ServiceDescriptor')
836
837    super(ServiceDescriptor, self).__init__(
838        options, 'ServiceOptions', name, full_name, file,
839        None, serialized_start=serialized_start,
840        serialized_end=serialized_end, serialized_options=serialized_options)
841    self.index = index
842    self.methods = methods
843    self.methods_by_name = dict((m.name, m) for m in methods)
844    # Set the containing service for each method in this service.
845    for method in self.methods:
846      method.containing_service = self
847
848  def FindMethodByName(self, name):
849    """Searches for the specified method, and returns its descriptor.
850
851    Args:
852      name (str): Name of the method.
853    Returns:
854      MethodDescriptor or None: the descriptor for the requested method, if
855      found.
856    """
857    return self.methods_by_name.get(name, None)
858
859  def CopyToProto(self, proto):
860    """Copies this to a descriptor_pb2.ServiceDescriptorProto.
861
862    Args:
863      proto (descriptor_pb2.ServiceDescriptorProto): An empty descriptor proto.
864    """
865    # This function is overridden to give a better doc comment.
866    super(ServiceDescriptor, self).CopyToProto(proto)
867
868
869class MethodDescriptor(DescriptorBase):
870
871  """Descriptor for a method in a service.
872
873  Attributes:
874    name (str): Name of the method within the service.
875    full_name (str): Full name of method.
876    index (int): 0-indexed index of the method inside the service.
877    containing_service (ServiceDescriptor): The service that contains this
878      method.
879    input_type (Descriptor): The descriptor of the message that this method
880      accepts.
881    output_type (Descriptor): The descriptor of the message that this method
882      returns.
883    options (descriptor_pb2.MethodOptions or None): Method options message, or
884      None to use default method options.
885  """
886
887  if _USE_C_DESCRIPTORS:
888    _C_DESCRIPTOR_CLASS = _message.MethodDescriptor
889
890    def __new__(cls, name, full_name, index, containing_service,
891                input_type, output_type, options=None, serialized_options=None,
892                create_key=None):
893      _message.Message._CheckCalledFromGeneratedFile()  # pylint: disable=protected-access
894      return _message.default_pool.FindMethodByName(full_name)
895
896  def __init__(self, name, full_name, index, containing_service,
897               input_type, output_type, options=None, serialized_options=None,
898               create_key=None):
899    """The arguments are as described in the description of MethodDescriptor
900    attributes above.
901
902    Note that containing_service may be None, and may be set later if necessary.
903    """
904    if create_key is not _internal_create_key:
905      _Deprecated('MethodDescriptor')
906
907    super(MethodDescriptor, self).__init__(
908        options, serialized_options, 'MethodOptions')
909    self.name = name
910    self.full_name = full_name
911    self.index = index
912    self.containing_service = containing_service
913    self.input_type = input_type
914    self.output_type = output_type
915
916
917class FileDescriptor(DescriptorBase):
918  """Descriptor for a file. Mimics the descriptor_pb2.FileDescriptorProto.
919
920  Note that :attr:`enum_types_by_name`, :attr:`extensions_by_name`, and
921  :attr:`dependencies` fields are only set by the
922  :py:mod:`google.protobuf.message_factory` module, and not by the generated
923  proto code.
924
925  Attributes:
926    name (str): Name of file, relative to root of source tree.
927    package (str): Name of the package
928    syntax (str): string indicating syntax of the file (can be "proto2" or
929      "proto3")
930    serialized_pb (bytes): Byte string of serialized
931      :class:`descriptor_pb2.FileDescriptorProto`.
932    dependencies (list[FileDescriptor]): List of other :class:`FileDescriptor`
933      objects this :class:`FileDescriptor` depends on.
934    public_dependencies (list[FileDescriptor]): A subset of
935      :attr:`dependencies`, which were declared as "public".
936    message_types_by_name (dict(str, Descriptor)): Mapping from message names
937      to their :class:`Desctiptor`.
938    enum_types_by_name (dict(str, EnumDescriptor)): Mapping from enum names to
939      their :class:`EnumDescriptor`.
940    extensions_by_name (dict(str, FieldDescriptor)): Mapping from extension
941      names declared at file scope to their :class:`FieldDescriptor`.
942    services_by_name (dict(str, ServiceDescriptor)): Mapping from services'
943      names to their :class:`ServiceDescriptor`.
944    pool (DescriptorPool): The pool this descriptor belongs to.  When not
945      passed to the constructor, the global default pool is used.
946  """
947
948  if _USE_C_DESCRIPTORS:
949    _C_DESCRIPTOR_CLASS = _message.FileDescriptor
950
951    def __new__(cls, name, package, options=None,
952                serialized_options=None, serialized_pb=None,
953                dependencies=None, public_dependencies=None,
954                syntax=None, pool=None, create_key=None):
955      # FileDescriptor() is called from various places, not only from generated
956      # files, to register dynamic proto files and messages.
957      # pylint: disable=g-explicit-bool-comparison
958      if serialized_pb == b'':
959        # Cpp generated code must be linked in if serialized_pb is ''
960        try:
961          return _message.default_pool.FindFileByName(name)
962        except KeyError:
963          raise RuntimeError('Please link in cpp generated lib for %s' % (name))
964      elif serialized_pb:
965        return _message.default_pool.AddSerializedFile(serialized_pb)
966      else:
967        return super(FileDescriptor, cls).__new__(cls)
968
969  def __init__(self, name, package, options=None,
970               serialized_options=None, serialized_pb=None,
971               dependencies=None, public_dependencies=None,
972               syntax=None, pool=None, create_key=None):
973    """Constructor."""
974    if create_key is not _internal_create_key:
975      _Deprecated('FileDescriptor')
976
977    super(FileDescriptor, self).__init__(
978        options, serialized_options, 'FileOptions')
979
980    if pool is None:
981      from google.protobuf import descriptor_pool
982      pool = descriptor_pool.Default()
983    self.pool = pool
984    self.message_types_by_name = {}
985    self.name = name
986    self.package = package
987    self.syntax = syntax or "proto2"
988    self.serialized_pb = serialized_pb
989
990    self.enum_types_by_name = {}
991    self.extensions_by_name = {}
992    self.services_by_name = {}
993    self.dependencies = (dependencies or [])
994    self.public_dependencies = (public_dependencies or [])
995
996  def CopyToProto(self, proto):
997    """Copies this to a descriptor_pb2.FileDescriptorProto.
998
999    Args:
1000      proto: An empty descriptor_pb2.FileDescriptorProto.
1001    """
1002    proto.ParseFromString(self.serialized_pb)
1003
1004
1005def _ParseOptions(message, string):
1006  """Parses serialized options.
1007
1008  This helper function is used to parse serialized options in generated
1009  proto2 files. It must not be used outside proto2.
1010  """
1011  message.ParseFromString(string)
1012  return message
1013
1014
1015def _ToCamelCase(name):
1016  """Converts name to camel-case and returns it."""
1017  capitalize_next = False
1018  result = []
1019
1020  for c in name:
1021    if c == '_':
1022      if result:
1023        capitalize_next = True
1024    elif capitalize_next:
1025      result.append(c.upper())
1026      capitalize_next = False
1027    else:
1028      result += c
1029
1030  # Lower-case the first letter.
1031  if result and result[0].isupper():
1032    result[0] = result[0].lower()
1033  return ''.join(result)
1034
1035
1036def _OptionsOrNone(descriptor_proto):
1037  """Returns the value of the field `options`, or None if it is not set."""
1038  if descriptor_proto.HasField('options'):
1039    return descriptor_proto.options
1040  else:
1041    return None
1042
1043
1044def _ToJsonName(name):
1045  """Converts name to Json name and returns it."""
1046  capitalize_next = False
1047  result = []
1048
1049  for c in name:
1050    if c == '_':
1051      capitalize_next = True
1052    elif capitalize_next:
1053      result.append(c.upper())
1054      capitalize_next = False
1055    else:
1056      result += c
1057
1058  return ''.join(result)
1059
1060
1061def MakeDescriptor(desc_proto, package='', build_file_if_cpp=True,
1062                   syntax=None):
1063  """Make a protobuf Descriptor given a DescriptorProto protobuf.
1064
1065  Handles nested descriptors. Note that this is limited to the scope of defining
1066  a message inside of another message. Composite fields can currently only be
1067  resolved if the message is defined in the same scope as the field.
1068
1069  Args:
1070    desc_proto: The descriptor_pb2.DescriptorProto protobuf message.
1071    package: Optional package name for the new message Descriptor (string).
1072    build_file_if_cpp: Update the C++ descriptor pool if api matches.
1073                       Set to False on recursion, so no duplicates are created.
1074    syntax: The syntax/semantics that should be used.  Set to "proto3" to get
1075            proto3 field presence semantics.
1076  Returns:
1077    A Descriptor for protobuf messages.
1078  """
1079  if api_implementation.Type() == 'cpp' and build_file_if_cpp:
1080    # The C++ implementation requires all descriptors to be backed by the same
1081    # definition in the C++ descriptor pool. To do this, we build a
1082    # FileDescriptorProto with the same definition as this descriptor and build
1083    # it into the pool.
1084    from google.protobuf import descriptor_pb2
1085    file_descriptor_proto = descriptor_pb2.FileDescriptorProto()
1086    file_descriptor_proto.message_type.add().MergeFrom(desc_proto)
1087
1088    # Generate a random name for this proto file to prevent conflicts with any
1089    # imported ones. We need to specify a file name so the descriptor pool
1090    # accepts our FileDescriptorProto, but it is not important what that file
1091    # name is actually set to.
1092    proto_name = binascii.hexlify(os.urandom(16)).decode('ascii')
1093
1094    if package:
1095      file_descriptor_proto.name = os.path.join(package.replace('.', '/'),
1096                                                proto_name + '.proto')
1097      file_descriptor_proto.package = package
1098    else:
1099      file_descriptor_proto.name = proto_name + '.proto'
1100
1101    _message.default_pool.Add(file_descriptor_proto)
1102    result = _message.default_pool.FindFileByName(file_descriptor_proto.name)
1103
1104    if _USE_C_DESCRIPTORS:
1105      return result.message_types_by_name[desc_proto.name]
1106
1107  full_message_name = [desc_proto.name]
1108  if package: full_message_name.insert(0, package)
1109
1110  # Create Descriptors for enum types
1111  enum_types = {}
1112  for enum_proto in desc_proto.enum_type:
1113    full_name = '.'.join(full_message_name + [enum_proto.name])
1114    enum_desc = EnumDescriptor(
1115        enum_proto.name, full_name, None, [
1116            EnumValueDescriptor(enum_val.name, ii, enum_val.number,
1117                                create_key=_internal_create_key)
1118            for ii, enum_val in enumerate(enum_proto.value)],
1119        create_key=_internal_create_key)
1120    enum_types[full_name] = enum_desc
1121
1122  # Create Descriptors for nested types
1123  nested_types = {}
1124  for nested_proto in desc_proto.nested_type:
1125    full_name = '.'.join(full_message_name + [nested_proto.name])
1126    # Nested types are just those defined inside of the message, not all types
1127    # used by fields in the message, so no loops are possible here.
1128    nested_desc = MakeDescriptor(nested_proto,
1129                                 package='.'.join(full_message_name),
1130                                 build_file_if_cpp=False,
1131                                 syntax=syntax)
1132    nested_types[full_name] = nested_desc
1133
1134  fields = []
1135  for field_proto in desc_proto.field:
1136    full_name = '.'.join(full_message_name + [field_proto.name])
1137    enum_desc = None
1138    nested_desc = None
1139    if field_proto.json_name:
1140      json_name = field_proto.json_name
1141    else:
1142      json_name = None
1143    if field_proto.HasField('type_name'):
1144      type_name = field_proto.type_name
1145      full_type_name = '.'.join(full_message_name +
1146                                [type_name[type_name.rfind('.')+1:]])
1147      if full_type_name in nested_types:
1148        nested_desc = nested_types[full_type_name]
1149      elif full_type_name in enum_types:
1150        enum_desc = enum_types[full_type_name]
1151      # Else type_name references a non-local type, which isn't implemented
1152    field = FieldDescriptor(
1153        field_proto.name, full_name, field_proto.number - 1,
1154        field_proto.number, field_proto.type,
1155        FieldDescriptor.ProtoTypeToCppProtoType(field_proto.type),
1156        field_proto.label, None, nested_desc, enum_desc, None, False, None,
1157        options=_OptionsOrNone(field_proto), has_default_value=False,
1158        json_name=json_name, create_key=_internal_create_key)
1159    fields.append(field)
1160
1161  desc_name = '.'.join(full_message_name)
1162  return Descriptor(desc_proto.name, desc_name, None, None, fields,
1163                    list(nested_types.values()), list(enum_types.values()), [],
1164                    options=_OptionsOrNone(desc_proto),
1165                    create_key=_internal_create_key)
1166