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