Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(996)

Unified Diff: tools/telemetry/third_party/gsutilz/third_party/protorpc/protorpc/descriptor.py

Issue 1264873003: Add gsutil/third_party to telemetry/third_party/gsutilz/third_party. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Remove httplib2 Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: tools/telemetry/third_party/gsutilz/third_party/protorpc/protorpc/descriptor.py
diff --git a/tools/telemetry/third_party/gsutilz/third_party/protorpc/protorpc/descriptor.py b/tools/telemetry/third_party/gsutilz/third_party/protorpc/protorpc/descriptor.py
new file mode 100755
index 0000000000000000000000000000000000000000..5f9e2e70222ce2ce2acfd0bfd427c4d3eab14b57
--- /dev/null
+++ b/tools/telemetry/third_party/gsutilz/third_party/protorpc/protorpc/descriptor.py
@@ -0,0 +1,712 @@
+#!/usr/bin/env python
+#
+# Copyright 2010 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+"""Services descriptor definitions.
+
+Contains message definitions and functions for converting
+service classes into transmittable message format.
+
+Describing an Enum instance, Enum class, Field class or Message class will
+generate an appropriate descriptor object that describes that class.
+This message can itself be used to transmit information to clients wishing
+to know the description of an enum value, enum, field or message without
+needing to download the source code. This format is also compatible with
+other, non-Python languages.
+
+The descriptors are modeled to be binary compatible with:
+
+ http://code.google.com/p/protobuf/source/browse/trunk/src/google/protobuf/descriptor.proto
+
+NOTE: The names of types and fields are not always the same between these
+descriptors and the ones defined in descriptor.proto. This was done in order
+to make source code files that use these descriptors easier to read. For
+example, it is not necessary to prefix TYPE to all the values in
+FieldDescriptor.Variant as is done in descriptor.proto FieldDescriptorProto.Type.
+
+Example:
+
+ class Pixel(messages.Message):
+
+ x = messages.IntegerField(1, required=True)
+ y = messages.IntegerField(2, required=True)
+
+ color = messages.BytesField(3)
+
+ # Describe Pixel class using message descriptor.
+ fields = []
+
+ field = FieldDescriptor()
+ field.name = 'x'
+ field.number = 1
+ field.label = FieldDescriptor.Label.REQUIRED
+ field.variant = FieldDescriptor.Variant.INT64
+ fields.append(field)
+
+ field = FieldDescriptor()
+ field.name = 'y'
+ field.number = 2
+ field.label = FieldDescriptor.Label.REQUIRED
+ field.variant = FieldDescriptor.Variant.INT64
+ fields.append(field)
+
+ field = FieldDescriptor()
+ field.name = 'color'
+ field.number = 3
+ field.label = FieldDescriptor.Label.OPTIONAL
+ field.variant = FieldDescriptor.Variant.BYTES
+ fields.append(field)
+
+ message = MessageDescriptor()
+ message.name = 'Pixel'
+ message.fields = fields
+
+ # Describing is the equivalent of building the above message.
+ message == describe_message(Pixel)
+
+Public Classes:
+ EnumValueDescriptor: Describes Enum values.
+ EnumDescriptor: Describes Enum classes.
+ FieldDescriptor: Describes field instances.
+ FileDescriptor: Describes a single 'file' unit.
+ FileSet: Describes a collection of file descriptors.
+ MessageDescriptor: Describes Message classes.
+ MethodDescriptor: Describes a method of a service.
+ ServiceDescriptor: Describes a services.
+
+Public Functions:
+ describe_enum_value: Describe an individual enum-value.
+ describe_enum: Describe an Enum class.
+ describe_field: Describe a Field definition.
+ describe_file: Describe a 'file' unit from a Python module or object.
+ describe_file_set: Describe a file set from a list of modules or objects.
+ describe_message: Describe a Message definition.
+ describe_method: Describe a Method definition.
+ describe_service: Describe a Service definition.
+"""
+import six
+
+__author__ = 'rafek@google.com (Rafe Kaplan)'
+
+import codecs
+import types
+
+from . import messages
+from . import util
+
+
+__all__ = ['EnumDescriptor',
+ 'EnumValueDescriptor',
+ 'FieldDescriptor',
+ 'MessageDescriptor',
+ 'MethodDescriptor',
+ 'FileDescriptor',
+ 'FileSet',
+ 'ServiceDescriptor',
+ 'DescriptorLibrary',
+
+ 'describe_enum',
+ 'describe_enum_value',
+ 'describe_field',
+ 'describe_message',
+ 'describe_method',
+ 'describe_file',
+ 'describe_file_set',
+ 'describe_service',
+ 'describe',
+ 'import_descriptor_loader',
+ ]
+
+
+# NOTE: MessageField is missing because message fields cannot have
+# a default value at this time.
+# TODO(rafek): Support default message values.
+#
+# Map to functions that convert default values of fields of a given type
+# to a string. The function must return a value that is compatible with
+# FieldDescriptor.default_value and therefore a unicode string.
+_DEFAULT_TO_STRING_MAP = {
+ messages.IntegerField: six.text_type,
+ messages.FloatField: six.text_type,
+ messages.BooleanField: lambda value: value and u'true' or u'false',
+ messages.BytesField: lambda value: codecs.escape_encode(value)[0],
+ messages.StringField: lambda value: value,
+ messages.EnumField: lambda value: six.text_type(value.number),
+}
+
+_DEFAULT_FROM_STRING_MAP = {
+ messages.IntegerField: int,
+ messages.FloatField: float,
+ messages.BooleanField: lambda value: value == u'true',
+ messages.BytesField: lambda value: codecs.escape_decode(value)[0],
+ messages.StringField: lambda value: value,
+ messages.EnumField: int,
+}
+
+
+class EnumValueDescriptor(messages.Message):
+ """Enum value descriptor.
+
+ Fields:
+ name: Name of enumeration value.
+ number: Number of enumeration value.
+ """
+
+ # TODO(rafek): Why are these listed as optional in descriptor.proto.
+ # Harmonize?
+ name = messages.StringField(1, required=True)
+ number = messages.IntegerField(2,
+ required=True,
+ variant=messages.Variant.INT32)
+
+
+class EnumDescriptor(messages.Message):
+ """Enum class descriptor.
+
+ Fields:
+ name: Name of Enum without any qualification.
+ values: Values defined by Enum class.
+ """
+
+ name = messages.StringField(1)
+ values = messages.MessageField(EnumValueDescriptor, 2, repeated=True)
+
+
+class FieldDescriptor(messages.Message):
+ """Field definition descriptor.
+
+ Enums:
+ Variant: Wire format hint sub-types for field.
+ Label: Values for optional, required and repeated fields.
+
+ Fields:
+ name: Name of field.
+ number: Number of field.
+ variant: Variant of field.
+ type_name: Type name for message and enum fields.
+ default_value: String representation of default value.
+ """
+
+ Variant = messages.Variant
+
+ class Label(messages.Enum):
+ """Field label."""
+
+ OPTIONAL = 1
+ REQUIRED = 2
+ REPEATED = 3
+
+ name = messages.StringField(1, required=True)
+ number = messages.IntegerField(3,
+ required=True,
+ variant=messages.Variant.INT32)
+ label = messages.EnumField(Label, 4, default=Label.OPTIONAL)
+ variant = messages.EnumField(Variant, 5)
+ type_name = messages.StringField(6)
+
+ # For numeric types, contains the original text representation of the value.
+ # For booleans, "true" or "false".
+ # For strings, contains the default text contents (not escaped in any way).
+ # For bytes, contains the C escaped value. All bytes < 128 are that are
+ # traditionally considered unprintable are also escaped.
+ default_value = messages.StringField(7)
+
+
+class MessageDescriptor(messages.Message):
+ """Message definition descriptor.
+
+ Fields:
+ name: Name of Message without any qualification.
+ fields: Fields defined for message.
+ message_types: Nested Message classes defined on message.
+ enum_types: Nested Enum classes defined on message.
+ """
+
+ name = messages.StringField(1)
+ fields = messages.MessageField(FieldDescriptor, 2, repeated=True)
+
+ message_types = messages.MessageField(
+ 'protorpc.descriptor.MessageDescriptor', 3, repeated=True)
+ enum_types = messages.MessageField(EnumDescriptor, 4, repeated=True)
+
+
+class MethodDescriptor(messages.Message):
+ """Service method definition descriptor.
+
+ Fields:
+ name: Name of service method.
+ request_type: Fully qualified or relative name of request message type.
+ response_type: Fully qualified or relative name of response message type.
+ """
+
+ name = messages.StringField(1)
+
+ request_type = messages.StringField(2)
+ response_type = messages.StringField(3)
+
+
+class ServiceDescriptor(messages.Message):
+ """Service definition descriptor.
+
+ Fields:
+ name: Name of Service without any qualification.
+ methods: Remote methods of Service.
+ """
+
+ name = messages.StringField(1)
+
+ methods = messages.MessageField(MethodDescriptor, 2, repeated=True)
+
+
+class FileDescriptor(messages.Message):
+ """Description of file containing protobuf definitions.
+
+ Fields:
+ package: Fully qualified name of package that definitions belong to.
+ message_types: Message definitions contained in file.
+ enum_types: Enum definitions contained in file.
+ service_types: Service definitions contained in file.
+ """
+
+ package = messages.StringField(2)
+
+ # TODO(rafek): Add dependency field
+
+ message_types = messages.MessageField(MessageDescriptor, 4, repeated=True)
+ enum_types = messages.MessageField(EnumDescriptor, 5, repeated=True)
+ service_types = messages.MessageField(ServiceDescriptor, 6, repeated=True)
+
+
+class FileSet(messages.Message):
+ """A collection of FileDescriptors.
+
+ Fields:
+ files: Files in file-set.
+ """
+
+ files = messages.MessageField(FileDescriptor, 1, repeated=True)
+
+
+def describe_enum_value(enum_value):
+ """Build descriptor for Enum instance.
+
+ Args:
+ enum_value: Enum value to provide descriptor for.
+
+ Returns:
+ Initialized EnumValueDescriptor instance describing the Enum instance.
+ """
+ enum_value_descriptor = EnumValueDescriptor()
+ enum_value_descriptor.name = six.text_type(enum_value.name)
+ enum_value_descriptor.number = enum_value.number
+ return enum_value_descriptor
+
+
+def describe_enum(enum_definition):
+ """Build descriptor for Enum class.
+
+ Args:
+ enum_definition: Enum class to provide descriptor for.
+
+ Returns:
+ Initialized EnumDescriptor instance describing the Enum class.
+ """
+ enum_descriptor = EnumDescriptor()
+ enum_descriptor.name = enum_definition.definition_name().split('.')[-1]
+
+ values = []
+ for number in enum_definition.numbers():
+ value = enum_definition.lookup_by_number(number)
+ values.append(describe_enum_value(value))
+
+ if values:
+ enum_descriptor.values = values
+
+ return enum_descriptor
+
+
+def describe_field(field_definition):
+ """Build descriptor for Field instance.
+
+ Args:
+ field_definition: Field instance to provide descriptor for.
+
+ Returns:
+ Initialized FieldDescriptor instance describing the Field instance.
+ """
+ field_descriptor = FieldDescriptor()
+ field_descriptor.name = field_definition.name
+ field_descriptor.number = field_definition.number
+ field_descriptor.variant = field_definition.variant
+
+ if isinstance(field_definition, messages.EnumField):
+ field_descriptor.type_name = field_definition.type.definition_name()
+
+ if isinstance(field_definition, messages.MessageField):
+ field_descriptor.type_name = field_definition.message_type.definition_name()
+
+ if field_definition.default is not None:
+ field_descriptor.default_value = _DEFAULT_TO_STRING_MAP[
+ type(field_definition)](field_definition.default)
+
+ # Set label.
+ if field_definition.repeated:
+ field_descriptor.label = FieldDescriptor.Label.REPEATED
+ elif field_definition.required:
+ field_descriptor.label = FieldDescriptor.Label.REQUIRED
+ else:
+ field_descriptor.label = FieldDescriptor.Label.OPTIONAL
+
+ return field_descriptor
+
+
+def describe_message(message_definition):
+ """Build descriptor for Message class.
+
+ Args:
+ message_definition: Message class to provide descriptor for.
+
+ Returns:
+ Initialized MessageDescriptor instance describing the Message class.
+ """
+ message_descriptor = MessageDescriptor()
+ message_descriptor.name = message_definition.definition_name().split('.')[-1]
+
+ fields = sorted(message_definition.all_fields(),
+ key=lambda v: v.number)
+ if fields:
+ message_descriptor.fields = [describe_field(field) for field in fields]
+
+ try:
+ nested_messages = message_definition.__messages__
+ except AttributeError:
+ pass
+ else:
+ message_descriptors = []
+ for name in nested_messages:
+ value = getattr(message_definition, name)
+ message_descriptors.append(describe_message(value))
+
+ message_descriptor.message_types = message_descriptors
+
+ try:
+ nested_enums = message_definition.__enums__
+ except AttributeError:
+ pass
+ else:
+ enum_descriptors = []
+ for name in nested_enums:
+ value = getattr(message_definition, name)
+ enum_descriptors.append(describe_enum(value))
+
+ message_descriptor.enum_types = enum_descriptors
+
+ return message_descriptor
+
+
+def describe_method(method):
+ """Build descriptor for service method.
+
+ Args:
+ method: Remote service method to describe.
+
+ Returns:
+ Initialized MethodDescriptor instance describing the service method.
+ """
+ method_info = method.remote
+ descriptor = MethodDescriptor()
+ descriptor.name = method_info.method.__name__
+ descriptor.request_type = method_info.request_type.definition_name()
+ descriptor.response_type = method_info.response_type.definition_name()
+
+ return descriptor
+
+
+def describe_service(service_class):
+ """Build descriptor for service.
+
+ Args:
+ service_class: Service class to describe.
+
+ Returns:
+ Initialized ServiceDescriptor instance describing the service.
+ """
+ descriptor = ServiceDescriptor()
+ descriptor.name = service_class.__name__
+ methods = []
+ remote_methods = service_class.all_remote_methods()
+ for name in sorted(remote_methods.keys()):
+ if name == 'get_descriptor':
+ continue
+
+ method = remote_methods[name]
+ methods.append(describe_method(method))
+ if methods:
+ descriptor.methods = methods
+
+ return descriptor
+
+
+def describe_file(module):
+ """Build a file from a specified Python module.
+
+ Args:
+ module: Python module to describe.
+
+ Returns:
+ Initialized FileDescriptor instance describing the module.
+ """
+ # May not import remote at top of file because remote depends on this
+ # file
+ # TODO(rafek): Straighten out this dependency. Possibly move these functions
+ # from descriptor to their own module.
+ from . import remote
+
+ descriptor = FileDescriptor()
+ descriptor.package = util.get_package_for_module(module)
+
+ if not descriptor.package:
+ descriptor.package = None
+
+ message_descriptors = []
+ enum_descriptors = []
+ service_descriptors = []
+
+ # Need to iterate over all top level attributes of the module looking for
+ # message, enum and service definitions. Each definition must be itself
+ # described.
+ for name in sorted(dir(module)):
+ value = getattr(module, name)
+
+ if isinstance(value, type):
+ if issubclass(value, messages.Message):
+ message_descriptors.append(describe_message(value))
+
+ elif issubclass(value, messages.Enum):
+ enum_descriptors.append(describe_enum(value))
+
+ elif issubclass(value, remote.Service):
+ service_descriptors.append(describe_service(value))
+
+ if message_descriptors:
+ descriptor.message_types = message_descriptors
+
+ if enum_descriptors:
+ descriptor.enum_types = enum_descriptors
+
+ if service_descriptors:
+ descriptor.service_types = service_descriptors
+
+ return descriptor
+
+
+def describe_file_set(modules):
+ """Build a file set from a specified Python modules.
+
+ Args:
+ modules: Iterable of Python module to describe.
+
+ Returns:
+ Initialized FileSet instance describing the modules.
+ """
+ descriptor = FileSet()
+ file_descriptors = []
+ for module in modules:
+ file_descriptors.append(describe_file(module))
+
+ if file_descriptors:
+ descriptor.files = file_descriptors
+
+ return descriptor
+
+
+def describe(value):
+ """Describe any value as a descriptor.
+
+ Helper function for describing any object with an appropriate descriptor
+ object.
+
+ Args:
+ value: Value to describe as a descriptor.
+
+ Returns:
+ Descriptor message class if object is describable as a descriptor, else
+ None.
+ """
+ from . import remote
+ if isinstance(value, types.ModuleType):
+ return describe_file(value)
+ elif callable(value) and hasattr(value, 'remote'):
+ return describe_method(value)
+ elif isinstance(value, messages.Field):
+ return describe_field(value)
+ elif isinstance(value, messages.Enum):
+ return describe_enum_value(value)
+ elif isinstance(value, type):
+ if issubclass(value, messages.Message):
+ return describe_message(value)
+ elif issubclass(value, messages.Enum):
+ return describe_enum(value)
+ elif issubclass(value, remote.Service):
+ return describe_service(value)
+ return None
+
+
+@util.positional(1)
+def import_descriptor_loader(definition_name, importer=__import__):
+ """Find objects by importing modules as needed.
+
+ A definition loader is a function that resolves a definition name to a
+ descriptor.
+
+ The import finder resolves definitions to their names by importing modules
+ when necessary.
+
+ Args:
+ definition_name: Name of definition to find.
+ importer: Import function used for importing new modules.
+
+ Returns:
+ Appropriate descriptor for any describable type located by name.
+
+ Raises:
+ DefinitionNotFoundError when a name does not refer to either a definition
+ or a module.
+ """
+ # Attempt to import descriptor as a module.
+ if definition_name.startswith('.'):
+ definition_name = definition_name[1:]
+ if not definition_name.startswith('.'):
+ leaf = definition_name.split('.')[-1]
+ if definition_name:
+ try:
+ module = importer(definition_name, '', '', [leaf])
+ except ImportError:
+ pass
+ else:
+ return describe(module)
+
+ try:
+ # Attempt to use messages.find_definition to find item.
+ return describe(messages.find_definition(definition_name,
+ importer=__import__))
+ except messages.DefinitionNotFoundError as err:
+ # There are things that find_definition will not find, but if the parent
+ # is loaded, its children can be searched for a match.
+ split_name = definition_name.rsplit('.', 1)
+ if len(split_name) > 1:
+ parent, child = split_name
+ try:
+ parent_definition = import_descriptor_loader(parent, importer=importer)
+ except messages.DefinitionNotFoundError:
+ # Fall through to original error.
+ pass
+ else:
+ # Check the parent definition for a matching descriptor.
+ if isinstance(parent_definition, FileDescriptor):
+ search_list = parent_definition.service_types or []
+ elif isinstance(parent_definition, ServiceDescriptor):
+ search_list = parent_definition.methods or []
+ elif isinstance(parent_definition, EnumDescriptor):
+ search_list = parent_definition.values or []
+ elif isinstance(parent_definition, MessageDescriptor):
+ search_list = parent_definition.fields or []
+ else:
+ search_list = []
+
+ for definition in search_list:
+ if definition.name == child:
+ return definition
+
+ # Still didn't find. Reraise original exception.
+ raise err
+
+
+class DescriptorLibrary(object):
+ """A descriptor library is an object that contains known definitions.
+
+ A descriptor library contains a cache of descriptor objects mapped by
+ definition name. It contains all types of descriptors except for
+ file sets.
+
+ When a definition name is requested that the library does not know about
+ it can be provided with a descriptor loader which attempt to resolve the
+ missing descriptor.
+ """
+
+ @util.positional(1)
+ def __init__(self,
+ descriptors=None,
+ descriptor_loader=import_descriptor_loader):
+ """Constructor.
+
+ Args:
+ descriptors: A dictionary or dictionary-like object that can be used
+ to store and cache descriptors by definition name.
+ definition_loader: A function used for resolving missing descriptors.
+ The function takes a definition name as its parameter and returns
+ an appropriate descriptor. It may raise DefinitionNotFoundError.
+ """
+ self.__descriptor_loader = descriptor_loader
+ self.__descriptors = descriptors or {}
+
+ def lookup_descriptor(self, definition_name):
+ """Lookup descriptor by name.
+
+ Get descriptor from library by name. If descriptor is not found will
+ attempt to find via descriptor loader if provided.
+
+ Args:
+ definition_name: Definition name to find.
+
+ Returns:
+ Descriptor that describes definition name.
+
+ Raises:
+ DefinitionNotFoundError if not descriptor exists for definition name.
+ """
+ try:
+ return self.__descriptors[definition_name]
+ except KeyError:
+ pass
+
+ if self.__descriptor_loader:
+ definition = self.__descriptor_loader(definition_name)
+ self.__descriptors[definition_name] = definition
+ return definition
+ else:
+ raise messages.DefinitionNotFoundError(
+ 'Could not find definition for %s' % definition_name)
+
+ def lookup_package(self, definition_name):
+ """Determines the package name for any definition.
+
+ Determine the package that any definition name belongs to. May check
+ parent for package name and will resolve missing descriptors if provided
+ descriptor loader.
+
+ Args:
+ definition_name: Definition name to find package for.
+ """
+ while True:
+ descriptor = self.lookup_descriptor(definition_name)
+ if isinstance(descriptor, FileDescriptor):
+ return descriptor.package
+ else:
+ index = definition_name.rfind('.')
+ if index < 0:
+ return None
+ definition_name = definition_name[:index]

Powered by Google App Engine
This is Rietveld 408576698