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