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