diff options
Diffstat (limited to 'generator/google/protobuf/descriptor.py')
-rw-r--r-- | generator/google/protobuf/descriptor.py | 372 |
1 files changed, 46 insertions, 326 deletions
diff --git a/generator/google/protobuf/descriptor.py b/generator/google/protobuf/descriptor.py index 873af30..eb13eda 100644 --- a/generator/google/protobuf/descriptor.py +++ b/generator/google/protobuf/descriptor.py @@ -1,6 +1,6 @@ # Protocol Buffers - Google's data interchange format # Copyright 2008 Google Inc. All rights reserved. -# https://developers.google.com/protocol-buffers/ +# http://code.google.com/p/protobuf/ # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are @@ -34,17 +34,15 @@ file, in types that make this information accessible in Python. __author__ = 'robinson@google.com (Will Robinson)' -import six from google.protobuf.internal import api_implementation -_USE_C_DESCRIPTORS = False + if api_implementation.Type() == 'cpp': - # Used by MakeDescriptor in cpp mode - import os - import uuid - from google.protobuf.pyext import _message - _USE_C_DESCRIPTORS = getattr(_message, '_USE_C_DESCRIPTORS', False) + if api_implementation.Version() == 2: + from google.protobuf.internal.cpp import _message + else: + from google.protobuf.internal import cpp_message class Error(Exception): @@ -55,29 +53,12 @@ class TypeTransformationError(Error): """Error transforming between python proto type and corresponding C++ type.""" -if _USE_C_DESCRIPTORS: - # This metaclass allows to override the behavior of code like - # isinstance(my_descriptor, FieldDescriptor) - # and make it return True when the descriptor is an instance of the extension - # type written in C++. - class DescriptorMetaclass(type): - def __instancecheck__(cls, obj): - if super(DescriptorMetaclass, cls).__instancecheck__(obj): - return True - if isinstance(obj, cls._C_DESCRIPTOR_CLASS): - return True - return False -else: - # The standard metaclass; nothing changes. - DescriptorMetaclass = type - - -class DescriptorBase(six.with_metaclass(DescriptorMetaclass)): +class DescriptorBase(object): """Descriptors base class. This class is the base of all descriptor classes. It provides common options - related functionality. + related functionaility. Attributes: has_options: True if the descriptor has non-default options. Usually it @@ -87,11 +68,6 @@ class DescriptorBase(six.with_metaclass(DescriptorMetaclass)): avoid some bootstrapping issues. """ - if _USE_C_DESCRIPTORS: - # The class, or tuple of classes, that are considered as "virtual - # subclasses" of this descriptor class. - _C_DESCRIPTOR_CLASS = () - def __init__(self, options, options_class_name): """Initialize the descriptor given its options message and the name of the class of the options message. The name of the class is required in case @@ -218,9 +194,6 @@ class Descriptor(_NestedDescriptorBase): fields_by_name: (dict str -> FieldDescriptor) Same FieldDescriptor objects as in |fields|, but indexed by "name" attribute in each FieldDescriptor. - fields_by_camelcase_name: (dict str -> FieldDescriptor) Same - FieldDescriptor objects as in |fields|, but indexed by - "camelcase_name" attribute in each FieldDescriptor. nested_types: (list of Descriptors) Descriptor references for all protocol message types nested within this one. @@ -244,33 +217,16 @@ class Descriptor(_NestedDescriptorBase): is_extendable: Does this type define any extension ranges? - oneofs: (list of OneofDescriptor) The list of descriptors for oneof fields - in this message. - oneofs_by_name: (dict str -> OneofDescriptor) Same objects as in |oneofs|, - but indexed by "name" attribute. + options: (descriptor_pb2.MessageOptions) Protocol message options or None + to use default message options. file: (FileDescriptor) Reference to file descriptor. """ - if _USE_C_DESCRIPTORS: - _C_DESCRIPTOR_CLASS = _message.Descriptor - - def __new__(cls, name, full_name, filename, containing_type, fields, - nested_types, enum_types, extensions, options=None, - is_extendable=True, extension_ranges=None, oneofs=None, - file=None, serialized_start=None, serialized_end=None, # pylint: disable=redefined-builtin - syntax=None): - _message.Message._CheckCalledFromGeneratedFile() - return _message.default_pool.FindMessageTypeByName(full_name) - - # NOTE(tmarek): The file argument redefining a builtin is nothing we can - # fix right now since we don't know how many clients already rely on the - # name of the argument. def __init__(self, name, full_name, filename, containing_type, fields, nested_types, enum_types, extensions, options=None, - is_extendable=True, extension_ranges=None, oneofs=None, - file=None, serialized_start=None, serialized_end=None, # pylint: disable=redefined-builtin - syntax=None): + is_extendable=True, extension_ranges=None, file=None, + serialized_start=None, serialized_end=None): """Arguments to __init__() are as described in the description of Descriptor fields above. @@ -280,7 +236,7 @@ class Descriptor(_NestedDescriptorBase): super(Descriptor, self).__init__( options, 'MessageOptions', name, full_name, file, containing_type, serialized_start=serialized_start, - serialized_end=serialized_end) + serialized_end=serialized_start) # We have fields in addition to fields_by_name and fields_by_number, # so that: @@ -292,11 +248,8 @@ class Descriptor(_NestedDescriptorBase): field.containing_type = self self.fields_by_number = dict((f.number, f) for f in fields) self.fields_by_name = dict((f.name, f) for f in fields) - self._fields_by_camelcase_name = None self.nested_types = nested_types - for nested_type in nested_types: - nested_type.containing_type = self self.nested_types_by_name = dict((t.name, t) for t in nested_types) self.enum_types = enum_types @@ -312,18 +265,9 @@ class Descriptor(_NestedDescriptorBase): self.extensions_by_name = dict((f.name, f) for f in extensions) self.is_extendable = is_extendable self.extension_ranges = extension_ranges - self.oneofs = oneofs if oneofs is not None else [] - self.oneofs_by_name = dict((o.name, o) for o in self.oneofs) - for oneof in self.oneofs: - oneof.containing_type = self - self.syntax = syntax or "proto2" - - @property - def fields_by_camelcase_name(self): - if self._fields_by_camelcase_name is None: - self._fields_by_camelcase_name = dict( - (f.camelcase_name, f) for f in self.fields) - return self._fields_by_camelcase_name + + self._serialized_start = serialized_start + self._serialized_end = serialized_end def EnumValueName(self, enum, value): """Returns the string name of an enum value. @@ -349,7 +293,7 @@ class Descriptor(_NestedDescriptorBase): Args: proto: An empty descriptor_pb2.DescriptorProto. """ - # This function is overridden to give a better doc comment. + # This function is overriden to give a better doc comment. super(Descriptor, self).CopyToProto(proto) @@ -373,7 +317,6 @@ class FieldDescriptor(DescriptorBase): name: (str) Name of this field, exactly as it appears in .proto. full_name: (str) Name of this field, including containing scope. This is particularly relevant for extensions. - camelcase_name: (str) Camelcase name of this field. index: (int) Dense, 0-indexed index giving the order that this field textually appears within its message in the .proto file. number: (int) Tag number declared for this field in the .proto file. @@ -410,9 +353,6 @@ class FieldDescriptor(DescriptorBase): options: (descriptor_pb2.FieldOptions) Protocol message field options or None to use default field options. - - containing_oneof: (OneofDescriptor) If the field is a member of a oneof - union, contains its descriptor. Otherwise, None. """ # Must be consistent with C++ FieldDescriptor::Type enum in @@ -485,29 +425,10 @@ class FieldDescriptor(DescriptorBase): LABEL_REPEATED = 3 MAX_LABEL = 3 - # Must be consistent with C++ constants kMaxNumber, kFirstReservedNumber, - # and kLastReservedNumber in descriptor.h - MAX_FIELD_NUMBER = (1 << 29) - 1 - FIRST_RESERVED_FIELD_NUMBER = 19000 - LAST_RESERVED_FIELD_NUMBER = 19999 - - if _USE_C_DESCRIPTORS: - _C_DESCRIPTOR_CLASS = _message.FieldDescriptor - - def __new__(cls, name, full_name, index, number, type, cpp_type, label, - default_value, message_type, enum_type, containing_type, - is_extension, extension_scope, options=None, - has_default_value=True, containing_oneof=None): - _message.Message._CheckCalledFromGeneratedFile() - if is_extension: - return _message.default_pool.FindExtensionByName(full_name) - else: - return _message.default_pool.FindFieldByName(full_name) - def __init__(self, name, full_name, index, number, type, cpp_type, label, default_value, message_type, enum_type, containing_type, is_extension, extension_scope, options=None, - has_default_value=True, containing_oneof=None): + has_default_value=True): """The arguments are as described in the description of FieldDescriptor attributes above. @@ -518,7 +439,6 @@ class FieldDescriptor(DescriptorBase): super(FieldDescriptor, self).__init__(options, 'FieldOptions') self.name = name self.full_name = full_name - self._camelcase_name = None self.index = index self.number = number self.type = type @@ -531,21 +451,20 @@ class FieldDescriptor(DescriptorBase): self.enum_type = enum_type self.is_extension = is_extension self.extension_scope = extension_scope - self.containing_oneof = containing_oneof if api_implementation.Type() == 'cpp': if is_extension: - self._cdescriptor = _message.default_pool.FindExtensionByName(full_name) + if api_implementation.Version() == 2: + self._cdescriptor = _message.GetExtensionDescriptor(full_name) + else: + self._cdescriptor = cpp_message.GetExtensionDescriptor(full_name) else: - self._cdescriptor = _message.default_pool.FindFieldByName(full_name) + if api_implementation.Version() == 2: + self._cdescriptor = _message.GetFieldDescriptor(full_name) + else: + self._cdescriptor = cpp_message.GetFieldDescriptor(full_name) else: self._cdescriptor = None - @property - def camelcase_name(self): - if self._camelcase_name is None: - self._camelcase_name = _ToCamelCase(self.name) - return self._camelcase_name - @staticmethod def ProtoTypeToCppProtoType(proto_type): """Converts from a Python proto type to a C++ Proto Type. @@ -592,15 +511,6 @@ class EnumDescriptor(_NestedDescriptorBase): None to use default enum options. """ - if _USE_C_DESCRIPTORS: - _C_DESCRIPTOR_CLASS = _message.EnumDescriptor - - def __new__(cls, name, full_name, filename, values, - containing_type=None, options=None, file=None, - serialized_start=None, serialized_end=None): - _message.Message._CheckCalledFromGeneratedFile() - return _message.default_pool.FindEnumTypeByName(full_name) - def __init__(self, name, full_name, filename, values, containing_type=None, options=None, file=None, serialized_start=None, serialized_end=None): @@ -612,7 +522,7 @@ class EnumDescriptor(_NestedDescriptorBase): super(EnumDescriptor, self).__init__( options, 'EnumOptions', name, full_name, file, containing_type, serialized_start=serialized_start, - serialized_end=serialized_end) + serialized_end=serialized_start) self.values = values for value in self.values: @@ -620,13 +530,16 @@ class EnumDescriptor(_NestedDescriptorBase): self.values_by_name = dict((v.name, v) for v in values) self.values_by_number = dict((v.number, v) for v in values) + self._serialized_start = serialized_start + self._serialized_end = serialized_end + def CopyToProto(self, proto): """Copies this to a descriptor_pb2.EnumDescriptorProto. Args: proto: An empty descriptor_pb2.EnumDescriptorProto. """ - # This function is overridden to give a better doc comment. + # This function is overriden to give a better doc comment. super(EnumDescriptor, self).CopyToProto(proto) @@ -645,17 +558,6 @@ class EnumValueDescriptor(DescriptorBase): None to use default enum value options options. """ - if _USE_C_DESCRIPTORS: - _C_DESCRIPTOR_CLASS = _message.EnumValueDescriptor - - def __new__(cls, name, index, number, type=None, options=None): - _message.Message._CheckCalledFromGeneratedFile() - # There is no way we can build a complete EnumValueDescriptor with the - # given parameters (the name of the Enum is not known, for example). - # Fortunately generated files just pass it to the EnumDescriptor() - # constructor, which will ignore it, so returning None is good enough. - return None - def __init__(self, name, index, number, type=None, options=None): """Arguments are as described in the attribute description above.""" super(EnumValueDescriptor, self).__init__(options, 'EnumValueOptions') @@ -665,39 +567,6 @@ class EnumValueDescriptor(DescriptorBase): self.type = type -class OneofDescriptor(DescriptorBase): - """Descriptor for a oneof field. - - name: (str) Name of the oneof field. - full_name: (str) Full name of the oneof field, including package name. - index: (int) 0-based index giving the order of the oneof field inside - its containing type. - containing_type: (Descriptor) Descriptor of the protocol message - type that contains this field. Set by the Descriptor constructor - if we're passed into one. - fields: (list of FieldDescriptor) The list of field descriptors this - oneof can contain. - """ - - if _USE_C_DESCRIPTORS: - _C_DESCRIPTOR_CLASS = _message.OneofDescriptor - - def __new__( - cls, name, full_name, index, containing_type, fields, options=None): - _message.Message._CheckCalledFromGeneratedFile() - return _message.default_pool.FindOneofByName(full_name) - - def __init__( - self, name, full_name, index, containing_type, fields, options=None): - """Arguments are as described in the attribute description above.""" - super(OneofDescriptor, self).__init__(options, 'OneofOptions') - self.name = name - self.full_name = full_name - self.index = index - self.containing_type = containing_type - self.fields = fields - - class ServiceDescriptor(_NestedDescriptorBase): """Descriptor for a service. @@ -708,22 +577,11 @@ class ServiceDescriptor(_NestedDescriptorBase): definition appears withing the .proto file. methods: (list of MethodDescriptor) List of methods provided by this service. - methods_by_name: (dict str -> MethodDescriptor) Same MethodDescriptor - objects as in |methods_by_name|, but indexed by "name" attribute in each - MethodDescriptor. options: (descriptor_pb2.ServiceOptions) Service options message or None to use default service options. file: (FileDescriptor) Reference to file info. """ - if _USE_C_DESCRIPTORS: - _C_DESCRIPTOR_CLASS = _message.ServiceDescriptor - - def __new__(cls, name, full_name, index, methods, options=None, file=None, # pylint: disable=redefined-builtin - serialized_start=None, serialized_end=None): - _message.Message._CheckCalledFromGeneratedFile() # pylint: disable=protected-access - return _message.default_pool.FindServiceByName(full_name) - def __init__(self, name, full_name, index, methods, options=None, file=None, serialized_start=None, serialized_end=None): super(ServiceDescriptor, self).__init__( @@ -732,14 +590,16 @@ class ServiceDescriptor(_NestedDescriptorBase): serialized_end=serialized_end) self.index = index self.methods = methods - self.methods_by_name = dict((m.name, m) for m in methods) # Set the containing service for each method in this service. for method in self.methods: method.containing_service = self def FindMethodByName(self, name): """Searches for the specified method, and returns its descriptor.""" - return self.methods_by_name.get(name, None) + for method in self.methods: + if name == method.name: + return method + return None def CopyToProto(self, proto): """Copies this to a descriptor_pb2.ServiceDescriptorProto. @@ -747,7 +607,7 @@ class ServiceDescriptor(_NestedDescriptorBase): Args: proto: An empty descriptor_pb2.ServiceDescriptorProto. """ - # This function is overridden to give a better doc comment. + # This function is overriden to give a better doc comment. super(ServiceDescriptor, self).CopyToProto(proto) @@ -766,14 +626,6 @@ class MethodDescriptor(DescriptorBase): None to use default method options. """ - if _USE_C_DESCRIPTORS: - _C_DESCRIPTOR_CLASS = _message.MethodDescriptor - - def __new__(cls, name, full_name, index, containing_service, - input_type, output_type, options=None): - _message.Message._CheckCalledFromGeneratedFile() # pylint: disable=protected-access - return _message.default_pool.FindMethodByName(full_name) - def __init__(self, name, full_name, index, containing_service, input_type, output_type, options=None): """The arguments are as described in the description of MethodDescriptor @@ -793,66 +645,26 @@ class MethodDescriptor(DescriptorBase): class FileDescriptor(DescriptorBase): """Descriptor for a file. Mimics the descriptor_pb2.FileDescriptorProto. - Note that enum_types_by_name, extensions_by_name, and dependencies - fields are only set by the message_factory module, and not by the - generated proto code. - name: name of file, relative to root of source tree. package: name of the package - syntax: string indicating syntax of the file (can be "proto2" or "proto3") serialized_pb: (str) Byte string of serialized descriptor_pb2.FileDescriptorProto. - dependencies: List of other FileDescriptors this FileDescriptor depends on. - public_dependencies: A list of FileDescriptors, subset of the dependencies - above, which were declared as "public". - message_types_by_name: Dict of message names of their descriptors. - enum_types_by_name: Dict of enum names and their descriptors. - extensions_by_name: Dict of extension names and their descriptors. - services_by_name: Dict of services names and their descriptors. - pool: the DescriptorPool this descriptor belongs to. When not passed to the - constructor, the global default pool is used. """ - if _USE_C_DESCRIPTORS: - _C_DESCRIPTOR_CLASS = _message.FileDescriptor - - def __new__(cls, name, package, options=None, serialized_pb=None, - dependencies=None, public_dependencies=None, - syntax=None, pool=None): - # FileDescriptor() is called from various places, not only from generated - # files, to register dynamic proto files and messages. - if serialized_pb: - # TODO(amauryfa): use the pool passed as argument. This will work only - # for C++-implemented DescriptorPools. - return _message.default_pool.AddSerializedFile(serialized_pb) - else: - return super(FileDescriptor, cls).__new__(cls) - - def __init__(self, name, package, options=None, serialized_pb=None, - dependencies=None, public_dependencies=None, - syntax=None, pool=None): + def __init__(self, name, package, options=None, serialized_pb=None): """Constructor.""" super(FileDescriptor, self).__init__(options, 'FileOptions') - if pool is None: - from google.protobuf import descriptor_pool - pool = descriptor_pool.Default() - self.pool = pool self.message_types_by_name = {} self.name = name self.package = package - self.syntax = syntax or "proto2" self.serialized_pb = serialized_pb - - self.enum_types_by_name = {} - self.extensions_by_name = {} - self.services_by_name = {} - self.dependencies = (dependencies or []) - self.public_dependencies = (public_dependencies or []) - if (api_implementation.Type() == 'cpp' and self.serialized_pb is not None): - _message.default_pool.AddSerializedFile(self.serialized_pb) + if api_implementation.Version() == 2: + _message.BuildFile(self.serialized_pb) + else: + cpp_message.BuildFile(self.serialized_pb) def CopyToProto(self, proto): """Copies this to a descriptor_pb2.FileDescriptorProto. @@ -873,121 +685,29 @@ def _ParseOptions(message, string): return message -def _ToCamelCase(name): - """Converts name to camel-case and returns it.""" - capitalize_next = False - result = [] - - for c in name: - if c == '_': - if result: - capitalize_next = True - elif capitalize_next: - result.append(c.upper()) - capitalize_next = False - else: - result += c - - # Lower-case the first letter. - if result and result[0].isupper(): - result[0] = result[0].lower() - return ''.join(result) - - -def MakeDescriptor(desc_proto, package='', build_file_if_cpp=True, - syntax=None): +def MakeDescriptor(desc_proto, package=''): """Make a protobuf Descriptor given a DescriptorProto protobuf. - Handles nested descriptors. Note that this is limited to the scope of defining - a message inside of another message. Composite fields can currently only be - resolved if the message is defined in the same scope as the field. - Args: desc_proto: The descriptor_pb2.DescriptorProto protobuf message. package: Optional package name for the new message Descriptor (string). - build_file_if_cpp: Update the C++ descriptor pool if api matches. - Set to False on recursion, so no duplicates are created. - syntax: The syntax/semantics that should be used. Set to "proto3" to get - proto3 field presence semantics. + Returns: A Descriptor for protobuf messages. """ - if api_implementation.Type() == 'cpp' and build_file_if_cpp: - # The C++ implementation requires all descriptors to be backed by the same - # definition in the C++ descriptor pool. To do this, we build a - # FileDescriptorProto with the same definition as this descriptor and build - # it into the pool. - from google.protobuf import descriptor_pb2 - file_descriptor_proto = descriptor_pb2.FileDescriptorProto() - file_descriptor_proto.message_type.add().MergeFrom(desc_proto) - - # Generate a random name for this proto file to prevent conflicts with any - # imported ones. We need to specify a file name so the descriptor pool - # accepts our FileDescriptorProto, but it is not important what that file - # name is actually set to. - proto_name = str(uuid.uuid4()) - - if package: - file_descriptor_proto.name = os.path.join(package.replace('.', '/'), - proto_name + '.proto') - file_descriptor_proto.package = package - else: - file_descriptor_proto.name = proto_name + '.proto' - - _message.default_pool.Add(file_descriptor_proto) - result = _message.default_pool.FindFileByName(file_descriptor_proto.name) - - if _USE_C_DESCRIPTORS: - return result.message_types_by_name[desc_proto.name] - full_message_name = [desc_proto.name] if package: full_message_name.insert(0, package) - - # Create Descriptors for enum types - enum_types = {} - for enum_proto in desc_proto.enum_type: - full_name = '.'.join(full_message_name + [enum_proto.name]) - enum_desc = EnumDescriptor( - enum_proto.name, full_name, None, [ - EnumValueDescriptor(enum_val.name, ii, enum_val.number) - for ii, enum_val in enumerate(enum_proto.value)]) - enum_types[full_name] = enum_desc - - # Create Descriptors for nested types - nested_types = {} - for nested_proto in desc_proto.nested_type: - full_name = '.'.join(full_message_name + [nested_proto.name]) - # Nested types are just those defined inside of the message, not all types - # used by fields in the message, so no loops are possible here. - nested_desc = MakeDescriptor(nested_proto, - package='.'.join(full_message_name), - build_file_if_cpp=False, - syntax=syntax) - nested_types[full_name] = nested_desc - fields = [] for field_proto in desc_proto.field: full_name = '.'.join(full_message_name + [field_proto.name]) - enum_desc = None - nested_desc = None - if field_proto.HasField('type_name'): - type_name = field_proto.type_name - full_type_name = '.'.join(full_message_name + - [type_name[type_name.rfind('.')+1:]]) - if full_type_name in nested_types: - nested_desc = nested_types[full_type_name] - elif full_type_name in enum_types: - enum_desc = enum_types[full_type_name] - # Else type_name references a non-local type, which isn't implemented field = FieldDescriptor( field_proto.name, full_name, field_proto.number - 1, field_proto.number, field_proto.type, FieldDescriptor.ProtoTypeToCppProtoType(field_proto.type), - field_proto.label, None, nested_desc, enum_desc, None, False, None, - options=field_proto.options, has_default_value=False) + field_proto.label, None, None, None, None, False, None, + has_default_value=False) fields.append(field) desc_name = '.'.join(full_message_name) return Descriptor(desc_proto.name, desc_name, None, None, fields, - list(nested_types.values()), list(enum_types.values()), [], - options=desc_proto.options) + [], [], []) |