1# Protocol Buffers - Google's data interchange format 2# Copyright 2008 Google Inc. All rights reserved. 3# http://code.google.com/p/protobuf/ 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# TODO(robinson): We probably need to provide deep-copy methods for 32# descriptor types. When a FieldDescriptor is passed into 33# Descriptor.__init__(), we should make a deep copy and then set 34# containing_type on it. Alternatively, we could just get 35# rid of containing_type (iit's not needed for reflection.py, at least). 36# 37# TODO(robinson): Print method? 38# 39# TODO(robinson): Useful __repr__? 40 41"""Descriptors essentially contain exactly the information found in a .proto 42file, in types that make this information accessible in Python. 43""" 44 45__author__ = 'robinson@google.com (Will Robinson)' 46 47 48class Error(Exception): 49 """Base error for this module.""" 50 51 52class DescriptorBase(object): 53 54 """Descriptors base class. 55 56 This class is the base of all descriptor classes. It provides common options 57 related functionaility. 58 59 Attributes: 60 has_options: True if the descriptor has non-default options. Usually it 61 is not necessary to read this -- just call GetOptions() which will 62 happily return the default instance. However, it's sometimes useful 63 for efficiency, and also useful inside the protobuf implementation to 64 avoid some bootstrapping issues. 65 """ 66 67 def __init__(self, options, options_class_name): 68 """Initialize the descriptor given its options message and the name of the 69 class of the options message. The name of the class is required in case 70 the options message is None and has to be created. 71 """ 72 self._options = options 73 self._options_class_name = options_class_name 74 75 # Does this descriptor have non-default options? 76 self.has_options = options is not None 77 78 def GetOptions(self): 79 """Retrieves descriptor options. 80 81 This method returns the options set or creates the default options for the 82 descriptor. 83 """ 84 if self._options: 85 return self._options 86 from google.protobuf import descriptor_pb2 87 try: 88 options_class = getattr(descriptor_pb2, self._options_class_name) 89 except AttributeError: 90 raise RuntimeError('Unknown options class name %s!' % 91 (self._options_class_name)) 92 self._options = options_class() 93 return self._options 94 95 96class _NestedDescriptorBase(DescriptorBase): 97 """Common class for descriptors that can be nested.""" 98 99 def __init__(self, options, options_class_name, name, full_name, 100 file, containing_type, serialized_start=None, 101 serialized_end=None): 102 """Constructor. 103 104 Args: 105 options: Protocol message options or None 106 to use default message options. 107 options_class_name: (str) The class name of the above options. 108 109 name: (str) Name of this protocol message type. 110 full_name: (str) Fully-qualified name of this protocol message type, 111 which will include protocol "package" name and the name of any 112 enclosing types. 113 file: (FileDescriptor) Reference to file info. 114 containing_type: if provided, this is a nested descriptor, with this 115 descriptor as parent, otherwise None. 116 serialized_start: The start index (inclusive) in block in the 117 file.serialized_pb that describes this descriptor. 118 serialized_end: The end index (exclusive) in block in the 119 file.serialized_pb that describes this descriptor. 120 """ 121 super(_NestedDescriptorBase, self).__init__( 122 options, options_class_name) 123 124 self.name = name 125 # TODO(falk): Add function to calculate full_name instead of having it in 126 # memory? 127 self.full_name = full_name 128 self.file = file 129 self.containing_type = containing_type 130 131 self._serialized_start = serialized_start 132 self._serialized_end = serialized_end 133 134 def GetTopLevelContainingType(self): 135 """Returns the root if this is a nested type, or itself if its the root.""" 136 desc = self 137 while desc.containing_type is not None: 138 desc = desc.containing_type 139 return desc 140 141 def CopyToProto(self, proto): 142 """Copies this to the matching proto in descriptor_pb2. 143 144 Args: 145 proto: An empty proto instance from descriptor_pb2. 146 147 Raises: 148 Error: If self couldnt be serialized, due to to few constructor arguments. 149 """ 150 if (self.file is not None and 151 self._serialized_start is not None and 152 self._serialized_end is not None): 153 proto.ParseFromString(self.file.serialized_pb[ 154 self._serialized_start:self._serialized_end]) 155 else: 156 raise Error('Descriptor does not contain serialization.') 157 158 159class Descriptor(_NestedDescriptorBase): 160 161 """Descriptor for a protocol message type. 162 163 A Descriptor instance has the following attributes: 164 165 name: (str) Name of this protocol message type. 166 full_name: (str) Fully-qualified name of this protocol message type, 167 which will include protocol "package" name and the name of any 168 enclosing types. 169 170 containing_type: (Descriptor) Reference to the descriptor of the 171 type containing us, or None if this is top-level. 172 173 fields: (list of FieldDescriptors) Field descriptors for all 174 fields in this type. 175 fields_by_number: (dict int -> FieldDescriptor) Same FieldDescriptor 176 objects as in |fields|, but indexed by "number" attribute in each 177 FieldDescriptor. 178 fields_by_name: (dict str -> FieldDescriptor) Same FieldDescriptor 179 objects as in |fields|, but indexed by "name" attribute in each 180 FieldDescriptor. 181 182 nested_types: (list of Descriptors) Descriptor references 183 for all protocol message types nested within this one. 184 nested_types_by_name: (dict str -> Descriptor) Same Descriptor 185 objects as in |nested_types|, but indexed by "name" attribute 186 in each Descriptor. 187 188 enum_types: (list of EnumDescriptors) EnumDescriptor references 189 for all enums contained within this type. 190 enum_types_by_name: (dict str ->EnumDescriptor) Same EnumDescriptor 191 objects as in |enum_types|, but indexed by "name" attribute 192 in each EnumDescriptor. 193 enum_values_by_name: (dict str -> EnumValueDescriptor) Dict mapping 194 from enum value name to EnumValueDescriptor for that value. 195 196 extensions: (list of FieldDescriptor) All extensions defined directly 197 within this message type (NOT within a nested type). 198 extensions_by_name: (dict, string -> FieldDescriptor) Same FieldDescriptor 199 objects as |extensions|, but indexed by "name" attribute of each 200 FieldDescriptor. 201 202 is_extendable: Does this type define any extension ranges? 203 204 options: (descriptor_pb2.MessageOptions) Protocol message options or None 205 to use default message options. 206 207 file: (FileDescriptor) Reference to file descriptor. 208 """ 209 210 def __init__(self, name, full_name, filename, containing_type, fields, 211 nested_types, enum_types, extensions, options=None, 212 is_extendable=True, extension_ranges=None, file=None, 213 serialized_start=None, serialized_end=None): 214 """Arguments to __init__() are as described in the description 215 of Descriptor fields above. 216 217 Note that filename is an obsolete argument, that is not used anymore. 218 Please use file.name to access this as an attribute. 219 """ 220 super(Descriptor, self).__init__( 221 options, 'MessageOptions', name, full_name, file, 222 containing_type, serialized_start=serialized_start, 223 serialized_end=serialized_start) 224 225 # We have fields in addition to fields_by_name and fields_by_number, 226 # so that: 227 # 1. Clients can index fields by "order in which they're listed." 228 # 2. Clients can easily iterate over all fields with the terse 229 # syntax: for f in descriptor.fields: ... 230 self.fields = fields 231 for field in self.fields: 232 field.containing_type = self 233 self.fields_by_number = dict((f.number, f) for f in fields) 234 self.fields_by_name = dict((f.name, f) for f in fields) 235 236 self.nested_types = nested_types 237 self.nested_types_by_name = dict((t.name, t) for t in nested_types) 238 239 self.enum_types = enum_types 240 for enum_type in self.enum_types: 241 enum_type.containing_type = self 242 self.enum_types_by_name = dict((t.name, t) for t in enum_types) 243 self.enum_values_by_name = dict( 244 (v.name, v) for t in enum_types for v in t.values) 245 246 self.extensions = extensions 247 for extension in self.extensions: 248 extension.extension_scope = self 249 self.extensions_by_name = dict((f.name, f) for f in extensions) 250 self.is_extendable = is_extendable 251 self.extension_ranges = extension_ranges 252 253 self._serialized_start = serialized_start 254 self._serialized_end = serialized_end 255 256 def CopyToProto(self, proto): 257 """Copies this to a descriptor_pb2.DescriptorProto. 258 259 Args: 260 proto: An empty descriptor_pb2.DescriptorProto. 261 """ 262 # This function is overriden to give a better doc comment. 263 super(Descriptor, self).CopyToProto(proto) 264 265 266# TODO(robinson): We should have aggressive checking here, 267# for example: 268# * If you specify a repeated field, you should not be allowed 269# to specify a default value. 270# * [Other examples here as needed]. 271# 272# TODO(robinson): for this and other *Descriptor classes, we 273# might also want to lock things down aggressively (e.g., 274# prevent clients from setting the attributes). Having 275# stronger invariants here in general will reduce the number 276# of runtime checks we must do in reflection.py... 277class FieldDescriptor(DescriptorBase): 278 279 """Descriptor for a single field in a .proto file. 280 281 A FieldDescriptor instance has the following attriubtes: 282 283 name: (str) Name of this field, exactly as it appears in .proto. 284 full_name: (str) Name of this field, including containing scope. This is 285 particularly relevant for extensions. 286 index: (int) Dense, 0-indexed index giving the order that this 287 field textually appears within its message in the .proto file. 288 number: (int) Tag number declared for this field in the .proto file. 289 290 type: (One of the TYPE_* constants below) Declared type. 291 cpp_type: (One of the CPPTYPE_* constants below) C++ type used to 292 represent this field. 293 294 label: (One of the LABEL_* constants below) Tells whether this 295 field is optional, required, or repeated. 296 has_default_value: (bool) True if this field has a default value defined, 297 otherwise false. 298 default_value: (Varies) Default value of this field. Only 299 meaningful for non-repeated scalar fields. Repeated fields 300 should always set this to [], and non-repeated composite 301 fields should always set this to None. 302 303 containing_type: (Descriptor) Descriptor of the protocol message 304 type that contains this field. Set by the Descriptor constructor 305 if we're passed into one. 306 Somewhat confusingly, for extension fields, this is the 307 descriptor of the EXTENDED message, not the descriptor 308 of the message containing this field. (See is_extension and 309 extension_scope below). 310 message_type: (Descriptor) If a composite field, a descriptor 311 of the message type contained in this field. Otherwise, this is None. 312 enum_type: (EnumDescriptor) If this field contains an enum, a 313 descriptor of that enum. Otherwise, this is None. 314 315 is_extension: True iff this describes an extension field. 316 extension_scope: (Descriptor) Only meaningful if is_extension is True. 317 Gives the message that immediately contains this extension field. 318 Will be None iff we're a top-level (file-level) extension field. 319 320 options: (descriptor_pb2.FieldOptions) Protocol message field options or 321 None to use default field options. 322 """ 323 324 # Must be consistent with C++ FieldDescriptor::Type enum in 325 # descriptor.h. 326 # 327 # TODO(robinson): Find a way to eliminate this repetition. 328 TYPE_DOUBLE = 1 329 TYPE_FLOAT = 2 330 TYPE_INT64 = 3 331 TYPE_UINT64 = 4 332 TYPE_INT32 = 5 333 TYPE_FIXED64 = 6 334 TYPE_FIXED32 = 7 335 TYPE_BOOL = 8 336 TYPE_STRING = 9 337 TYPE_GROUP = 10 338 TYPE_MESSAGE = 11 339 TYPE_BYTES = 12 340 TYPE_UINT32 = 13 341 TYPE_ENUM = 14 342 TYPE_SFIXED32 = 15 343 TYPE_SFIXED64 = 16 344 TYPE_SINT32 = 17 345 TYPE_SINT64 = 18 346 MAX_TYPE = 18 347 348 # Must be consistent with C++ FieldDescriptor::CppType enum in 349 # descriptor.h. 350 # 351 # TODO(robinson): Find a way to eliminate this repetition. 352 CPPTYPE_INT32 = 1 353 CPPTYPE_INT64 = 2 354 CPPTYPE_UINT32 = 3 355 CPPTYPE_UINT64 = 4 356 CPPTYPE_DOUBLE = 5 357 CPPTYPE_FLOAT = 6 358 CPPTYPE_BOOL = 7 359 CPPTYPE_ENUM = 8 360 CPPTYPE_STRING = 9 361 CPPTYPE_MESSAGE = 10 362 MAX_CPPTYPE = 10 363 364 # Must be consistent with C++ FieldDescriptor::Label enum in 365 # descriptor.h. 366 # 367 # TODO(robinson): Find a way to eliminate this repetition. 368 LABEL_OPTIONAL = 1 369 LABEL_REQUIRED = 2 370 LABEL_REPEATED = 3 371 MAX_LABEL = 3 372 373 def __init__(self, name, full_name, index, number, type, cpp_type, label, 374 default_value, message_type, enum_type, containing_type, 375 is_extension, extension_scope, options=None, 376 has_default_value=True): 377 """The arguments are as described in the description of FieldDescriptor 378 attributes above. 379 380 Note that containing_type may be None, and may be set later if necessary 381 (to deal with circular references between message types, for example). 382 Likewise for extension_scope. 383 """ 384 super(FieldDescriptor, self).__init__(options, 'FieldOptions') 385 self.name = name 386 self.full_name = full_name 387 self.index = index 388 self.number = number 389 self.type = type 390 self.cpp_type = cpp_type 391 self.label = label 392 self.has_default_value = has_default_value 393 self.default_value = default_value 394 self.containing_type = containing_type 395 self.message_type = message_type 396 self.enum_type = enum_type 397 self.is_extension = is_extension 398 self.extension_scope = extension_scope 399 400 401class EnumDescriptor(_NestedDescriptorBase): 402 403 """Descriptor for an enum defined in a .proto file. 404 405 An EnumDescriptor instance has the following attributes: 406 407 name: (str) Name of the enum type. 408 full_name: (str) Full name of the type, including package name 409 and any enclosing type(s). 410 411 values: (list of EnumValueDescriptors) List of the values 412 in this enum. 413 values_by_name: (dict str -> EnumValueDescriptor) Same as |values|, 414 but indexed by the "name" field of each EnumValueDescriptor. 415 values_by_number: (dict int -> EnumValueDescriptor) Same as |values|, 416 but indexed by the "number" field of each EnumValueDescriptor. 417 containing_type: (Descriptor) Descriptor of the immediate containing 418 type of this enum, or None if this is an enum defined at the 419 top level in a .proto file. Set by Descriptor's constructor 420 if we're passed into one. 421 file: (FileDescriptor) Reference to file descriptor. 422 options: (descriptor_pb2.EnumOptions) Enum options message or 423 None to use default enum options. 424 """ 425 426 def __init__(self, name, full_name, filename, values, 427 containing_type=None, options=None, file=None, 428 serialized_start=None, serialized_end=None): 429 """Arguments are as described in the attribute description above. 430 431 Note that filename is an obsolete argument, that is not used anymore. 432 Please use file.name to access this as an attribute. 433 """ 434 super(EnumDescriptor, self).__init__( 435 options, 'EnumOptions', name, full_name, file, 436 containing_type, serialized_start=serialized_start, 437 serialized_end=serialized_start) 438 439 self.values = values 440 for value in self.values: 441 value.type = self 442 self.values_by_name = dict((v.name, v) for v in values) 443 self.values_by_number = dict((v.number, v) for v in values) 444 445 self._serialized_start = serialized_start 446 self._serialized_end = serialized_end 447 448 def CopyToProto(self, proto): 449 """Copies this to a descriptor_pb2.EnumDescriptorProto. 450 451 Args: 452 proto: An empty descriptor_pb2.EnumDescriptorProto. 453 """ 454 # This function is overriden to give a better doc comment. 455 super(EnumDescriptor, self).CopyToProto(proto) 456 457 458class EnumValueDescriptor(DescriptorBase): 459 460 """Descriptor for a single value within an enum. 461 462 name: (str) Name of this value. 463 index: (int) Dense, 0-indexed index giving the order that this 464 value appears textually within its enum in the .proto file. 465 number: (int) Actual number assigned to this enum value. 466 type: (EnumDescriptor) EnumDescriptor to which this value 467 belongs. Set by EnumDescriptor's constructor if we're 468 passed into one. 469 options: (descriptor_pb2.EnumValueOptions) Enum value options message or 470 None to use default enum value options options. 471 """ 472 473 def __init__(self, name, index, number, type=None, options=None): 474 """Arguments are as described in the attribute description above.""" 475 super(EnumValueDescriptor, self).__init__(options, 'EnumValueOptions') 476 self.name = name 477 self.index = index 478 self.number = number 479 self.type = type 480 481 482class ServiceDescriptor(_NestedDescriptorBase): 483 484 """Descriptor for a service. 485 486 name: (str) Name of the service. 487 full_name: (str) Full name of the service, including package name. 488 index: (int) 0-indexed index giving the order that this services 489 definition appears withing the .proto file. 490 methods: (list of MethodDescriptor) List of methods provided by this 491 service. 492 options: (descriptor_pb2.ServiceOptions) Service options message or 493 None to use default service options. 494 file: (FileDescriptor) Reference to file info. 495 """ 496 497 def __init__(self, name, full_name, index, methods, options=None, file=None, 498 serialized_start=None, serialized_end=None): 499 super(ServiceDescriptor, self).__init__( 500 options, 'ServiceOptions', name, full_name, file, 501 None, serialized_start=serialized_start, 502 serialized_end=serialized_end) 503 self.index = index 504 self.methods = methods 505 # Set the containing service for each method in this service. 506 for method in self.methods: 507 method.containing_service = self 508 509 def FindMethodByName(self, name): 510 """Searches for the specified method, and returns its descriptor.""" 511 for method in self.methods: 512 if name == method.name: 513 return method 514 return None 515 516 def CopyToProto(self, proto): 517 """Copies this to a descriptor_pb2.ServiceDescriptorProto. 518 519 Args: 520 proto: An empty descriptor_pb2.ServiceDescriptorProto. 521 """ 522 # This function is overriden to give a better doc comment. 523 super(ServiceDescriptor, self).CopyToProto(proto) 524 525 526class MethodDescriptor(DescriptorBase): 527 528 """Descriptor for a method in a service. 529 530 name: (str) Name of the method within the service. 531 full_name: (str) Full name of method. 532 index: (int) 0-indexed index of the method inside the service. 533 containing_service: (ServiceDescriptor) The service that contains this 534 method. 535 input_type: The descriptor of the message that this method accepts. 536 output_type: The descriptor of the message that this method returns. 537 options: (descriptor_pb2.MethodOptions) Method options message or 538 None to use default method options. 539 """ 540 541 def __init__(self, name, full_name, index, containing_service, 542 input_type, output_type, options=None): 543 """The arguments are as described in the description of MethodDescriptor 544 attributes above. 545 546 Note that containing_service may be None, and may be set later if necessary. 547 """ 548 super(MethodDescriptor, self).__init__(options, 'MethodOptions') 549 self.name = name 550 self.full_name = full_name 551 self.index = index 552 self.containing_service = containing_service 553 self.input_type = input_type 554 self.output_type = output_type 555 556 557class FileDescriptor(DescriptorBase): 558 """Descriptor for a file. Mimics the descriptor_pb2.FileDescriptorProto. 559 560 name: name of file, relative to root of source tree. 561 package: name of the package 562 serialized_pb: (str) Byte string of serialized 563 descriptor_pb2.FileDescriptorProto. 564 """ 565 566 def __init__(self, name, package, options=None, serialized_pb=None): 567 """Constructor.""" 568 super(FileDescriptor, self).__init__(options, 'FileOptions') 569 570 self.name = name 571 self.package = package 572 self.serialized_pb = serialized_pb 573 574 def CopyToProto(self, proto): 575 """Copies this to a descriptor_pb2.FileDescriptorProto. 576 577 Args: 578 proto: An empty descriptor_pb2.FileDescriptorProto. 579 """ 580 proto.ParseFromString(self.serialized_pb) 581 582 583def _ParseOptions(message, string): 584 """Parses serialized options. 585 586 This helper function is used to parse serialized options in generated 587 proto2 files. It must not be used outside proto2. 588 """ 589 message.ParseFromString(string) 590 return message 591