1 # Protocol Buffers - Google's data interchange format
2 # Copyright 2008 Google Inc. All rights reserved.
3 # http://code.google.com/p/protobuf/
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions are
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
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.
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.
31 """Descriptors essentially contain exactly the information found in a .proto
32 file, in types that make this information accessible in Python.
35 __author__ = 'robinson@google.com (Will Robinson)'
38 from google.protobuf.internal import api_implementation
41 if api_implementation.Type() == 'cpp':
42 if api_implementation.Version() == 2:
43 from google.protobuf.internal.cpp import _message
45 from google.protobuf.internal import cpp_message
48 class Error(Exception):
49 """Base error for this module."""
52 class TypeTransformationError(Error):
53 """Error transforming between python proto type and corresponding C++ type."""
56 class DescriptorBase(object):
58 """Descriptors base class.
60 This class is the base of all descriptor classes. It provides common options
61 related functionaility.
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.
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.
76 self._options = options
77 self._options_class_name = options_class_name
79 # Does this descriptor have non-default options?
80 self.has_options = options is not None
82 def _SetOptions(self, options, options_class_name):
83 """Sets the descriptor's options
85 This function is used in generated proto2 files to update descriptor
86 options. It must not be used outside proto2.
88 self._options = options
89 self._options_class_name = options_class_name
91 # Does this descriptor have non-default options?
92 self.has_options = options is not None
95 """Retrieves descriptor options.
97 This method returns the options set or creates the default options for the
102 from google.protobuf import descriptor_pb2
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()
112 class _NestedDescriptorBase(DescriptorBase):
113 """Common class for descriptors that can be nested."""
115 def __init__(self, options, options_class_name, name, full_name,
116 file, containing_type, serialized_start=None,
117 serialized_end=None):
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.
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
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.
137 super(_NestedDescriptorBase, self).__init__(
138 options, options_class_name)
141 # TODO(falk): Add function to calculate full_name instead of having it in
143 self.full_name = full_name
145 self.containing_type = containing_type
147 self._serialized_start = serialized_start
148 self._serialized_end = serialized_end
150 def GetTopLevelContainingType(self):
151 """Returns the root if this is a nested type, or itself if its the root."""
153 while desc.containing_type is not None:
154 desc = desc.containing_type
157 def CopyToProto(self, proto):
158 """Copies this to the matching proto in descriptor_pb2.
161 proto: An empty proto instance from descriptor_pb2.
164 Error: If self couldnt be serialized, due to to few constructor arguments.
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])
172 raise Error('Descriptor does not contain serialization.')
175 class Descriptor(_NestedDescriptorBase):
177 """Descriptor for a protocol message type.
179 A Descriptor instance has the following attributes:
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
186 containing_type: (Descriptor) Reference to the descriptor of the
187 type containing us, or None if this is top-level.
189 fields: (list of FieldDescriptors) Field descriptors for all
191 fields_by_number: (dict int -> FieldDescriptor) Same FieldDescriptor
192 objects as in |fields|, but indexed by "number" attribute in each
194 fields_by_name: (dict str -> FieldDescriptor) Same FieldDescriptor
195 objects as in |fields|, but indexed by "name" attribute in each
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
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.
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
218 is_extendable: Does this type define any extension ranges?
220 options: (descriptor_pb2.MessageOptions) Protocol message options or None
221 to use default message options.
223 file: (FileDescriptor) Reference to file descriptor.
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.
233 Note that filename is an obsolete argument, that is not used anymore.
234 Please use file.name to access this as an attribute.
236 super(Descriptor, self).__init__(
237 options, 'MessageOptions', name, full_name, file,
238 containing_type, serialized_start=serialized_start,
239 serialized_end=serialized_start)
241 # We have fields in addition to fields_by_name and fields_by_number,
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: ...
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)
252 self.nested_types = nested_types
253 self.nested_types_by_name = dict((t.name, t) for t in nested_types)
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)
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
269 self._serialized_start = serialized_start
270 self._serialized_end = serialized_end
272 def EnumValueName(self, enum, value):
273 """Returns the string name of an enum value.
275 This is just a small helper method to simplify a common operation.
278 enum: string name of the Enum.
279 value: int, value of the enum.
282 string name of the enum value.
285 KeyError if either the Enum doesn't exist or the value is not a valid
288 return self.enum_types_by_name[enum].values_by_number[value].name
290 def CopyToProto(self, proto):
291 """Copies this to a descriptor_pb2.DescriptorProto.
294 proto: An empty descriptor_pb2.DescriptorProto.
296 # This function is overriden to give a better doc comment.
297 super(Descriptor, self).CopyToProto(proto)
300 # TODO(robinson): We should have aggressive checking here,
302 # * If you specify a repeated field, you should not be allowed
303 # to specify a default value.
304 # * [Other examples here as needed].
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):
313 """Descriptor for a single field in a .proto file.
315 A FieldDescriptor instance has the following attributes:
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.
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.
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,
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.
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.
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.
354 options: (descriptor_pb2.FieldOptions) Protocol message field options or
355 None to use default field options.
358 # Must be consistent with C++ FieldDescriptor::Type enum in
361 # TODO(robinson): Find a way to eliminate this repetition.
382 # Must be consistent with C++ FieldDescriptor::CppType enum in
385 # TODO(robinson): Find a way to eliminate this repetition.
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
419 # Must be consistent with C++ FieldDescriptor::Label enum in
422 # TODO(robinson): Find a way to eliminate this repetition.
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
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.
439 super(FieldDescriptor, self).__init__(options, 'FieldOptions')
441 self.full_name = full_name
445 self.cpp_type = cpp_type
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':
456 if api_implementation.Version() == 2:
457 self._cdescriptor = _message.GetExtensionDescriptor(full_name)
459 self._cdescriptor = cpp_message.GetExtensionDescriptor(full_name)
461 if api_implementation.Version() == 2:
462 self._cdescriptor = _message.GetFieldDescriptor(full_name)
464 self._cdescriptor = cpp_message.GetFieldDescriptor(full_name)
466 self._cdescriptor = None
469 def ProtoTypeToCppProtoType(proto_type):
470 """Converts from a Python proto type to a C++ Proto Type.
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.
477 proto_type: the Python proto type (descriptor.FieldDescriptor.TYPE_*)
479 descriptor.FieldDescriptor.CPPTYPE_*, the C++ type.
481 TypeTransformationError: when the Python proto type isn't known.
484 return FieldDescriptor._PYTHON_TO_CPP_PROTO_TYPE_MAP[proto_type]
486 raise TypeTransformationError('Unknown proto_type: %s' % proto_type)
489 class EnumDescriptor(_NestedDescriptorBase):
491 """Descriptor for an enum defined in a .proto file.
493 An EnumDescriptor instance has the following attributes:
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).
499 values: (list of EnumValueDescriptors) List of the values
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.
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.
519 Note that filename is an obsolete argument, that is not used anymore.
520 Please use file.name to access this as an attribute.
522 super(EnumDescriptor, self).__init__(
523 options, 'EnumOptions', name, full_name, file,
524 containing_type, serialized_start=serialized_start,
525 serialized_end=serialized_start)
528 for value in self.values:
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)
533 self._serialized_start = serialized_start
534 self._serialized_end = serialized_end
536 def CopyToProto(self, proto):
537 """Copies this to a descriptor_pb2.EnumDescriptorProto.
540 proto: An empty descriptor_pb2.EnumDescriptorProto.
542 # This function is overriden to give a better doc comment.
543 super(EnumDescriptor, self).CopyToProto(proto)
546 class EnumValueDescriptor(DescriptorBase):
548 """Descriptor for a single value within an enum.
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
557 options: (descriptor_pb2.EnumValueOptions) Enum value options message or
558 None to use default enum value options options.
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')
570 class ServiceDescriptor(_NestedDescriptorBase):
572 """Descriptor for a service.
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
580 options: (descriptor_pb2.ServiceOptions) Service options message or
581 None to use default service options.
582 file: (FileDescriptor) Reference to file info.
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)
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
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:
604 def CopyToProto(self, proto):
605 """Copies this to a descriptor_pb2.ServiceDescriptorProto.
608 proto: An empty descriptor_pb2.ServiceDescriptorProto.
610 # This function is overriden to give a better doc comment.
611 super(ServiceDescriptor, self).CopyToProto(proto)
614 class MethodDescriptor(DescriptorBase):
616 """Descriptor for a method in a service.
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
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.
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
634 Note that containing_service may be None, and may be set later if necessary.
636 super(MethodDescriptor, self).__init__(options, 'MethodOptions')
638 self.full_name = full_name
640 self.containing_service = containing_service
641 self.input_type = input_type
642 self.output_type = output_type
645 class FileDescriptor(DescriptorBase):
646 """Descriptor for a file. Mimics the descriptor_pb2.FileDescriptorProto.
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.
654 def __init__(self, name, package, options=None, serialized_pb=None):
656 super(FileDescriptor, self).__init__(options, 'FileOptions')
658 self.message_types_by_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)
667 cpp_message.BuildFile(self.serialized_pb)
669 def CopyToProto(self, proto):
670 """Copies this to a descriptor_pb2.FileDescriptorProto.
673 proto: An empty descriptor_pb2.FileDescriptorProto.
675 proto.ParseFromString(self.serialized_pb)
678 def _ParseOptions(message, string):
679 """Parses serialized options.
681 This helper function is used to parse serialized options in generated
682 proto2 files. It must not be used outside proto2.
684 message.ParseFromString(string)
688 def MakeDescriptor(desc_proto, package=''):
689 """Make a protobuf Descriptor given a DescriptorProto protobuf.
692 desc_proto: The descriptor_pb2.DescriptorProto protobuf message.
693 package: Optional package name for the new message Descriptor (string).
696 A Descriptor for protobuf messages.
698 full_message_name = [desc_proto.name]
699 if package: full_message_name.insert(0, package)
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)
711 desc_name = '.'.join(full_message_name)
712 return Descriptor(desc_proto.name, desc_name, None, None, fields,