• 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 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,
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,
273               syntax=None):  # pylint:disable=redefined-builtin
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 overriden 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 overriden 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(object):
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__(cls, name, full_name, index, containing_type, fields):
686      _message.Message._CheckCalledFromGeneratedFile()
687      return _message.default_pool.FindOneofByName(full_name)
688
689  def __init__(self, name, full_name, index, containing_type, fields):
690    """Arguments are as described in the attribute description above."""
691    self.name = name
692    self.full_name = full_name
693    self.index = index
694    self.containing_type = containing_type
695    self.fields = fields
696
697
698class ServiceDescriptor(_NestedDescriptorBase):
699
700  """Descriptor for a service.
701
702    name: (str) Name of the service.
703    full_name: (str) Full name of the service, including package name.
704    index: (int) 0-indexed index giving the order that this services
705      definition appears withing the .proto file.
706    methods: (list of MethodDescriptor) List of methods provided by this
707      service.
708    options: (descriptor_pb2.ServiceOptions) Service options message or
709      None to use default service options.
710    file: (FileDescriptor) Reference to file info.
711  """
712
713  def __init__(self, name, full_name, index, methods, options=None, file=None,
714               serialized_start=None, serialized_end=None):
715    super(ServiceDescriptor, self).__init__(
716        options, 'ServiceOptions', name, full_name, file,
717        None, serialized_start=serialized_start,
718        serialized_end=serialized_end)
719    self.index = index
720    self.methods = methods
721    # Set the containing service for each method in this service.
722    for method in self.methods:
723      method.containing_service = self
724
725  def FindMethodByName(self, name):
726    """Searches for the specified method, and returns its descriptor."""
727    for method in self.methods:
728      if name == method.name:
729        return method
730    return None
731
732  def CopyToProto(self, proto):
733    """Copies this to a descriptor_pb2.ServiceDescriptorProto.
734
735    Args:
736      proto: An empty descriptor_pb2.ServiceDescriptorProto.
737    """
738    # This function is overriden to give a better doc comment.
739    super(ServiceDescriptor, self).CopyToProto(proto)
740
741
742class MethodDescriptor(DescriptorBase):
743
744  """Descriptor for a method in a service.
745
746  name: (str) Name of the method within the service.
747  full_name: (str) Full name of method.
748  index: (int) 0-indexed index of the method inside the service.
749  containing_service: (ServiceDescriptor) The service that contains this
750    method.
751  input_type: The descriptor of the message that this method accepts.
752  output_type: The descriptor of the message that this method returns.
753  options: (descriptor_pb2.MethodOptions) Method options message or
754    None to use default method options.
755  """
756
757  def __init__(self, name, full_name, index, containing_service,
758               input_type, output_type, options=None):
759    """The arguments are as described in the description of MethodDescriptor
760    attributes above.
761
762    Note that containing_service may be None, and may be set later if necessary.
763    """
764    super(MethodDescriptor, self).__init__(options, 'MethodOptions')
765    self.name = name
766    self.full_name = full_name
767    self.index = index
768    self.containing_service = containing_service
769    self.input_type = input_type
770    self.output_type = output_type
771
772
773class FileDescriptor(DescriptorBase):
774  """Descriptor for a file. Mimics the descriptor_pb2.FileDescriptorProto.
775
776  Note that enum_types_by_name, extensions_by_name, and dependencies
777  fields are only set by the message_factory module, and not by the
778  generated proto code.
779
780  name: name of file, relative to root of source tree.
781  package: name of the package
782  syntax: string indicating syntax of the file (can be "proto2" or "proto3")
783  serialized_pb: (str) Byte string of serialized
784    descriptor_pb2.FileDescriptorProto.
785  dependencies: List of other FileDescriptors this FileDescriptor depends on.
786  public_dependencies: A list of FileDescriptors, subset of the dependencies
787    above, which were declared as "public".
788  message_types_by_name: Dict of message names of their descriptors.
789  enum_types_by_name: Dict of enum names and their descriptors.
790  extensions_by_name: Dict of extension names and their descriptors.
791  pool: the DescriptorPool this descriptor belongs to.  When not passed to the
792    constructor, the global default pool is used.
793  """
794
795  if _USE_C_DESCRIPTORS:
796    _C_DESCRIPTOR_CLASS = _message.FileDescriptor
797
798    def __new__(cls, name, package, options=None, serialized_pb=None,
799                dependencies=None, public_dependencies=None,
800                syntax=None, pool=None):
801      # FileDescriptor() is called from various places, not only from generated
802      # files, to register dynamic proto files and messages.
803      if serialized_pb:
804        # TODO(amauryfa): use the pool passed as argument. This will work only
805        # for C++-implemented DescriptorPools.
806        return _message.default_pool.AddSerializedFile(serialized_pb)
807      else:
808        return super(FileDescriptor, cls).__new__(cls)
809
810  def __init__(self, name, package, options=None, serialized_pb=None,
811               dependencies=None, public_dependencies=None,
812               syntax=None, pool=None):
813    """Constructor."""
814    super(FileDescriptor, self).__init__(options, 'FileOptions')
815
816    if pool is None:
817      from google.protobuf import descriptor_pool
818      pool = descriptor_pool.Default()
819    self.pool = pool
820    self.message_types_by_name = {}
821    self.name = name
822    self.package = package
823    self.syntax = syntax or "proto2"
824    self.serialized_pb = serialized_pb
825
826    self.enum_types_by_name = {}
827    self.extensions_by_name = {}
828    self.dependencies = (dependencies or [])
829    self.public_dependencies = (public_dependencies or [])
830
831    if (api_implementation.Type() == 'cpp' and
832        self.serialized_pb is not None):
833      _message.default_pool.AddSerializedFile(self.serialized_pb)
834
835  def CopyToProto(self, proto):
836    """Copies this to a descriptor_pb2.FileDescriptorProto.
837
838    Args:
839      proto: An empty descriptor_pb2.FileDescriptorProto.
840    """
841    proto.ParseFromString(self.serialized_pb)
842
843
844def _ParseOptions(message, string):
845  """Parses serialized options.
846
847  This helper function is used to parse serialized options in generated
848  proto2 files. It must not be used outside proto2.
849  """
850  message.ParseFromString(string)
851  return message
852
853
854def _ToCamelCase(name):
855  """Converts name to camel-case and returns it."""
856  capitalize_next = False
857  result = []
858
859  for c in name:
860    if c == '_':
861      if result:
862        capitalize_next = True
863    elif capitalize_next:
864      result.append(c.upper())
865      capitalize_next = False
866    else:
867      result += c
868
869  # Lower-case the first letter.
870  if result and result[0].isupper():
871    result[0] = result[0].lower()
872  return ''.join(result)
873
874
875def MakeDescriptor(desc_proto, package='', build_file_if_cpp=True,
876                   syntax=None):
877  """Make a protobuf Descriptor given a DescriptorProto protobuf.
878
879  Handles nested descriptors. Note that this is limited to the scope of defining
880  a message inside of another message. Composite fields can currently only be
881  resolved if the message is defined in the same scope as the field.
882
883  Args:
884    desc_proto: The descriptor_pb2.DescriptorProto protobuf message.
885    package: Optional package name for the new message Descriptor (string).
886    build_file_if_cpp: Update the C++ descriptor pool if api matches.
887                       Set to False on recursion, so no duplicates are created.
888    syntax: The syntax/semantics that should be used.  Set to "proto3" to get
889            proto3 field presence semantics.
890  Returns:
891    A Descriptor for protobuf messages.
892  """
893  if api_implementation.Type() == 'cpp' and build_file_if_cpp:
894    # The C++ implementation requires all descriptors to be backed by the same
895    # definition in the C++ descriptor pool. To do this, we build a
896    # FileDescriptorProto with the same definition as this descriptor and build
897    # it into the pool.
898    from google.protobuf import descriptor_pb2
899    file_descriptor_proto = descriptor_pb2.FileDescriptorProto()
900    file_descriptor_proto.message_type.add().MergeFrom(desc_proto)
901
902    # Generate a random name for this proto file to prevent conflicts with any
903    # imported ones. We need to specify a file name so the descriptor pool
904    # accepts our FileDescriptorProto, but it is not important what that file
905    # name is actually set to.
906    proto_name = str(uuid.uuid4())
907
908    if package:
909      file_descriptor_proto.name = os.path.join(package.replace('.', '/'),
910                                                proto_name + '.proto')
911      file_descriptor_proto.package = package
912    else:
913      file_descriptor_proto.name = proto_name + '.proto'
914
915    _message.default_pool.Add(file_descriptor_proto)
916    result = _message.default_pool.FindFileByName(file_descriptor_proto.name)
917
918    if _USE_C_DESCRIPTORS:
919      return result.message_types_by_name[desc_proto.name]
920
921  full_message_name = [desc_proto.name]
922  if package: full_message_name.insert(0, package)
923
924  # Create Descriptors for enum types
925  enum_types = {}
926  for enum_proto in desc_proto.enum_type:
927    full_name = '.'.join(full_message_name + [enum_proto.name])
928    enum_desc = EnumDescriptor(
929      enum_proto.name, full_name, None, [
930          EnumValueDescriptor(enum_val.name, ii, enum_val.number)
931          for ii, enum_val in enumerate(enum_proto.value)])
932    enum_types[full_name] = enum_desc
933
934  # Create Descriptors for nested types
935  nested_types = {}
936  for nested_proto in desc_proto.nested_type:
937    full_name = '.'.join(full_message_name + [nested_proto.name])
938    # Nested types are just those defined inside of the message, not all types
939    # used by fields in the message, so no loops are possible here.
940    nested_desc = MakeDescriptor(nested_proto,
941                                 package='.'.join(full_message_name),
942                                 build_file_if_cpp=False,
943                                 syntax=syntax)
944    nested_types[full_name] = nested_desc
945
946  fields = []
947  for field_proto in desc_proto.field:
948    full_name = '.'.join(full_message_name + [field_proto.name])
949    enum_desc = None
950    nested_desc = None
951    if field_proto.HasField('type_name'):
952      type_name = field_proto.type_name
953      full_type_name = '.'.join(full_message_name +
954                                [type_name[type_name.rfind('.')+1:]])
955      if full_type_name in nested_types:
956        nested_desc = nested_types[full_type_name]
957      elif full_type_name in enum_types:
958        enum_desc = enum_types[full_type_name]
959      # Else type_name references a non-local type, which isn't implemented
960    field = FieldDescriptor(
961        field_proto.name, full_name, field_proto.number - 1,
962        field_proto.number, field_proto.type,
963        FieldDescriptor.ProtoTypeToCppProtoType(field_proto.type),
964        field_proto.label, None, nested_desc, enum_desc, None, False, None,
965        options=field_proto.options, has_default_value=False)
966    fields.append(field)
967
968  desc_name = '.'.join(full_message_name)
969  return Descriptor(desc_proto.name, desc_name, None, None, fields,
970                    list(nested_types.values()), list(enum_types.values()), [],
971                    options=desc_proto.options)
972