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