Home | History | Annotate | Download | only in protobuf
      1 # Protocol Buffers - Google's data interchange format
      2 # Copyright 2008 Google Inc.  All rights reserved.
      3 # http://code.google.com/p/protobuf/
      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
     32 file, in types that make this information accessible in Python.
     33 """
     34 
     35 __author__ = 'robinson (at] google.com (Will Robinson)'
     36 
     37 
     38 from google.protobuf.internal import api_implementation
     39 
     40 
     41 if api_implementation.Type() == 'cpp':
     42   if api_implementation.Version() == 2:
     43     from google.protobuf.internal.cpp import _message
     44   else:
     45     from google.protobuf.internal import cpp_message
     46 
     47 
     48 class Error(Exception):
     49   """Base error for this module."""
     50 
     51 
     52 class TypeTransformationError(Error):
     53   """Error transforming between python proto type and corresponding C++ type."""
     54 
     55 
     56 class DescriptorBase(object):
     57 
     58   """Descriptors base class.
     59 
     60   This class is the base of all descriptor classes. It provides common options
     61   related functionaility.
     62 
     63   Attributes:
     64     has_options:  True if the descriptor has non-default options.  Usually it
     65         is not necessary to read this -- just call GetOptions() which will
     66         happily return the default instance.  However, it's sometimes useful
     67         for efficiency, and also useful inside the protobuf implementation to
     68         avoid some bootstrapping issues.
     69   """
     70 
     71   def __init__(self, options, options_class_name):
     72     """Initialize the descriptor given its options message and the name of the
     73     class of the options message. The name of the class is required in case
     74     the options message is None and has to be created.
     75     """
     76     self._options = options
     77     self._options_class_name = options_class_name
     78 
     79     # Does this descriptor have non-default options?
     80     self.has_options = options is not None
     81 
     82   def _SetOptions(self, options, options_class_name):
     83     """Sets the descriptor's options
     84 
     85     This function is used in generated proto2 files to update descriptor
     86     options. It must not be used outside proto2.
     87     """
     88     self._options = options
     89     self._options_class_name = options_class_name
     90 
     91     # Does this descriptor have non-default options?
     92     self.has_options = options is not None
     93 
     94   def GetOptions(self):
     95     """Retrieves descriptor options.
     96 
     97     This method returns the options set or creates the default options for the
     98     descriptor.
     99     """
    100     if self._options:
    101       return self._options
    102     from google.protobuf import descriptor_pb2
    103     try:
    104       options_class = getattr(descriptor_pb2, self._options_class_name)
    105     except AttributeError:
    106       raise RuntimeError('Unknown options class name %s!' %
    107                          (self._options_class_name))
    108     self._options = options_class()
    109     return self._options
    110 
    111 
    112 class _NestedDescriptorBase(DescriptorBase):
    113   """Common class for descriptors that can be nested."""
    114 
    115   def __init__(self, options, options_class_name, name, full_name,
    116                file, containing_type, serialized_start=None,
    117                serialized_end=None):
    118     """Constructor.
    119 
    120     Args:
    121       options: Protocol message options or None
    122         to use default message options.
    123       options_class_name: (str) The class name of the above options.
    124 
    125       name: (str) Name of this protocol message type.
    126       full_name: (str) Fully-qualified name of this protocol message type,
    127         which will include protocol "package" name and the name of any
    128         enclosing types.
    129       file: (FileDescriptor) Reference to file info.
    130       containing_type: if provided, this is a nested descriptor, with this
    131         descriptor as parent, otherwise None.
    132       serialized_start: The start index (inclusive) in block in the
    133         file.serialized_pb that describes this descriptor.
    134       serialized_end: The end index (exclusive) in block in the
    135         file.serialized_pb that describes this descriptor.
    136     """
    137     super(_NestedDescriptorBase, self).__init__(
    138         options, options_class_name)
    139 
    140     self.name = name
    141     # TODO(falk): Add function to calculate full_name instead of having it in
    142     #             memory?
    143     self.full_name = full_name
    144     self.file = file
    145     self.containing_type = containing_type
    146 
    147     self._serialized_start = serialized_start
    148     self._serialized_end = serialized_end
    149 
    150   def GetTopLevelContainingType(self):
    151     """Returns the root if this is a nested type, or itself if its the root."""
    152     desc = self
    153     while desc.containing_type is not None:
    154       desc = desc.containing_type
    155     return desc
    156 
    157   def CopyToProto(self, proto):
    158     """Copies this to the matching proto in descriptor_pb2.
    159 
    160     Args:
    161       proto: An empty proto instance from descriptor_pb2.
    162 
    163     Raises:
    164       Error: If self couldnt be serialized, due to to few constructor arguments.
    165     """
    166     if (self.file is not None and
    167         self._serialized_start is not None and
    168         self._serialized_end is not None):
    169       proto.ParseFromString(self.file.serialized_pb[
    170           self._serialized_start:self._serialized_end])
    171     else:
    172       raise Error('Descriptor does not contain serialization.')
    173 
    174 
    175 class Descriptor(_NestedDescriptorBase):
    176 
    177   """Descriptor for a protocol message type.
    178 
    179   A Descriptor instance has the following attributes:
    180 
    181     name: (str) Name of this protocol message type.
    182     full_name: (str) Fully-qualified name of this protocol message type,
    183       which will include protocol "package" name and the name of any
    184       enclosing types.
    185 
    186     containing_type: (Descriptor) Reference to the descriptor of the
    187       type containing us, or None if this is top-level.
    188 
    189     fields: (list of FieldDescriptors) Field descriptors for all
    190       fields in this type.
    191     fields_by_number: (dict int -> FieldDescriptor) Same FieldDescriptor
    192       objects as in |fields|, but indexed by "number" attribute in each
    193       FieldDescriptor.
    194     fields_by_name: (dict str -> FieldDescriptor) Same FieldDescriptor
    195       objects as in |fields|, but indexed by "name" attribute in each
    196       FieldDescriptor.
    197 
    198     nested_types: (list of Descriptors) Descriptor references
    199       for all protocol message types nested within this one.
    200     nested_types_by_name: (dict str -> Descriptor) Same Descriptor
    201       objects as in |nested_types|, but indexed by "name" attribute
    202       in each Descriptor.
    203 
    204     enum_types: (list of EnumDescriptors) EnumDescriptor references
    205       for all enums contained within this type.
    206     enum_types_by_name: (dict str ->EnumDescriptor) Same EnumDescriptor
    207       objects as in |enum_types|, but indexed by "name" attribute
    208       in each EnumDescriptor.
    209     enum_values_by_name: (dict str -> EnumValueDescriptor) Dict mapping
    210       from enum value name to EnumValueDescriptor for that value.
    211 
    212     extensions: (list of FieldDescriptor) All extensions defined directly
    213       within this message type (NOT within a nested type).
    214     extensions_by_name: (dict, string -> FieldDescriptor) Same FieldDescriptor
    215       objects as |extensions|, but indexed by "name" attribute of each
    216       FieldDescriptor.
    217 
    218     is_extendable:  Does this type define any extension ranges?
    219 
    220     options: (descriptor_pb2.MessageOptions) Protocol message options or None
    221       to use default message options.
    222 
    223     file: (FileDescriptor) Reference to file descriptor.
    224   """
    225 
    226   def __init__(self, name, full_name, filename, containing_type, fields,
    227                nested_types, enum_types, extensions, options=None,
    228                is_extendable=True, extension_ranges=None, file=None,
    229                serialized_start=None, serialized_end=None):
    230     """Arguments to __init__() are as described in the description
    231     of Descriptor fields above.
    232 
    233     Note that filename is an obsolete argument, that is not used anymore.
    234     Please use file.name to access this as an attribute.
    235     """
    236     super(Descriptor, self).__init__(
    237         options, 'MessageOptions', name, full_name, file,
    238         containing_type, serialized_start=serialized_start,
    239         serialized_end=serialized_start)
    240 
    241     # We have fields in addition to fields_by_name and fields_by_number,
    242     # so that:
    243     #   1. Clients can index fields by "order in which they're listed."
    244     #   2. Clients can easily iterate over all fields with the terse
    245     #      syntax: for f in descriptor.fields: ...
    246     self.fields = fields
    247     for field in self.fields:
    248       field.containing_type = self
    249     self.fields_by_number = dict((f.number, f) for f in fields)
    250     self.fields_by_name = dict((f.name, f) for f in fields)
    251 
    252     self.nested_types = nested_types
    253     self.nested_types_by_name = dict((t.name, t) for t in nested_types)
    254 
    255     self.enum_types = enum_types
    256     for enum_type in self.enum_types:
    257       enum_type.containing_type = self
    258     self.enum_types_by_name = dict((t.name, t) for t in enum_types)
    259     self.enum_values_by_name = dict(
    260         (v.name, v) for t in enum_types for v in t.values)
    261 
    262     self.extensions = extensions
    263     for extension in self.extensions:
    264       extension.extension_scope = self
    265     self.extensions_by_name = dict((f.name, f) for f in extensions)
    266     self.is_extendable = is_extendable
    267     self.extension_ranges = extension_ranges
    268 
    269     self._serialized_start = serialized_start
    270     self._serialized_end = serialized_end
    271 
    272   def EnumValueName(self, enum, value):
    273     """Returns the string name of an enum value.
    274 
    275     This is just a small helper method to simplify a common operation.
    276 
    277     Args:
    278       enum: string name of the Enum.
    279       value: int, value of the enum.
    280 
    281     Returns:
    282       string name of the enum value.
    283 
    284     Raises:
    285       KeyError if either the Enum doesn't exist or the value is not a valid
    286         value for the enum.
    287     """
    288     return self.enum_types_by_name[enum].values_by_number[value].name
    289 
    290   def CopyToProto(self, proto):
    291     """Copies this to a descriptor_pb2.DescriptorProto.
    292 
    293     Args:
    294       proto: An empty descriptor_pb2.DescriptorProto.
    295     """
    296     # This function is overriden to give a better doc comment.
    297     super(Descriptor, self).CopyToProto(proto)
    298 
    299 
    300 # TODO(robinson): We should have aggressive checking here,
    301 # for example:
    302 #   * If you specify a repeated field, you should not be allowed
    303 #     to specify a default value.
    304 #   * [Other examples here as needed].
    305 #
    306 # TODO(robinson): for this and other *Descriptor classes, we
    307 # might also want to lock things down aggressively (e.g.,
    308 # prevent clients from setting the attributes).  Having
    309 # stronger invariants here in general will reduce the number
    310 # of runtime checks we must do in reflection.py...
    311 class FieldDescriptor(DescriptorBase):
    312 
    313   """Descriptor for a single field in a .proto file.
    314 
    315   A FieldDescriptor instance has the following attributes:
    316 
    317     name: (str) Name of this field, exactly as it appears in .proto.
    318     full_name: (str) Name of this field, including containing scope.  This is
    319       particularly relevant for extensions.
    320     index: (int) Dense, 0-indexed index giving the order that this
    321       field textually appears within its message in the .proto file.
    322     number: (int) Tag number declared for this field in the .proto file.
    323 
    324     type: (One of the TYPE_* constants below) Declared type.
    325     cpp_type: (One of the CPPTYPE_* constants below) C++ type used to
    326       represent this field.
    327 
    328     label: (One of the LABEL_* constants below) Tells whether this
    329       field is optional, required, or repeated.
    330     has_default_value: (bool) True if this field has a default value defined,
    331       otherwise false.
    332     default_value: (Varies) Default value of this field.  Only
    333       meaningful for non-repeated scalar fields.  Repeated fields
    334       should always set this to [], and non-repeated composite
    335       fields should always set this to None.
    336 
    337     containing_type: (Descriptor) Descriptor of the protocol message
    338       type that contains this field.  Set by the Descriptor constructor
    339       if we're passed into one.
    340       Somewhat confusingly, for extension fields, this is the
    341       descriptor of the EXTENDED message, not the descriptor
    342       of the message containing this field.  (See is_extension and
    343       extension_scope below).
    344     message_type: (Descriptor) If a composite field, a descriptor
    345       of the message type contained in this field.  Otherwise, this is None.
    346     enum_type: (EnumDescriptor) If this field contains an enum, a
    347       descriptor of that enum.  Otherwise, this is None.
    348 
    349     is_extension: True iff this describes an extension field.
    350     extension_scope: (Descriptor) Only meaningful if is_extension is True.
    351       Gives the message that immediately contains this extension field.
    352       Will be None iff we're a top-level (file-level) extension field.
    353 
    354     options: (descriptor_pb2.FieldOptions) Protocol message field options or
    355       None to use default field options.
    356   """
    357 
    358   # Must be consistent with C++ FieldDescriptor::Type enum in
    359   # descriptor.h.
    360   #
    361   # TODO(robinson): Find a way to eliminate this repetition.
    362   TYPE_DOUBLE         = 1
    363   TYPE_FLOAT          = 2
    364   TYPE_INT64          = 3
    365   TYPE_UINT64         = 4
    366   TYPE_INT32          = 5
    367   TYPE_FIXED64        = 6
    368   TYPE_FIXED32        = 7
    369   TYPE_BOOL           = 8
    370   TYPE_STRING         = 9
    371   TYPE_GROUP          = 10
    372   TYPE_MESSAGE        = 11
    373   TYPE_BYTES          = 12
    374   TYPE_UINT32         = 13
    375   TYPE_ENUM           = 14
    376   TYPE_SFIXED32       = 15
    377   TYPE_SFIXED64       = 16
    378   TYPE_SINT32         = 17
    379   TYPE_SINT64         = 18
    380   MAX_TYPE            = 18
    381 
    382   # Must be consistent with C++ FieldDescriptor::CppType enum in
    383   # descriptor.h.
    384   #
    385   # TODO(robinson): Find a way to eliminate this repetition.
    386   CPPTYPE_INT32       = 1
    387   CPPTYPE_INT64       = 2
    388   CPPTYPE_UINT32      = 3
    389   CPPTYPE_UINT64      = 4
    390   CPPTYPE_DOUBLE      = 5
    391   CPPTYPE_FLOAT       = 6
    392   CPPTYPE_BOOL        = 7
    393   CPPTYPE_ENUM        = 8
    394   CPPTYPE_STRING      = 9
    395   CPPTYPE_MESSAGE     = 10
    396   MAX_CPPTYPE         = 10
    397 
    398   _PYTHON_TO_CPP_PROTO_TYPE_MAP = {
    399       TYPE_DOUBLE: CPPTYPE_DOUBLE,
    400       TYPE_FLOAT: CPPTYPE_FLOAT,
    401       TYPE_ENUM: CPPTYPE_ENUM,
    402       TYPE_INT64: CPPTYPE_INT64,
    403       TYPE_SINT64: CPPTYPE_INT64,
    404       TYPE_SFIXED64: CPPTYPE_INT64,
    405       TYPE_UINT64: CPPTYPE_UINT64,
    406       TYPE_FIXED64: CPPTYPE_UINT64,
    407       TYPE_INT32: CPPTYPE_INT32,
    408       TYPE_SFIXED32: CPPTYPE_INT32,
    409       TYPE_SINT32: CPPTYPE_INT32,
    410       TYPE_UINT32: CPPTYPE_UINT32,
    411       TYPE_FIXED32: CPPTYPE_UINT32,
    412       TYPE_BYTES: CPPTYPE_STRING,
    413       TYPE_STRING: CPPTYPE_STRING,
    414       TYPE_BOOL: CPPTYPE_BOOL,
    415       TYPE_MESSAGE: CPPTYPE_MESSAGE,
    416       TYPE_GROUP: CPPTYPE_MESSAGE
    417       }
    418 
    419   # Must be consistent with C++ FieldDescriptor::Label enum in
    420   # descriptor.h.
    421   #
    422   # TODO(robinson): Find a way to eliminate this repetition.
    423   LABEL_OPTIONAL      = 1
    424   LABEL_REQUIRED      = 2
    425   LABEL_REPEATED      = 3
    426   MAX_LABEL           = 3
    427 
    428   def __init__(self, name, full_name, index, number, type, cpp_type, label,
    429                default_value, message_type, enum_type, containing_type,
    430                is_extension, extension_scope, options=None,
    431                has_default_value=True):
    432     """The arguments are as described in the description of FieldDescriptor
    433     attributes above.
    434 
    435     Note that containing_type may be None, and may be set later if necessary
    436     (to deal with circular references between message types, for example).
    437     Likewise for extension_scope.
    438     """
    439     super(FieldDescriptor, self).__init__(options, 'FieldOptions')
    440     self.name = name
    441     self.full_name = full_name
    442     self.index = index
    443     self.number = number
    444     self.type = type
    445     self.cpp_type = cpp_type
    446     self.label = label
    447     self.has_default_value = has_default_value
    448     self.default_value = default_value
    449     self.containing_type = containing_type
    450     self.message_type = message_type
    451     self.enum_type = enum_type
    452     self.is_extension = is_extension
    453     self.extension_scope = extension_scope
    454     if api_implementation.Type() == 'cpp':
    455       if is_extension:
    456         if api_implementation.Version() == 2:
    457           self._cdescriptor = _message.GetExtensionDescriptor(full_name)
    458         else:
    459           self._cdescriptor = cpp_message.GetExtensionDescriptor(full_name)
    460       else:
    461         if api_implementation.Version() == 2:
    462           self._cdescriptor = _message.GetFieldDescriptor(full_name)
    463         else:
    464           self._cdescriptor = cpp_message.GetFieldDescriptor(full_name)
    465     else:
    466       self._cdescriptor = None
    467 
    468   @staticmethod
    469   def ProtoTypeToCppProtoType(proto_type):
    470     """Converts from a Python proto type to a C++ Proto Type.
    471 
    472     The Python ProtocolBuffer classes specify both the 'Python' datatype and the
    473     'C++' datatype - and they're not the same. This helper method should
    474     translate from one to another.
    475 
    476     Args:
    477       proto_type: the Python proto type (descriptor.FieldDescriptor.TYPE_*)
    478     Returns:
    479       descriptor.FieldDescriptor.CPPTYPE_*, the C++ type.
    480     Raises:
    481       TypeTransformationError: when the Python proto type isn't known.
    482     """
    483     try:
    484       return FieldDescriptor._PYTHON_TO_CPP_PROTO_TYPE_MAP[proto_type]
    485     except KeyError:
    486       raise TypeTransformationError('Unknown proto_type: %s' % proto_type)
    487 
    488 
    489 class EnumDescriptor(_NestedDescriptorBase):
    490 
    491   """Descriptor for an enum defined in a .proto file.
    492 
    493   An EnumDescriptor instance has the following attributes:
    494 
    495     name: (str) Name of the enum type.
    496     full_name: (str) Full name of the type, including package name
    497       and any enclosing type(s).
    498 
    499     values: (list of EnumValueDescriptors) List of the values
    500       in this enum.
    501     values_by_name: (dict str -> EnumValueDescriptor) Same as |values|,
    502       but indexed by the "name" field of each EnumValueDescriptor.
    503     values_by_number: (dict int -> EnumValueDescriptor) Same as |values|,
    504       but indexed by the "number" field of each EnumValueDescriptor.
    505     containing_type: (Descriptor) Descriptor of the immediate containing
    506       type of this enum, or None if this is an enum defined at the
    507       top level in a .proto file.  Set by Descriptor's constructor
    508       if we're passed into one.
    509     file: (FileDescriptor) Reference to file descriptor.
    510     options: (descriptor_pb2.EnumOptions) Enum options message or
    511       None to use default enum options.
    512   """
    513 
    514   def __init__(self, name, full_name, filename, values,
    515                containing_type=None, options=None, file=None,
    516                serialized_start=None, serialized_end=None):
    517     """Arguments are as described in the attribute description above.
    518 
    519     Note that filename is an obsolete argument, that is not used anymore.
    520     Please use file.name to access this as an attribute.
    521     """
    522     super(EnumDescriptor, self).__init__(
    523         options, 'EnumOptions', name, full_name, file,
    524         containing_type, serialized_start=serialized_start,
    525         serialized_end=serialized_start)
    526 
    527     self.values = values
    528     for value in self.values:
    529       value.type = self
    530     self.values_by_name = dict((v.name, v) for v in values)
    531     self.values_by_number = dict((v.number, v) for v in values)
    532 
    533     self._serialized_start = serialized_start
    534     self._serialized_end = serialized_end
    535 
    536   def CopyToProto(self, proto):
    537     """Copies this to a descriptor_pb2.EnumDescriptorProto.
    538 
    539     Args:
    540       proto: An empty descriptor_pb2.EnumDescriptorProto.
    541     """
    542     # This function is overriden to give a better doc comment.
    543     super(EnumDescriptor, self).CopyToProto(proto)
    544 
    545 
    546 class EnumValueDescriptor(DescriptorBase):
    547 
    548   """Descriptor for a single value within an enum.
    549 
    550     name: (str) Name of this value.
    551     index: (int) Dense, 0-indexed index giving the order that this
    552       value appears textually within its enum in the .proto file.
    553     number: (int) Actual number assigned to this enum value.
    554     type: (EnumDescriptor) EnumDescriptor to which this value
    555       belongs.  Set by EnumDescriptor's constructor if we're
    556       passed into one.
    557     options: (descriptor_pb2.EnumValueOptions) Enum value options message or
    558       None to use default enum value options options.
    559   """
    560 
    561   def __init__(self, name, index, number, type=None, options=None):
    562     """Arguments are as described in the attribute description above."""
    563     super(EnumValueDescriptor, self).__init__(options, 'EnumValueOptions')
    564     self.name = name
    565     self.index = index
    566     self.number = number
    567     self.type = type
    568 
    569 
    570 class ServiceDescriptor(_NestedDescriptorBase):
    571 
    572   """Descriptor for a service.
    573 
    574     name: (str) Name of the service.
    575     full_name: (str) Full name of the service, including package name.
    576     index: (int) 0-indexed index giving the order that this services
    577       definition appears withing the .proto file.
    578     methods: (list of MethodDescriptor) List of methods provided by this
    579       service.
    580     options: (descriptor_pb2.ServiceOptions) Service options message or
    581       None to use default service options.
    582     file: (FileDescriptor) Reference to file info.
    583   """
    584 
    585   def __init__(self, name, full_name, index, methods, options=None, file=None,
    586                serialized_start=None, serialized_end=None):
    587     super(ServiceDescriptor, self).__init__(
    588         options, 'ServiceOptions', name, full_name, file,
    589         None, serialized_start=serialized_start,
    590         serialized_end=serialized_end)
    591     self.index = index
    592     self.methods = methods
    593     # Set the containing service for each method in this service.
    594     for method in self.methods:
    595       method.containing_service = self
    596 
    597   def FindMethodByName(self, name):
    598     """Searches for the specified method, and returns its descriptor."""
    599     for method in self.methods:
    600       if name == method.name:
    601         return method
    602     return None
    603 
    604   def CopyToProto(self, proto):
    605     """Copies this to a descriptor_pb2.ServiceDescriptorProto.
    606 
    607     Args:
    608       proto: An empty descriptor_pb2.ServiceDescriptorProto.
    609     """
    610     # This function is overriden to give a better doc comment.
    611     super(ServiceDescriptor, self).CopyToProto(proto)
    612 
    613 
    614 class MethodDescriptor(DescriptorBase):
    615 
    616   """Descriptor for a method in a service.
    617 
    618   name: (str) Name of the method within the service.
    619   full_name: (str) Full name of method.
    620   index: (int) 0-indexed index of the method inside the service.
    621   containing_service: (ServiceDescriptor) The service that contains this
    622     method.
    623   input_type: The descriptor of the message that this method accepts.
    624   output_type: The descriptor of the message that this method returns.
    625   options: (descriptor_pb2.MethodOptions) Method options message or
    626     None to use default method options.
    627   """
    628 
    629   def __init__(self, name, full_name, index, containing_service,
    630                input_type, output_type, options=None):
    631     """The arguments are as described in the description of MethodDescriptor
    632     attributes above.
    633 
    634     Note that containing_service may be None, and may be set later if necessary.
    635     """
    636     super(MethodDescriptor, self).__init__(options, 'MethodOptions')
    637     self.name = name
    638     self.full_name = full_name
    639     self.index = index
    640     self.containing_service = containing_service
    641     self.input_type = input_type
    642     self.output_type = output_type
    643 
    644 
    645 class FileDescriptor(DescriptorBase):
    646   """Descriptor for a file. Mimics the descriptor_pb2.FileDescriptorProto.
    647 
    648   name: name of file, relative to root of source tree.
    649   package: name of the package
    650   serialized_pb: (str) Byte string of serialized
    651     descriptor_pb2.FileDescriptorProto.
    652   """
    653 
    654   def __init__(self, name, package, options=None, serialized_pb=None):
    655     """Constructor."""
    656     super(FileDescriptor, self).__init__(options, 'FileOptions')
    657 
    658     self.message_types_by_name = {}
    659     self.name = name
    660     self.package = package
    661     self.serialized_pb = serialized_pb
    662     if (api_implementation.Type() == 'cpp' and
    663         self.serialized_pb is not None):
    664       if api_implementation.Version() == 2:
    665         _message.BuildFile(self.serialized_pb)
    666       else:
    667         cpp_message.BuildFile(self.serialized_pb)
    668 
    669   def CopyToProto(self, proto):
    670     """Copies this to a descriptor_pb2.FileDescriptorProto.
    671 
    672     Args:
    673       proto: An empty descriptor_pb2.FileDescriptorProto.
    674     """
    675     proto.ParseFromString(self.serialized_pb)
    676 
    677 
    678 def _ParseOptions(message, string):
    679   """Parses serialized options.
    680 
    681   This helper function is used to parse serialized options in generated
    682   proto2 files. It must not be used outside proto2.
    683   """
    684   message.ParseFromString(string)
    685   return message
    686 
    687 
    688 def MakeDescriptor(desc_proto, package=''):
    689   """Make a protobuf Descriptor given a DescriptorProto protobuf.
    690 
    691   Args:
    692     desc_proto: The descriptor_pb2.DescriptorProto protobuf message.
    693     package: Optional package name for the new message Descriptor (string).
    694 
    695   Returns:
    696     A Descriptor for protobuf messages.
    697   """
    698   full_message_name = [desc_proto.name]
    699   if package: full_message_name.insert(0, package)
    700   fields = []
    701   for field_proto in desc_proto.field:
    702     full_name = '.'.join(full_message_name + [field_proto.name])
    703     field = FieldDescriptor(
    704         field_proto.name, full_name, field_proto.number - 1,
    705         field_proto.number, field_proto.type,
    706         FieldDescriptor.ProtoTypeToCppProtoType(field_proto.type),
    707         field_proto.label, None, None, None, None, False, None,
    708         has_default_value=False)
    709     fields.append(field)
    710 
    711   desc_name = '.'.join(full_message_name)
    712   return Descriptor(desc_proto.name, desc_name, None, None, fields,
    713                     [], [], [])
    714