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