The Android Open Source Project | cf31fe9 | 2008-10-21 07:00:00 -0700 | [diff] [blame^] | 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 |
| 42 | file, in types that make this information accessible in Python. |
| 43 | """ |
| 44 | |
| 45 | __author__ = 'robinson@google.com (Will Robinson)' |
| 46 | |
| 47 | class DescriptorBase(object): |
| 48 | |
| 49 | """Descriptors base class. |
| 50 | |
| 51 | This class is the base of all descriptor classes. It provides common options |
| 52 | related functionaility. |
| 53 | """ |
| 54 | |
| 55 | def __init__(self, options, options_class_name): |
| 56 | """Initialize the descriptor given its options message and the name of the |
| 57 | class of the options message. The name of the class is required in case |
| 58 | the options message is None and has to be created. |
| 59 | """ |
| 60 | self._options = options |
| 61 | self._options_class_name = options_class_name |
| 62 | |
| 63 | def GetOptions(self): |
| 64 | """Retrieves descriptor options. |
| 65 | |
| 66 | This method returns the options set or creates the default options for the |
| 67 | descriptor. |
| 68 | """ |
| 69 | if self._options: |
| 70 | return self._options |
| 71 | from froofle.protobuf import descriptor_pb2 |
| 72 | try: |
| 73 | options_class = getattr(descriptor_pb2, self._options_class_name) |
| 74 | except AttributeError: |
| 75 | raise RuntimeError('Unknown options class name %s!' % |
| 76 | (self._options_class_name)) |
| 77 | self._options = options_class() |
| 78 | return self._options |
| 79 | |
| 80 | |
| 81 | class Descriptor(DescriptorBase): |
| 82 | |
| 83 | """Descriptor for a protocol message type. |
| 84 | |
| 85 | A Descriptor instance has the following attributes: |
| 86 | |
| 87 | name: (str) Name of this protocol message type. |
| 88 | full_name: (str) Fully-qualified name of this protocol message type, |
| 89 | which will include protocol "package" name and the name of any |
| 90 | enclosing types. |
| 91 | |
| 92 | filename: (str) Name of the .proto file containing this message. |
| 93 | |
| 94 | containing_type: (Descriptor) Reference to the descriptor of the |
| 95 | type containing us, or None if we have no containing type. |
| 96 | |
| 97 | fields: (list of FieldDescriptors) Field descriptors for all |
| 98 | fields in this type. |
| 99 | fields_by_number: (dict int -> FieldDescriptor) Same FieldDescriptor |
| 100 | objects as in |fields|, but indexed by "number" attribute in each |
| 101 | FieldDescriptor. |
| 102 | fields_by_name: (dict str -> FieldDescriptor) Same FieldDescriptor |
| 103 | objects as in |fields|, but indexed by "name" attribute in each |
| 104 | FieldDescriptor. |
| 105 | |
| 106 | nested_types: (list of Descriptors) Descriptor references |
| 107 | for all protocol message types nested within this one. |
| 108 | nested_types_by_name: (dict str -> Descriptor) Same Descriptor |
| 109 | objects as in |nested_types|, but indexed by "name" attribute |
| 110 | in each Descriptor. |
| 111 | |
| 112 | enum_types: (list of EnumDescriptors) EnumDescriptor references |
| 113 | for all enums contained within this type. |
| 114 | enum_types_by_name: (dict str ->EnumDescriptor) Same EnumDescriptor |
| 115 | objects as in |enum_types|, but indexed by "name" attribute |
| 116 | in each EnumDescriptor. |
| 117 | enum_values_by_name: (dict str -> EnumValueDescriptor) Dict mapping |
| 118 | from enum value name to EnumValueDescriptor for that value. |
| 119 | |
| 120 | extensions: (list of FieldDescriptor) All extensions defined directly |
| 121 | within this message type (NOT within a nested type). |
| 122 | extensions_by_name: (dict, string -> FieldDescriptor) Same FieldDescriptor |
| 123 | objects as |extensions|, but indexed by "name" attribute of each |
| 124 | FieldDescriptor. |
| 125 | |
| 126 | options: (descriptor_pb2.MessageOptions) Protocol message options or None |
| 127 | to use default message options. |
| 128 | """ |
| 129 | |
| 130 | def __init__(self, name, full_name, filename, containing_type, |
| 131 | fields, nested_types, enum_types, extensions, options=None): |
| 132 | """Arguments to __init__() are as described in the description |
| 133 | of Descriptor fields above. |
| 134 | """ |
| 135 | super(Descriptor, self).__init__(options, 'MessageOptions') |
| 136 | self.name = name |
| 137 | self.full_name = full_name |
| 138 | self.filename = filename |
| 139 | self.containing_type = containing_type |
| 140 | |
| 141 | # We have fields in addition to fields_by_name and fields_by_number, |
| 142 | # so that: |
| 143 | # 1. Clients can index fields by "order in which they're listed." |
| 144 | # 2. Clients can easily iterate over all fields with the terse |
| 145 | # syntax: for f in descriptor.fields: ... |
| 146 | self.fields = fields |
| 147 | for field in self.fields: |
| 148 | field.containing_type = self |
| 149 | self.fields_by_number = dict((f.number, f) for f in fields) |
| 150 | self.fields_by_name = dict((f.name, f) for f in fields) |
| 151 | |
| 152 | self.nested_types = nested_types |
| 153 | self.nested_types_by_name = dict((t.name, t) for t in nested_types) |
| 154 | |
| 155 | self.enum_types = enum_types |
| 156 | for enum_type in self.enum_types: |
| 157 | enum_type.containing_type = self |
| 158 | self.enum_types_by_name = dict((t.name, t) for t in enum_types) |
| 159 | self.enum_values_by_name = dict( |
| 160 | (v.name, v) for t in enum_types for v in t.values) |
| 161 | |
| 162 | self.extensions = extensions |
| 163 | for extension in self.extensions: |
| 164 | extension.extension_scope = self |
| 165 | self.extensions_by_name = dict((f.name, f) for f in extensions) |
| 166 | |
| 167 | |
| 168 | # TODO(robinson): We should have aggressive checking here, |
| 169 | # for example: |
| 170 | # * If you specify a repeated field, you should not be allowed |
| 171 | # to specify a default value. |
| 172 | # * [Other examples here as needed]. |
| 173 | # |
| 174 | # TODO(robinson): for this and other *Descriptor classes, we |
| 175 | # might also want to lock things down aggressively (e.g., |
| 176 | # prevent clients from setting the attributes). Having |
| 177 | # stronger invariants here in general will reduce the number |
| 178 | # of runtime checks we must do in reflection.py... |
| 179 | class FieldDescriptor(DescriptorBase): |
| 180 | |
| 181 | """Descriptor for a single field in a .proto file. |
| 182 | |
| 183 | A FieldDescriptor instance has the following attriubtes: |
| 184 | |
| 185 | name: (str) Name of this field, exactly as it appears in .proto. |
| 186 | full_name: (str) Name of this field, including containing scope. This is |
| 187 | particularly relevant for extensions. |
| 188 | index: (int) Dense, 0-indexed index giving the order that this |
| 189 | field textually appears within its message in the .proto file. |
| 190 | number: (int) Tag number declared for this field in the .proto file. |
| 191 | |
| 192 | type: (One of the TYPE_* constants below) Declared type. |
| 193 | cpp_type: (One of the CPPTYPE_* constants below) C++ type used to |
| 194 | represent this field. |
| 195 | |
| 196 | label: (One of the LABEL_* constants below) Tells whether this |
| 197 | field is optional, required, or repeated. |
| 198 | default_value: (Varies) Default value of this field. Only |
| 199 | meaningful for non-repeated scalar fields. Repeated fields |
| 200 | should always set this to [], and non-repeated composite |
| 201 | fields should always set this to None. |
| 202 | |
| 203 | containing_type: (Descriptor) Descriptor of the protocol message |
| 204 | type that contains this field. Set by the Descriptor constructor |
| 205 | if we're passed into one. |
| 206 | Somewhat confusingly, for extension fields, this is the |
| 207 | descriptor of the EXTENDED message, not the descriptor |
| 208 | of the message containing this field. (See is_extension and |
| 209 | extension_scope below). |
| 210 | message_type: (Descriptor) If a composite field, a descriptor |
| 211 | of the message type contained in this field. Otherwise, this is None. |
| 212 | enum_type: (EnumDescriptor) If this field contains an enum, a |
| 213 | descriptor of that enum. Otherwise, this is None. |
| 214 | |
| 215 | is_extension: True iff this describes an extension field. |
| 216 | extension_scope: (Descriptor) Only meaningful if is_extension is True. |
| 217 | Gives the message that immediately contains this extension field. |
| 218 | Will be None iff we're a top-level (file-level) extension field. |
| 219 | |
| 220 | options: (descriptor_pb2.FieldOptions) Protocol message field options or |
| 221 | None to use default field options. |
| 222 | """ |
| 223 | |
| 224 | # Must be consistent with C++ FieldDescriptor::Type enum in |
| 225 | # descriptor.h. |
| 226 | # |
| 227 | # TODO(robinson): Find a way to eliminate this repetition. |
| 228 | TYPE_DOUBLE = 1 |
| 229 | TYPE_FLOAT = 2 |
| 230 | TYPE_INT64 = 3 |
| 231 | TYPE_UINT64 = 4 |
| 232 | TYPE_INT32 = 5 |
| 233 | TYPE_FIXED64 = 6 |
| 234 | TYPE_FIXED32 = 7 |
| 235 | TYPE_BOOL = 8 |
| 236 | TYPE_STRING = 9 |
| 237 | TYPE_GROUP = 10 |
| 238 | TYPE_MESSAGE = 11 |
| 239 | TYPE_BYTES = 12 |
| 240 | TYPE_UINT32 = 13 |
| 241 | TYPE_ENUM = 14 |
| 242 | TYPE_SFIXED32 = 15 |
| 243 | TYPE_SFIXED64 = 16 |
| 244 | TYPE_SINT32 = 17 |
| 245 | TYPE_SINT64 = 18 |
| 246 | MAX_TYPE = 18 |
| 247 | |
| 248 | # Must be consistent with C++ FieldDescriptor::CppType enum in |
| 249 | # descriptor.h. |
| 250 | # |
| 251 | # TODO(robinson): Find a way to eliminate this repetition. |
| 252 | CPPTYPE_INT32 = 1 |
| 253 | CPPTYPE_INT64 = 2 |
| 254 | CPPTYPE_UINT32 = 3 |
| 255 | CPPTYPE_UINT64 = 4 |
| 256 | CPPTYPE_DOUBLE = 5 |
| 257 | CPPTYPE_FLOAT = 6 |
| 258 | CPPTYPE_BOOL = 7 |
| 259 | CPPTYPE_ENUM = 8 |
| 260 | CPPTYPE_STRING = 9 |
| 261 | CPPTYPE_MESSAGE = 10 |
| 262 | MAX_CPPTYPE = 10 |
| 263 | |
| 264 | # Must be consistent with C++ FieldDescriptor::Label enum in |
| 265 | # descriptor.h. |
| 266 | # |
| 267 | # TODO(robinson): Find a way to eliminate this repetition. |
| 268 | LABEL_OPTIONAL = 1 |
| 269 | LABEL_REQUIRED = 2 |
| 270 | LABEL_REPEATED = 3 |
| 271 | MAX_LABEL = 3 |
| 272 | |
| 273 | def __init__(self, name, full_name, index, number, type, cpp_type, label, |
| 274 | default_value, message_type, enum_type, containing_type, |
| 275 | is_extension, extension_scope, options=None): |
| 276 | """The arguments are as described in the description of FieldDescriptor |
| 277 | attributes above. |
| 278 | |
| 279 | Note that containing_type may be None, and may be set later if necessary |
| 280 | (to deal with circular references between message types, for example). |
| 281 | Likewise for extension_scope. |
| 282 | """ |
| 283 | super(FieldDescriptor, self).__init__(options, 'FieldOptions') |
| 284 | self.name = name |
| 285 | self.full_name = full_name |
| 286 | self.index = index |
| 287 | self.number = number |
| 288 | self.type = type |
| 289 | self.cpp_type = cpp_type |
| 290 | self.label = label |
| 291 | self.default_value = default_value |
| 292 | self.containing_type = containing_type |
| 293 | self.message_type = message_type |
| 294 | self.enum_type = enum_type |
| 295 | self.is_extension = is_extension |
| 296 | self.extension_scope = extension_scope |
| 297 | |
| 298 | |
| 299 | class EnumDescriptor(DescriptorBase): |
| 300 | |
| 301 | """Descriptor for an enum defined in a .proto file. |
| 302 | |
| 303 | An EnumDescriptor instance has the following attributes: |
| 304 | |
| 305 | name: (str) Name of the enum type. |
| 306 | full_name: (str) Full name of the type, including package name |
| 307 | and any enclosing type(s). |
| 308 | filename: (str) Name of the .proto file in which this appears. |
| 309 | |
| 310 | values: (list of EnumValueDescriptors) List of the values |
| 311 | in this enum. |
| 312 | values_by_name: (dict str -> EnumValueDescriptor) Same as |values|, |
| 313 | but indexed by the "name" field of each EnumValueDescriptor. |
| 314 | values_by_number: (dict int -> EnumValueDescriptor) Same as |values|, |
| 315 | but indexed by the "number" field of each EnumValueDescriptor. |
| 316 | containing_type: (Descriptor) Descriptor of the immediate containing |
| 317 | type of this enum, or None if this is an enum defined at the |
| 318 | top level in a .proto file. Set by Descriptor's constructor |
| 319 | if we're passed into one. |
| 320 | options: (descriptor_pb2.EnumOptions) Enum options message or |
| 321 | None to use default enum options. |
| 322 | """ |
| 323 | |
| 324 | def __init__(self, name, full_name, filename, values, |
| 325 | containing_type=None, options=None): |
| 326 | """Arguments are as described in the attribute description above.""" |
| 327 | super(EnumDescriptor, self).__init__(options, 'EnumOptions') |
| 328 | self.name = name |
| 329 | self.full_name = full_name |
| 330 | self.filename = filename |
| 331 | self.values = values |
| 332 | for value in self.values: |
| 333 | value.type = self |
| 334 | self.values_by_name = dict((v.name, v) for v in values) |
| 335 | self.values_by_number = dict((v.number, v) for v in values) |
| 336 | self.containing_type = containing_type |
| 337 | |
| 338 | |
| 339 | class EnumValueDescriptor(DescriptorBase): |
| 340 | |
| 341 | """Descriptor for a single value within an enum. |
| 342 | |
| 343 | name: (str) Name of this value. |
| 344 | index: (int) Dense, 0-indexed index giving the order that this |
| 345 | value appears textually within its enum in the .proto file. |
| 346 | number: (int) Actual number assigned to this enum value. |
| 347 | type: (EnumDescriptor) EnumDescriptor to which this value |
| 348 | belongs. Set by EnumDescriptor's constructor if we're |
| 349 | passed into one. |
| 350 | options: (descriptor_pb2.EnumValueOptions) Enum value options message or |
| 351 | None to use default enum value options options. |
| 352 | """ |
| 353 | |
| 354 | def __init__(self, name, index, number, type=None, options=None): |
| 355 | """Arguments are as described in the attribute description above.""" |
| 356 | super(EnumValueDescriptor, self).__init__(options, 'EnumValueOptions') |
| 357 | self.name = name |
| 358 | self.index = index |
| 359 | self.number = number |
| 360 | self.type = type |
| 361 | |
| 362 | |
| 363 | class ServiceDescriptor(DescriptorBase): |
| 364 | |
| 365 | """Descriptor for a service. |
| 366 | |
| 367 | name: (str) Name of the service. |
| 368 | full_name: (str) Full name of the service, including package name. |
| 369 | index: (int) 0-indexed index giving the order that this services |
| 370 | definition appears withing the .proto file. |
| 371 | methods: (list of MethodDescriptor) List of methods provided by this |
| 372 | service. |
| 373 | options: (descriptor_pb2.ServiceOptions) Service options message or |
| 374 | None to use default service options. |
| 375 | """ |
| 376 | |
| 377 | def __init__(self, name, full_name, index, methods, options=None): |
| 378 | super(ServiceDescriptor, self).__init__(options, 'ServiceOptions') |
| 379 | self.name = name |
| 380 | self.full_name = full_name |
| 381 | self.index = index |
| 382 | self.methods = methods |
| 383 | # Set the containing service for each method in this service. |
| 384 | for method in self.methods: |
| 385 | method.containing_service = self |
| 386 | |
| 387 | def FindMethodByName(self, name): |
| 388 | """Searches for the specified method, and returns its descriptor.""" |
| 389 | for method in self.methods: |
| 390 | if name == method.name: |
| 391 | return method |
| 392 | return None |
| 393 | |
| 394 | |
| 395 | class MethodDescriptor(DescriptorBase): |
| 396 | |
| 397 | """Descriptor for a method in a service. |
| 398 | |
| 399 | name: (str) Name of the method within the service. |
| 400 | full_name: (str) Full name of method. |
| 401 | index: (int) 0-indexed index of the method inside the service. |
| 402 | containing_service: (ServiceDescriptor) The service that contains this |
| 403 | method. |
| 404 | input_type: The descriptor of the message that this method accepts. |
| 405 | output_type: The descriptor of the message that this method returns. |
| 406 | options: (descriptor_pb2.MethodOptions) Method options message or |
| 407 | None to use default method options. |
| 408 | """ |
| 409 | |
| 410 | def __init__(self, name, full_name, index, containing_service, |
| 411 | input_type, output_type, options=None): |
| 412 | """The arguments are as described in the description of MethodDescriptor |
| 413 | attributes above. |
| 414 | |
| 415 | Note that containing_service may be None, and may be set later if necessary. |
| 416 | """ |
| 417 | super(MethodDescriptor, self).__init__(options, 'MethodOptions') |
| 418 | self.name = name |
| 419 | self.full_name = full_name |
| 420 | self.index = index |
| 421 | self.containing_service = containing_service |
| 422 | self.input_type = input_type |
| 423 | self.output_type = output_type |
| 424 | |
| 425 | |
| 426 | def _ParseOptions(message, string): |
| 427 | """Parses serialized options. |
| 428 | |
| 429 | This helper function is used to parse serialized options in generated |
| 430 | proto2 files. It must not be used outside proto2. |
| 431 | """ |
| 432 | message.ParseFromString(string) |
| 433 | return message; |