1 # Protocol Buffers - Google's data interchange format
2 # Copyright 2008 Google Inc. All rights reserved.
3 # https://developers.google.com/protocol-buffers/
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)'
40 from google.protobuf.internal import api_implementation
42 _USE_C_DESCRIPTORS = False
43 if api_implementation.Type() == 'cpp':
44 # Used by MakeDescriptor in cpp mode
47 from google.protobuf.pyext import _message
48 _USE_C_DESCRIPTORS = getattr(_message, '_USE_C_DESCRIPTORS', False)
51 class Error(Exception):
52 """Base error for this module."""
55 class TypeTransformationError(Error):
56 """Error transforming between python proto type and corresponding C++ type."""
59 if _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):
68 if isinstance(obj, cls._C_DESCRIPTOR_CLASS):
72 # The standard metaclass; nothing changes.
73 DescriptorMetaclass = type
77 """Wrapper class of threading.Lock(), which is allowed by 'with'."""
80 self = object.__new__(cls)
81 self._lock = threading.Lock() # pylint: disable=protected-access
87 def __exit__(self, exc_type, exc_value, exc_tb):
91 _lock = threading.Lock()
94 class DescriptorBase(six.with_metaclass(DescriptorMetaclass)):
96 """Descriptors base class.
98 This class is the base of all descriptor classes. It provides common options
99 related functionality.
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.
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 = ()
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.
119 self._options = options
120 self._options_class_name = options_class_name
121 self._serialized_options = serialized_options
123 # Does this descriptor have non-default options?
124 self.has_options = (options is not None) or (serialized_options is not None)
126 def _SetOptions(self, options, options_class_name):
127 """Sets the descriptor's options
129 This function is used in generated proto2 files to update descriptor
130 options. It must not be used outside proto2.
132 self._options = options
133 self._options_class_name = options_class_name
135 # Does this descriptor have non-default options?
136 self.has_options = options is not None
138 def GetOptions(self):
139 """Retrieves descriptor options.
141 This method returns the options set or creates the default options for the
147 from google.protobuf import descriptor_pb2
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))
156 if self._serialized_options is None:
157 self._options = options_class()
159 self._options = _ParseOptions(options_class(),
160 self._serialized_options)
165 class _NestedDescriptorBase(DescriptorBase):
166 """Common class for descriptors that can be nested."""
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):
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.
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
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.
191 super(_NestedDescriptorBase, self).__init__(
192 options, serialized_options, options_class_name)
195 # TODO(falk): Add function to calculate full_name instead of having it in
197 self.full_name = full_name
199 self.containing_type = containing_type
201 self._serialized_start = serialized_start
202 self._serialized_end = serialized_end
204 def CopyToProto(self, proto):
205 """Copies this to the matching proto in descriptor_pb2.
208 proto: An empty proto instance from descriptor_pb2.
211 Error: If self couldnt be serialized, due to to few constructor arguments.
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])
219 raise Error('Descriptor does not contain serialization.')
222 class Descriptor(_NestedDescriptorBase):
224 """Descriptor for a protocol message type.
226 A Descriptor instance has the following attributes:
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
233 containing_type: (Descriptor) Reference to the descriptor of the
234 type containing us, or None if this is top-level.
236 fields: (list of FieldDescriptors) Field descriptors for all
238 fields_by_number: (dict int -> FieldDescriptor) Same FieldDescriptor
239 objects as in |fields|, but indexed by "number" attribute in each
241 fields_by_name: (dict str -> FieldDescriptor) Same FieldDescriptor
242 objects as in |fields|, but indexed by "name" attribute in each
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.
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
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.
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
268 is_extendable: Does this type define any extension ranges?
270 oneofs: (list of OneofDescriptor) The list of descriptors for oneof fields
272 oneofs_by_name: (dict str -> OneofDescriptor) Same objects as in |oneofs|,
273 but indexed by "name" attribute.
275 file: (FileDescriptor) Reference to file descriptor.
278 if _USE_C_DESCRIPTORS:
279 _C_DESCRIPTOR_CLASS = _message.Descriptor
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
287 _message.Message._CheckCalledFromGeneratedFile()
288 return _message.default_pool.FindMessageTypeByName(full_name)
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
299 """Arguments to __init__() are as described in the description
300 of Descriptor fields above.
302 Note that filename is an obsolete argument, that is not used anymore.
303 Please use file.name to access this as an attribute.
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)
310 # We have fields in addition to fields_by_name and fields_by_number,
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: ...
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
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)
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)
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"
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
353 def EnumValueName(self, enum, value):
354 """Returns the string name of an enum value.
356 This is just a small helper method to simplify a common operation.
359 enum: string name of the Enum.
360 value: int, value of the enum.
363 string name of the enum value.
366 KeyError if either the Enum doesn't exist or the value is not a valid
369 return self.enum_types_by_name[enum].values_by_number[value].name
371 def CopyToProto(self, proto):
372 """Copies this to a descriptor_pb2.DescriptorProto.
375 proto: An empty descriptor_pb2.DescriptorProto.
377 # This function is overridden to give a better doc comment.
378 super(Descriptor, self).CopyToProto(proto)
381 # TODO(robinson): We should have aggressive checking here,
383 # * If you specify a repeated field, you should not be allowed
384 # to specify a default value.
385 # * [Other examples here as needed].
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...
392 class FieldDescriptor(DescriptorBase):
394 """Descriptor for a single field in a .proto file.
396 A FieldDescriptor instance has the following attributes:
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.
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.
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,
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.
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.
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.
436 options: (descriptor_pb2.FieldOptions) Protocol message field options or
437 None to use default field options.
439 containing_oneof: (OneofDescriptor) If the field is a member of a oneof
440 union, contains its descriptor. Otherwise, None.
442 file: (FileDescriptor) Reference to file descriptor.
445 # Must be consistent with C++ FieldDescriptor::Type enum in
448 # TODO(robinson): Find a way to eliminate this repetition.
469 # Must be consistent with C++ FieldDescriptor::CppType enum in
472 # TODO(robinson): Find a way to eliminate this repetition.
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
506 # Must be consistent with C++ FieldDescriptor::Label enum in
509 # TODO(robinson): Find a way to eliminate this repetition.
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
521 if _USE_C_DESCRIPTORS:
522 _C_DESCRIPTOR_CLASS = _message.FieldDescriptor
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()
532 return _message.default_pool.FindExtensionByName(full_name)
534 return _message.default_pool.FindFieldByName(full_name)
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
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.
549 super(FieldDescriptor, self).__init__(
550 options, serialized_options, 'FieldOptions')
552 self.full_name = full_name
554 self._camelcase_name = None
555 if json_name is None:
556 self.json_name = _ToJsonName(name)
558 self.json_name = json_name
562 self.cpp_type = cpp_type
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':
574 self._cdescriptor = _message.default_pool.FindExtensionByName(full_name)
576 self._cdescriptor = _message.default_pool.FindFieldByName(full_name)
578 self._cdescriptor = None
581 def camelcase_name(self):
582 if self._camelcase_name is None:
583 self._camelcase_name = _ToCamelCase(self.name)
584 return self._camelcase_name
587 def ProtoTypeToCppProtoType(proto_type):
588 """Converts from a Python proto type to a C++ Proto Type.
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.
595 proto_type: the Python proto type (descriptor.FieldDescriptor.TYPE_*)
597 descriptor.FieldDescriptor.CPPTYPE_*, the C++ type.
599 TypeTransformationError: when the Python proto type isn't known.
602 return FieldDescriptor._PYTHON_TO_CPP_PROTO_TYPE_MAP[proto_type]
604 raise TypeTransformationError('Unknown proto_type: %s' % proto_type)
607 class EnumDescriptor(_NestedDescriptorBase):
609 """Descriptor for an enum defined in a .proto file.
611 An EnumDescriptor instance has the following attributes:
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).
617 values: (list of EnumValueDescriptors) List of the values
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.
632 if _USE_C_DESCRIPTORS:
633 _C_DESCRIPTOR_CLASS = _message.EnumDescriptor
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)
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.
648 Note that filename is an obsolete argument, that is not used anymore.
649 Please use file.name to access this as an attribute.
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)
657 for value in self.values:
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))
663 def CopyToProto(self, proto):
664 """Copies this to a descriptor_pb2.EnumDescriptorProto.
667 proto: An empty descriptor_pb2.EnumDescriptorProto.
669 # This function is overridden to give a better doc comment.
670 super(EnumDescriptor, self).CopyToProto(proto)
673 class EnumValueDescriptor(DescriptorBase):
675 """Descriptor for a single value within an enum.
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
684 options: (descriptor_pb2.EnumValueOptions) Enum value options message or
685 None to use default enum value options options.
688 if _USE_C_DESCRIPTORS:
689 _C_DESCRIPTOR_CLASS = _message.EnumValueDescriptor
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.
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')
713 class OneofDescriptor(DescriptorBase):
714 """Descriptor for a oneof field.
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
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
727 if _USE_C_DESCRIPTORS:
728 _C_DESCRIPTOR_CLASS = _message.OneofDescriptor
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)
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')
743 self.full_name = full_name
745 self.containing_type = containing_type
749 class ServiceDescriptor(_NestedDescriptorBase):
751 """Descriptor for a service.
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
759 methods_by_name: (dict str -> MethodDescriptor) Same MethodDescriptor
760 objects as in |methods_by_name|, but indexed by "name" attribute in each
762 options: (descriptor_pb2.ServiceOptions) Service options message or
763 None to use default service options.
764 file: (FileDescriptor) Reference to file info.
767 if _USE_C_DESCRIPTORS:
768 _C_DESCRIPTOR_CLASS = _message.ServiceDescriptor
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)
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)
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
790 def FindMethodByName(self, name):
791 """Searches for the specified method, and returns its descriptor."""
792 return self.methods_by_name.get(name, None)
794 def CopyToProto(self, proto):
795 """Copies this to a descriptor_pb2.ServiceDescriptorProto.
798 proto: An empty descriptor_pb2.ServiceDescriptorProto.
800 # This function is overridden to give a better doc comment.
801 super(ServiceDescriptor, self).CopyToProto(proto)
804 class MethodDescriptor(DescriptorBase):
806 """Descriptor for a method in a service.
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
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.
819 if _USE_C_DESCRIPTORS:
820 _C_DESCRIPTOR_CLASS = _message.MethodDescriptor
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)
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
832 Note that containing_service may be None, and may be set later if necessary.
834 super(MethodDescriptor, self).__init__(
835 options, serialized_options, 'MethodOptions')
837 self.full_name = full_name
839 self.containing_service = containing_service
840 self.input_type = input_type
841 self.output_type = output_type
844 class FileDescriptor(DescriptorBase):
845 """Descriptor for a file. Mimics the descriptor_pb2.FileDescriptorProto.
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.
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.
867 if _USE_C_DESCRIPTORS:
868 _C_DESCRIPTOR_CLASS = _message.FileDescriptor
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.
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)
881 return super(FileDescriptor, cls).__new__(cls)
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):
888 super(FileDescriptor, self).__init__(
889 options, serialized_options, 'FileOptions')
892 from google.protobuf import descriptor_pool
893 pool = descriptor_pool.Default()
895 self.message_types_by_name = {}
897 self.package = package
898 self.syntax = syntax or "proto2"
899 self.serialized_pb = serialized_pb
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 [])
907 if (api_implementation.Type() == 'cpp' and
908 self.serialized_pb is not None):
909 _message.default_pool.AddSerializedFile(self.serialized_pb)
911 def CopyToProto(self, proto):
912 """Copies this to a descriptor_pb2.FileDescriptorProto.
915 proto: An empty descriptor_pb2.FileDescriptorProto.
917 proto.ParseFromString(self.serialized_pb)
920 def _ParseOptions(message, string):
921 """Parses serialized options.
923 This helper function is used to parse serialized options in generated
924 proto2 files. It must not be used outside proto2.
926 message.ParseFromString(string)
930 def _ToCamelCase(name):
931 """Converts name to camel-case and returns it."""
932 capitalize_next = False
938 capitalize_next = True
939 elif capitalize_next:
940 result.append(c.upper())
941 capitalize_next = False
945 # Lower-case the first letter.
946 if result and result[0].isupper():
947 result[0] = result[0].lower()
948 return ''.join(result)
951 def _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
959 def _ToJsonName(name):
960 """Converts name to Json name and returns it."""
961 capitalize_next = False
966 capitalize_next = True
967 elif capitalize_next:
968 result.append(c.upper())
969 capitalize_next = False
973 return ''.join(result)
976 def MakeDescriptor(desc_proto, package='', build_file_if_cpp=True,
978 """Make a protobuf Descriptor given a DescriptorProto protobuf.
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.
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.
992 A Descriptor for protobuf messages.
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
999 from google.protobuf import descriptor_pb2
1000 file_descriptor_proto = descriptor_pb2.FileDescriptorProto()
1001 file_descriptor_proto.message_type.add().MergeFrom(desc_proto)
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')
1010 file_descriptor_proto.name = os.path.join(package.replace('.', '/'),
1011 proto_name + '.proto')
1012 file_descriptor_proto.package = package
1014 file_descriptor_proto.name = proto_name + '.proto'
1016 _message.default_pool.Add(file_descriptor_proto)
1017 result = _message.default_pool.FindFileByName(file_descriptor_proto.name)
1019 if _USE_C_DESCRIPTORS:
1020 return result.message_types_by_name[desc_proto.name]
1022 full_message_name = [desc_proto.name]
1023 if package: full_message_name.insert(0, package)
1025 # Create Descriptors for 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
1035 # Create Descriptors for 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,
1045 nested_types[full_name] = nested_desc
1048 for field_proto in desc_proto.field:
1049 full_name = '.'.join(full_message_name + [field_proto.name])
1052 if field_proto.json_name:
1053 json_name = field_proto.json_name
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)
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))