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

Unified Diff: tools/telemetry/third_party/gsutil/third_party/protorpc/protorpc/messages.py

Issue 1260493004: Revert "Add gsutil 4.13 to telemetry/third_party" (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: 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/gsutil/third_party/protorpc/protorpc/messages.py
diff --git a/tools/telemetry/third_party/gsutil/third_party/protorpc/protorpc/messages.py b/tools/telemetry/third_party/gsutil/third_party/protorpc/protorpc/messages.py
deleted file mode 100644
index ca918aadd1654824fa2b6ddd76fa76439531989d..0000000000000000000000000000000000000000
--- a/tools/telemetry/third_party/gsutil/third_party/protorpc/protorpc/messages.py
+++ /dev/null
@@ -1,1929 +0,0 @@
-#!/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.
-#
-
-"""Stand-alone implementation of in memory protocol messages.
-
-Public Classes:
- Enum: Represents an enumerated type.
- Variant: Hint for wire format to determine how to serialize.
- Message: Base class for user defined messages.
- IntegerField: Field for integer values.
- FloatField: Field for float values.
- BooleanField: Field for boolean values.
- BytesField: Field for binary string values.
- StringField: Field for UTF-8 string values.
- MessageField: Field for other message type values.
- EnumField: Field for enumerated type values.
-
-Public Exceptions (indentation indications class hierarchy):
- EnumDefinitionError: Raised when enumeration is incorrectly defined.
- FieldDefinitionError: Raised when field is incorrectly defined.
- InvalidVariantError: Raised when variant is not compatible with field type.
- InvalidDefaultError: Raised when default is not compatiable with field.
- InvalidNumberError: Raised when field number is out of range or reserved.
- MessageDefinitionError: Raised when message is incorrectly defined.
- DuplicateNumberError: Raised when field has duplicate number with another.
- ValidationError: Raised when a message or field is not valid.
- DefinitionNotFoundError: Raised when definition not found.
-"""
-import six
-
-__author__ = 'rafek@google.com (Rafe Kaplan)'
-
-
-import types
-import weakref
-
-from . import util
-
-__all__ = ['MAX_ENUM_VALUE',
- 'MAX_FIELD_NUMBER',
- 'FIRST_RESERVED_FIELD_NUMBER',
- 'LAST_RESERVED_FIELD_NUMBER',
-
- 'Enum',
- 'Field',
- 'FieldList',
- 'Variant',
- 'Message',
- 'IntegerField',
- 'FloatField',
- 'BooleanField',
- 'BytesField',
- 'StringField',
- 'MessageField',
- 'EnumField',
- 'find_definition',
-
- 'Error',
- 'DecodeError',
- 'EncodeError',
- 'EnumDefinitionError',
- 'FieldDefinitionError',
- 'InvalidVariantError',
- 'InvalidDefaultError',
- 'InvalidNumberError',
- 'MessageDefinitionError',
- 'DuplicateNumberError',
- 'ValidationError',
- 'DefinitionNotFoundError',
- ]
-
-
-# TODO(rafek): Add extended module test to ensure all exceptions
-# in services extends Error.
-Error = util.Error
-
-
-class EnumDefinitionError(Error):
- """Enumeration definition error."""
-
-
-class FieldDefinitionError(Error):
- """Field definition error."""
-
-
-class InvalidVariantError(FieldDefinitionError):
- """Invalid variant provided to field."""
-
-
-class InvalidDefaultError(FieldDefinitionError):
- """Invalid default provided to field."""
-
-
-class InvalidNumberError(FieldDefinitionError):
- """Invalid number provided to field."""
-
-
-class MessageDefinitionError(Error):
- """Message definition error."""
-
-
-class DuplicateNumberError(Error):
- """Duplicate number assigned to field."""
-
-
-class DefinitionNotFoundError(Error):
- """Raised when definition is not found."""
-
-
-class DecodeError(Error):
- """Error found decoding message from encoded form."""
-
-
-class EncodeError(Error):
- """Error found when encoding message."""
-
-
-class ValidationError(Error):
- """Invalid value for message error."""
-
- def __str__(self):
- """Prints string with field name if present on exception."""
- message = Error.__str__(self)
- try:
- field_name = self.field_name
- except AttributeError:
- return message
- else:
- return message
-
-
-# Attributes that are reserved by a class definition that
-# may not be used by either Enum or Message class definitions.
-_RESERVED_ATTRIBUTE_NAMES = frozenset(
- ['__module__', '__doc__', '__qualname__'])
-
-_POST_INIT_FIELD_ATTRIBUTE_NAMES = frozenset(
- ['name',
- '_message_definition',
- '_MessageField__type',
- '_EnumField__type',
- '_EnumField__resolved_default'])
-
-_POST_INIT_ATTRIBUTE_NAMES = frozenset(
- ['_message_definition'])
-
-# Maximum enumeration value as defined by the protocol buffers standard.
-# All enum values must be less than or equal to this value.
-MAX_ENUM_VALUE = (2 ** 29) - 1
-
-# Maximum field number as defined by the protocol buffers standard.
-# All field numbers must be less than or equal to this value.
-MAX_FIELD_NUMBER = (2 ** 29) - 1
-
-# Field numbers between 19000 and 19999 inclusive are reserved by the
-# protobuf protocol and may not be used by fields.
-FIRST_RESERVED_FIELD_NUMBER = 19000
-LAST_RESERVED_FIELD_NUMBER = 19999
-
-
-class _DefinitionClass(type):
- """Base meta-class used for definition meta-classes.
-
- The Enum and Message definition classes share some basic functionality.
- Both of these classes may be contained by a Message definition. After
- initialization, neither class may have attributes changed
- except for the protected _message_definition attribute, and that attribute
- may change only once.
- """
-
- __initialized = False
-
- def __init__(cls, name, bases, dct):
- """Constructor."""
- type.__init__(cls, name, bases, dct)
- # Base classes may never be initialized.
- if cls.__bases__ != (object,):
- cls.__initialized = True
-
- def message_definition(cls):
- """Get outer Message definition that contains this definition.
-
- Returns:
- Containing Message definition if definition is contained within one,
- else None.
- """
- try:
- return cls._message_definition()
- except AttributeError:
- return None
-
- def __setattr__(cls, name, value):
- """Overridden so that cannot set variables on definition classes after init.
-
- Setting attributes on a class must work during the period of initialization
- to set the enumation value class variables and build the name/number maps.
- Once __init__ has set the __initialized flag to True prohibits setting any
- more values on the class. The class is in effect frozen.
-
- Args:
- name: Name of value to set.
- value: Value to set.
- """
- if cls.__initialized and name not in _POST_INIT_ATTRIBUTE_NAMES:
- raise AttributeError('May not change values: %s' % name)
- else:
- type.__setattr__(cls, name, value)
-
- def __delattr__(cls, name):
- """Overridden so that cannot delete varaibles on definition classes."""
- raise TypeError('May not delete attributes on definition class')
-
- def definition_name(cls):
- """Helper method for creating definition name.
-
- Names will be generated to include the classes package name, scope (if the
- class is nested in another definition) and class name.
-
- By default, the package name for a definition is derived from its module
- name. However, this value can be overriden by placing a 'package' attribute
- in the module that contains the definition class. For example:
-
- package = 'some.alternate.package'
-
- class MyMessage(Message):
- ...
-
- >>> MyMessage.definition_name()
- some.alternate.package.MyMessage
-
- Returns:
- Dot-separated fully qualified name of definition.
- """
- outer_definition_name = cls.outer_definition_name()
- if outer_definition_name is None:
- return six.text_type(cls.__name__)
- else:
- return u'%s.%s' % (outer_definition_name, cls.__name__)
-
- def outer_definition_name(cls):
- """Helper method for creating outer definition name.
-
- Returns:
- If definition is nested, will return the outer definitions name, else the
- package name.
- """
- outer_definition = cls.message_definition()
- if not outer_definition:
- return util.get_package_for_module(cls.__module__)
- else:
- return outer_definition.definition_name()
-
- def definition_package(cls):
- """Helper method for creating creating the package of a definition.
-
- Returns:
- Name of package that definition belongs to.
- """
- outer_definition = cls.message_definition()
- if not outer_definition:
- return util.get_package_for_module(cls.__module__)
- else:
- return outer_definition.definition_package()
-
-
-class _EnumClass(_DefinitionClass):
- """Meta-class used for defining the Enum base class.
-
- Meta-class enables very specific behavior for any defined Enum
- class. All attributes defined on an Enum sub-class must be integers.
- Each attribute defined on an Enum sub-class is translated
- into an instance of that sub-class, with the name of the attribute
- as its name, and the number provided as its value. It also ensures
- that only one level of Enum class hierarchy is possible. In other
- words it is not possible to delcare sub-classes of sub-classes of
- Enum.
-
- This class also defines some functions in order to restrict the
- behavior of the Enum class and its sub-classes. It is not possible
- to change the behavior of the Enum class in later classes since
- any new classes may be defined with only integer values, and no methods.
- """
-
- def __init__(cls, name, bases, dct):
- # Can only define one level of sub-classes below Enum.
- if not (bases == (object,) or bases == (Enum,)):
- raise EnumDefinitionError('Enum type %s may only inherit from Enum' %
- (name,))
-
- cls.__by_number = {}
- cls.__by_name = {}
-
- # Enum base class does not need to be initialized or locked.
- if bases != (object,):
- # Replace integer with number.
- for attribute, value in dct.items():
-
- # Module will be in every enum class.
- if attribute in _RESERVED_ATTRIBUTE_NAMES:
- continue
-
- # Reject anything that is not an int.
- if not isinstance(value, six.integer_types):
- raise EnumDefinitionError(
- 'May only use integers in Enum definitions. Found: %s = %s' %
- (attribute, value))
-
- # Protocol buffer standard recommends non-negative values.
- # Reject negative values.
- if value < 0:
- raise EnumDefinitionError(
- 'Must use non-negative enum values. Found: %s = %d' %
- (attribute, value))
-
- if value > MAX_ENUM_VALUE:
- raise EnumDefinitionError(
- 'Must use enum values less than or equal %d. Found: %s = %d' %
- (MAX_ENUM_VALUE, attribute, value))
-
- if value in cls.__by_number:
- raise EnumDefinitionError(
- 'Value for %s = %d is already defined: %s' %
- (attribute, value, cls.__by_number[value].name))
-
- # Create enum instance and list in new Enum type.
- instance = object.__new__(cls)
- cls.__init__(instance, attribute, value)
- cls.__by_name[instance.name] = instance
- cls.__by_number[instance.number] = instance
- setattr(cls, attribute, instance)
-
- _DefinitionClass.__init__(cls, name, bases, dct)
-
- def __iter__(cls):
- """Iterate over all values of enum.
-
- Yields:
- Enumeration instances of the Enum class in arbitrary order.
- """
- return iter(cls.__by_number.values())
-
- def names(cls):
- """Get all names for Enum.
-
- Returns:
- An iterator for names of the enumeration in arbitrary order.
- """
- return cls.__by_name.keys()
-
- def numbers(cls):
- """Get all numbers for Enum.
-
- Returns:
- An iterator for all numbers of the enumeration in arbitrary order.
- """
- return cls.__by_number.keys()
-
- def lookup_by_name(cls, name):
- """Look up Enum by name.
-
- Args:
- name: Name of enum to find.
-
- Returns:
- Enum sub-class instance of that value.
- """
- return cls.__by_name[name]
-
- def lookup_by_number(cls, number):
- """Look up Enum by number.
-
- Args:
- number: Number of enum to find.
-
- Returns:
- Enum sub-class instance of that value.
- """
- return cls.__by_number[number]
-
- def __len__(cls):
- return len(cls.__by_name)
-
-
-class Enum(six.with_metaclass(_EnumClass, object)):
- """Base class for all enumerated types."""
-
- __slots__ = set(('name', 'number'))
-
- def __new__(cls, index):
- """Acts as look-up routine after class is initialized.
-
- The purpose of overriding __new__ is to provide a way to treat
- Enum subclasses as casting types, similar to how the int type
- functions. A program can pass a string or an integer and this
- method with "convert" that value in to an appropriate Enum instance.
-
- Args:
- index: Name or number to look up. During initialization
- this is always the name of the new enum value.
-
- Raises:
- TypeError: When an inappropriate index value is passed provided.
- """
- # If is enum type of this class, return it.
- if isinstance(index, cls):
- return index
-
- # If number, look up by number.
- if isinstance(index, six.integer_types):
- try:
- return cls.lookup_by_number(index)
- except KeyError:
- pass
-
- # If name, look up by name.
- if isinstance(index, six.string_types):
- try:
- return cls.lookup_by_name(index)
- except KeyError:
- pass
-
- raise TypeError('No such value for %s in Enum %s' %
- (index, cls.__name__))
-
- def __init__(self, name, number=None):
- """Initialize new Enum instance.
-
- Since this should only be called during class initialization any
- calls that happen after the class is frozen raises an exception.
- """
- # Immediately return if __init__ was called after _Enum.__init__().
- # It means that casting operator version of the class constructor
- # is being used.
- if getattr(type(self), '_DefinitionClass__initialized'):
- return
- object.__setattr__(self, 'name', name)
- object.__setattr__(self, 'number', number)
-
- def __setattr__(self, name, value):
- raise TypeError('May not change enum values')
-
- def __str__(self):
- return self.name
-
- def __int__(self):
- return self.number
-
- def __repr__(self):
- return '%s(%s, %d)' % (type(self).__name__, self.name, self.number)
-
- def __reduce__(self):
- """Enable pickling.
-
- Returns:
- A 2-tuple containing the class and __new__ args to be used for restoring
- a pickled instance.
- """
- return self.__class__, (self.number,)
-
- def __cmp__(self, other):
- """Order is by number."""
- if isinstance(other, type(self)):
- return cmp(self.number, other.number)
- return NotImplemented
-
- def __lt__(self, other):
- """Order is by number."""
- if isinstance(other, type(self)):
- return self.number < other.number
- return NotImplemented
-
- def __le__(self, other):
- """Order is by number."""
- if isinstance(other, type(self)):
- return self.number <= other.number
- return NotImplemented
-
- def __eq__(self, other):
- """Order is by number."""
- if isinstance(other, type(self)):
- return self.number == other.number
- return NotImplemented
-
- def __ne__(self, other):
- """Order is by number."""
- if isinstance(other, type(self)):
- return self.number != other.number
- return NotImplemented
-
- def __ge__(self, other):
- """Order is by number."""
- if isinstance(other, type(self)):
- return self.number >= other.number
- return NotImplemented
-
- def __gt__(self, other):
- """Order is by number."""
- if isinstance(other, type(self)):
- return self.number > other.number
- return NotImplemented
-
- def __hash__(self):
- """Hash by number."""
- return hash(self.number)
-
- @classmethod
- def to_dict(cls):
- """Make dictionary version of enumerated class.
-
- Dictionary created this way can be used with def_num.
-
- Returns:
- A dict (name) -> number
- """
- return dict((item.name, item.number) for item in iter(cls))
-
- @staticmethod
- def def_enum(dct, name):
- """Define enum class from dictionary.
-
- Args:
- dct: Dictionary of enumerated values for type.
- name: Name of enum.
- """
- return type(name, (Enum,), dct)
-
-
-# TODO(rafek): Determine to what degree this enumeration should be compatible
-# with FieldDescriptor.Type in:
-#
-# http://code.google.com/p/protobuf/source/browse/trunk/src/google/protobuf/descriptor.proto
-class Variant(Enum):
- """Wire format variant.
-
- Used by the 'protobuf' wire format to determine how to transmit
- a single piece of data. May be used by other formats.
-
- See: http://code.google.com/apis/protocolbuffers/docs/encoding.html
-
- Values:
- DOUBLE: 64-bit floating point number.
- FLOAT: 32-bit floating point number.
- INT64: 64-bit signed integer.
- UINT64: 64-bit unsigned integer.
- INT32: 32-bit signed integer.
- BOOL: Boolean value (True or False).
- STRING: String of UTF-8 encoded text.
- MESSAGE: Embedded message as byte string.
- BYTES: String of 8-bit bytes.
- UINT32: 32-bit unsigned integer.
- ENUM: Enum value as integer.
- SINT32: 32-bit signed integer. Uses "zig-zag" encoding.
- SINT64: 64-bit signed integer. Uses "zig-zag" encoding.
- """
- DOUBLE = 1
- FLOAT = 2
- INT64 = 3
- UINT64 = 4
- INT32 = 5
- BOOL = 8
- STRING = 9
- MESSAGE = 11
- BYTES = 12
- UINT32 = 13
- ENUM = 14
- SINT32 = 17
- SINT64 = 18
-
-
-class _MessageClass(_DefinitionClass):
- """Meta-class used for defining the Message base class.
-
- For more details about Message classes, see the Message class docstring.
- Information contained there may help understanding this class.
-
- Meta-class enables very specific behavior for any defined Message
- class. All attributes defined on an Message sub-class must be field
- instances, Enum class definitions or other Message class definitions. Each
- field attribute defined on an Message sub-class is added to the set of
- field definitions and the attribute is translated in to a slot. It also
- ensures that only one level of Message class hierarchy is possible. In other
- words it is not possible to declare sub-classes of sub-classes of
- Message.
-
- This class also defines some functions in order to restrict the
- behavior of the Message class and its sub-classes. It is not possible
- to change the behavior of the Message class in later classes since
- any new classes may be defined with only field, Enums and Messages, and
- no methods.
- """
-
- def __new__(cls, name, bases, dct):
- """Create new Message class instance.
-
- The __new__ method of the _MessageClass type is overridden so as to
- allow the translation of Field instances to slots.
- """
- by_number = {}
- by_name = {}
-
- variant_map = {}
-
- if bases != (object,):
- # Can only define one level of sub-classes below Message.
- if bases != (Message,):
- raise MessageDefinitionError(
- 'Message types may only inherit from Message')
-
- enums = []
- messages = []
- # Must not use iteritems because this loop will change the state of dct.
- for key, field in dct.items():
-
- if key in _RESERVED_ATTRIBUTE_NAMES:
- continue
-
- if isinstance(field, type) and issubclass(field, Enum):
- enums.append(key)
- continue
-
- if (isinstance(field, type) and
- issubclass(field, Message) and
- field is not Message):
- messages.append(key)
- continue
-
- # Reject anything that is not a field.
- if type(field) is Field or not isinstance(field, Field):
- raise MessageDefinitionError(
- 'May only use fields in message definitions. Found: %s = %s' %
- (key, field))
-
- if field.number in by_number:
- raise DuplicateNumberError(
- 'Field with number %d declared more than once in %s' %
- (field.number, name))
-
- field.name = key
-
- # Place in name and number maps.
- by_name[key] = field
- by_number[field.number] = field
-
- # Add enums if any exist.
- if enums:
- dct['__enums__'] = sorted(enums)
-
- # Add messages if any exist.
- if messages:
- dct['__messages__'] = sorted(messages)
-
- dct['_Message__by_number'] = by_number
- dct['_Message__by_name'] = by_name
-
- return _DefinitionClass.__new__(cls, name, bases, dct)
-
- def __init__(cls, name, bases, dct):
- """Initializer required to assign references to new class."""
- if bases != (object,):
- for value in dct.values():
- if isinstance(value, _DefinitionClass) and not value is Message:
- value._message_definition = weakref.ref(cls)
-
- for field in cls.all_fields():
- field._message_definition = weakref.ref(cls)
-
- _DefinitionClass.__init__(cls, name, bases, dct)
-
-
-class Message(six.with_metaclass(_MessageClass, object)):
- """Base class for user defined message objects.
-
- Used to define messages for efficient transmission across network or
- process space. Messages are defined using the field classes (IntegerField,
- FloatField, EnumField, etc.).
-
- Messages are more restricted than normal classes in that they may only
- contain field attributes and other Message and Enum definitions. These
- restrictions are in place because the structure of the Message class is
- intentended to itself be transmitted across network or process space and
- used directly by clients or even other servers. As such methods and
- non-field attributes could not be transmitted with the structural information
- causing discrepancies between different languages and implementations.
-
- Initialization and validation:
-
- A Message object is considered to be initialized if it has all required
- fields and any nested messages are also initialized.
-
- Calling 'check_initialized' will raise a ValidationException if it is not
- initialized; 'is_initialized' returns a boolean value indicating if it is
- valid.
-
- Validation automatically occurs when Message objects are created
- and populated. Validation that a given value will be compatible with
- a field that it is assigned to can be done through the Field instances
- validate() method. The validate method used on a message will check that
- all values of a message and its sub-messages are valid. Assingning an
- invalid value to a field will raise a ValidationException.
-
- Example:
-
- # Trade type.
- class TradeType(Enum):
- BUY = 1
- SELL = 2
- SHORT = 3
- CALL = 4
-
- class Lot(Message):
- price = IntegerField(1, required=True)
- quantity = IntegerField(2, required=True)
-
- class Order(Message):
- symbol = StringField(1, required=True)
- total_quantity = IntegerField(2, required=True)
- trade_type = EnumField(TradeType, 3, required=True)
- lots = MessageField(Lot, 4, repeated=True)
- limit = IntegerField(5)
-
- order = Order(symbol='GOOG',
- total_quantity=10,
- trade_type=TradeType.BUY)
-
- lot1 = Lot(price=304,
- quantity=7)
-
- lot2 = Lot(price = 305,
- quantity=3)
-
- order.lots = [lot1, lot2]
-
- # Now object is initialized!
- order.check_initialized()
- """
-
- def __init__(self, **kwargs):
- """Initialize internal messages state.
-
- Args:
- A message can be initialized via the constructor by passing in keyword
- arguments corresponding to fields. For example:
-
- class Date(Message):
- day = IntegerField(1)
- month = IntegerField(2)
- year = IntegerField(3)
-
- Invoking:
-
- date = Date(day=6, month=6, year=1911)
-
- is the same as doing:
-
- date = Date()
- date.day = 6
- date.month = 6
- date.year = 1911
- """
- # Tag being an essential implementation detail must be private.
- self.__tags = {}
- self.__unrecognized_fields = {}
-
- assigned = set()
- for name, value in kwargs.items():
- setattr(self, name, value)
- assigned.add(name)
-
- # initialize repeated fields.
- for field in self.all_fields():
- if field.repeated and field.name not in assigned:
- setattr(self, field.name, [])
-
-
- def check_initialized(self):
- """Check class for initialization status.
-
- Check that all required fields are initialized
-
- Raises:
- ValidationError: If message is not initialized.
- """
- for name, field in self.__by_name.items():
- value = getattr(self, name)
- if value is None:
- if field.required:
- raise ValidationError("Message %s is missing required field %s" %
- (type(self).__name__, name))
- else:
- try:
- if (isinstance(field, MessageField) and
- issubclass(field.message_type, Message)):
- if field.repeated:
- for item in value:
- item_message_value = field.value_to_message(item)
- item_message_value.check_initialized()
- else:
- message_value = field.value_to_message(value)
- message_value.check_initialized()
- except ValidationError as err:
- if not hasattr(err, 'message_name'):
- err.message_name = type(self).__name__
- raise
-
- def is_initialized(self):
- """Get initialization status.
-
- Returns:
- True if message is valid, else False.
- """
- try:
- self.check_initialized()
- except ValidationError:
- return False
- else:
- return True
-
- @classmethod
- def all_fields(cls):
- """Get all field definition objects.
-
- Ordering is arbitrary.
-
- Returns:
- Iterator over all values in arbitrary order.
- """
- return cls.__by_name.values()
-
- @classmethod
- def field_by_name(cls, name):
- """Get field by name.
-
- Returns:
- Field object associated with name.
-
- Raises:
- KeyError if no field found by that name.
- """
- return cls.__by_name[name]
-
- @classmethod
- def field_by_number(cls, number):
- """Get field by number.
-
- Returns:
- Field object associated with number.
-
- Raises:
- KeyError if no field found by that number.
- """
- return cls.__by_number[number]
-
- def get_assigned_value(self, name):
- """Get the assigned value of an attribute.
-
- Get the underlying value of an attribute. If value has not been set, will
- not return the default for the field.
-
- Args:
- name: Name of attribute to get.
-
- Returns:
- Value of attribute, None if it has not been set.
- """
- message_type = type(self)
- try:
- field = message_type.field_by_name(name)
- except KeyError:
- raise AttributeError('Message %s has no field %s' % (
- message_type.__name__, name))
- return self.__tags.get(field.number)
-
- def reset(self, name):
- """Reset assigned value for field.
-
- Resetting a field will return it to its default value or None.
-
- Args:
- name: Name of field to reset.
- """
- message_type = type(self)
- try:
- field = message_type.field_by_name(name)
- except KeyError:
- if name not in message_type.__by_name:
- raise AttributeError('Message %s has no field %s' % (
- message_type.__name__, name))
- if field.repeated:
- self.__tags[field.number] = FieldList(field, [])
- else:
- self.__tags.pop(field.number, None)
-
- def all_unrecognized_fields(self):
- """Get the names of all unrecognized fields in this message."""
- return list(self.__unrecognized_fields.keys())
-
- def get_unrecognized_field_info(self, key, value_default=None,
- variant_default=None):
- """Get the value and variant of an unknown field in this message.
-
- Args:
- key: The name or number of the field to retrieve.
- value_default: Value to be returned if the key isn't found.
- variant_default: Value to be returned as variant if the key isn't
- found.
-
- Returns:
- (value, variant), where value and variant are whatever was passed
- to set_unrecognized_field.
- """
- value, variant = self.__unrecognized_fields.get(key, (value_default,
- variant_default))
- return value, variant
-
- def set_unrecognized_field(self, key, value, variant):
- """Set an unrecognized field, used when decoding a message.
-
- Args:
- key: The name or number used to refer to this unknown value.
- value: The value of the field.
- variant: Type information needed to interpret the value or re-encode it.
-
- Raises:
- TypeError: If the variant is not an instance of messages.Variant.
- """
- if not isinstance(variant, Variant):
- raise TypeError('Variant type %s is not valid.' % variant)
- self.__unrecognized_fields[key] = value, variant
-
- def __setattr__(self, name, value):
- """Change set behavior for messages.
-
- Messages may only be assigned values that are fields.
-
- Does not try to validate field when set.
-
- Args:
- name: Name of field to assign to.
- vlaue: Value to assign to field.
-
- Raises:
- AttributeError when trying to assign value that is not a field.
- """
- if name in self.__by_name or name.startswith('_Message__'):
- object.__setattr__(self, name, value)
- else:
- raise AttributeError("May not assign arbitrary value %s "
- "to message %s" % (name, type(self).__name__))
-
- def __repr__(self):
- """Make string representation of message.
-
- Example:
-
- class MyMessage(messages.Message):
- integer_value = messages.IntegerField(1)
- string_value = messages.StringField(2)
-
- my_message = MyMessage()
- my_message.integer_value = 42
- my_message.string_value = u'A string'
-
- print my_message
- >>> <MyMessage
- ... integer_value: 42
- ... string_value: u'A string'>
-
- Returns:
- String representation of message, including the values
- of all fields and repr of all sub-messages.
- """
- body = ['<', type(self).__name__]
- for field in sorted(self.all_fields(),
- key=lambda f: f.number):
- attribute = field.name
- value = self.get_assigned_value(field.name)
- if value is not None:
- body.append('\n %s: %s' % (attribute, repr(value)))
- body.append('>')
- return ''.join(body)
-
- def __eq__(self, other):
- """Equality operator.
-
- Does field by field comparison with other message. For
- equality, must be same type and values of all fields must be
- equal.
-
- Messages not required to be initialized for comparison.
-
- Does not attempt to determine equality for values that have
- default values that are not set. In other words:
-
- class HasDefault(Message):
-
- attr1 = StringField(1, default='default value')
-
- message1 = HasDefault()
- message2 = HasDefault()
- message2.attr1 = 'default value'
-
- message1 != message2
-
- Does not compare unknown values.
-
- Args:
- other: Other message to compare with.
- """
- # TODO(rafek): Implement "equivalent" which does comparisons
- # taking default values in to consideration.
- if self is other:
- return True
-
- if type(self) is not type(other):
- return False
-
- return self.__tags == other.__tags
-
- def __ne__(self, other):
- """Not equals operator.
-
- Does field by field comparison with other message. For
- non-equality, must be different type or any value of a field must be
- non-equal to the same field in the other instance.
-
- Messages not required to be initialized for comparison.
-
- Args:
- other: Other message to compare with.
- """
- return not self.__eq__(other)
-
-
-class FieldList(list):
- """List implementation that validates field values.
-
- This list implementation overrides all methods that add values in to a list
- in order to validate those new elements. Attempting to add or set list
- values that are not of the correct type will raise ValidationError.
- """
-
- def __init__(self, field_instance, sequence):
- """Constructor.
-
- Args:
- field_instance: Instance of field that validates the list.
- sequence: List or tuple to construct list from.
- """
- if not field_instance.repeated:
- raise FieldDefinitionError('FieldList may only accept repeated fields')
- self.__field = field_instance
- self.__field.validate(sequence)
- list.__init__(self, sequence)
-
- def __getstate__(self):
- """Enable pickling.
-
- The assigned field instance can't be pickled if it belongs to a Message
- definition (message_definition uses a weakref), so the Message class and
- field number are returned in that case.
-
- Returns:
- A 3-tuple containing:
- - The field instance, or None if it belongs to a Message class.
- - The Message class that the field instance belongs to, or None.
- - The field instance number of the Message class it belongs to, or None.
- """
- message_class = self.__field.message_definition()
- if message_class is None:
- return self.__field, None, None
- else:
- return None, message_class, self.__field.number
-
- def __setstate__(self, state):
- """Enable unpickling.
-
- Args:
- state: A 3-tuple containing:
- - The field instance, or None if it belongs to a Message class.
- - The Message class that the field instance belongs to, or None.
- - The field instance number of the Message class it belongs to, or None.
- """
- field_instance, message_class, number = state
- if field_instance is None:
- self.__field = message_class.field_by_number(number)
- else:
- self.__field = field_instance
-
- @property
- def field(self):
- """Field that validates list."""
- return self.__field
-
- def __setslice__(self, i, j, sequence):
- """Validate slice assignment to list."""
- self.__field.validate(sequence)
- list.__setslice__(self, i, j, sequence)
-
- def __setitem__(self, index, value):
- """Validate item assignment to list."""
- if isinstance(index, slice):
- self.__field.validate(value)
- else:
- self.__field.validate_element(value)
- list.__setitem__(self, index, value)
-
- def append(self, value):
- """Validate item appending to list."""
- self.__field.validate_element(value)
- return list.append(self, value)
-
- def extend(self, sequence):
- """Validate extension of list."""
- self.__field.validate(sequence)
- return list.extend(self, sequence)
-
- def insert(self, index, value):
- """Validate item insertion to list."""
- self.__field.validate_element(value)
- return list.insert(self, index, value)
-
-
-# TODO(rafek): Prevent additional field subclasses.
-class Field(object):
-
- __variant_to_type = {}
-
- class __metaclass__(type):
-
- def __init__(cls, name, bases, dct):
- getattr(cls, '_Field__variant_to_type').update(
- (variant, cls) for variant in dct.get('VARIANTS', []))
- type.__init__(cls, name, bases, dct)
-
- __initialized = False
-
- @util.positional(2)
- def __init__(self,
- number,
- required=False,
- repeated=False,
- variant=None,
- default=None):
- """Constructor.
-
- The required and repeated parameters are mutually exclusive. Setting both
- to True will raise a FieldDefinitionError.
-
- Sub-class Attributes:
- Each sub-class of Field must define the following:
- VARIANTS: Set of variant types accepted by that field.
- DEFAULT_VARIANT: Default variant type if not specified in constructor.
-
- Args:
- number: Number of field. Must be unique per message class.
- required: Whether or not field is required. Mutually exclusive with
- 'repeated'.
- repeated: Whether or not field is repeated. Mutually exclusive with
- 'required'.
- variant: Wire-format variant hint.
- default: Default value for field if not found in stream.
-
- Raises:
- InvalidVariantError when invalid variant for field is provided.
- InvalidDefaultError when invalid default for field is provided.
- FieldDefinitionError when invalid number provided or mutually exclusive
- fields are used.
- InvalidNumberError when the field number is out of range or reserved.
- """
- if not isinstance(number, int) or not 1 <= number <= MAX_FIELD_NUMBER:
- raise InvalidNumberError('Invalid number for field: %s\n'
- 'Number must be 1 or greater and %d or less' %
- (number, MAX_FIELD_NUMBER))
-
- if FIRST_RESERVED_FIELD_NUMBER <= number <= LAST_RESERVED_FIELD_NUMBER:
- raise InvalidNumberError('Tag number %d is a reserved number.\n'
- 'Numbers %d to %d are reserved' %
- (number, FIRST_RESERVED_FIELD_NUMBER,
- LAST_RESERVED_FIELD_NUMBER))
-
- if repeated and required:
- raise FieldDefinitionError('Cannot set both repeated and required')
-
- if variant is None:
- variant = self.DEFAULT_VARIANT
-
- if repeated and default is not None:
- raise FieldDefinitionError('Repeated fields may not have defaults')
-
- if variant not in self.VARIANTS:
- raise InvalidVariantError(
- 'Invalid variant: %s\nValid variants for %s are %r' %
- (variant, type(self).__name__, sorted(self.VARIANTS)))
-
- self.number = number
- self.required = required
- self.repeated = repeated
- self.variant = variant
-
- if default is not None:
- try:
- self.validate_default(default)
- except ValidationError as err:
- try:
- name = self.name
- except AttributeError:
- # For when raising error before name initialization.
- raise InvalidDefaultError('Invalid default value for %s: %r: %s' %
- (self.__class__.__name__, default, err))
- else:
- raise InvalidDefaultError('Invalid default value for field %s: '
- '%r: %s' % (name, default, err))
-
- self.__default = default
- self.__initialized = True
-
- def __setattr__(self, name, value):
- """Setter overidden to prevent assignment to fields after creation.
-
- Args:
- name: Name of attribute to set.
- value: Value to assign.
- """
- # Special case post-init names. They need to be set after constructor.
- if name in _POST_INIT_FIELD_ATTRIBUTE_NAMES:
- object.__setattr__(self, name, value)
- return
-
- # All other attributes must be set before __initialized.
- if not self.__initialized:
- # Not initialized yet, allow assignment.
- object.__setattr__(self, name, value)
- else:
- raise AttributeError('Field objects are read-only')
-
- def __set__(self, message_instance, value):
- """Set value on message.
-
- Args:
- message_instance: Message instance to set value on.
- value: Value to set on message.
- """
- # Reaches in to message instance directly to assign to private tags.
- if value is None:
- if self.repeated:
- raise ValidationError(
- 'May not assign None to repeated field %s' % self.name)
- else:
- message_instance._Message__tags.pop(self.number, None)
- else:
- if self.repeated:
- value = FieldList(self, value)
- else:
- self.validate(value)
- message_instance._Message__tags[self.number] = value
-
- def __get__(self, message_instance, message_class):
- if message_instance is None:
- return self
-
- result = message_instance._Message__tags.get(self.number)
- if result is None:
- return self.default
- else:
- return result
-
- def validate_element(self, value):
- """Validate single element of field.
-
- This is different from validate in that it is used on individual
- values of repeated fields.
-
- Args:
- value: Value to validate.
-
- Raises:
- ValidationError if value is not expected type.
- """
- if not isinstance(value, self.type):
- if value is None:
- if self.required:
- raise ValidationError('Required field is missing')
- else:
- try:
- name = self.name
- except AttributeError:
- raise ValidationError('Expected type %s for %s, '
- 'found %s (type %s)' %
- (self.type, self.__class__.__name__,
- value, type(value)))
- else:
- raise ValidationError('Expected type %s for field %s, '
- 'found %s (type %s)' %
- (self.type, name, value, type(value)))
-
- def __validate(self, value, validate_element):
- """Internal validation function.
-
- Validate an internal value using a function to validate individual elements.
-
- Args:
- value: Value to validate.
- validate_element: Function to use to validate individual elements.
-
- Raises:
- ValidationError if value is not expected type.
- """
- if not self.repeated:
- validate_element(value)
- else:
- # Must be a list or tuple, may not be a string.
- if isinstance(value, (list, tuple)):
- for element in value:
- if element is None:
- try:
- name = self.name
- except AttributeError:
- raise ValidationError('Repeated values for %s '
- 'may not be None' % self.__class__.__name__)
- else:
- raise ValidationError('Repeated values for field %s '
- 'may not be None' % name)
- validate_element(element)
- elif value is not None:
- try:
- name = self.name
- except AttributeError:
- raise ValidationError('%s is repeated. Found: %s' % (
- self.__class__.__name__, value))
- else:
- raise ValidationError('Field %s is repeated. Found: %s' % (name,
- value))
-
- def validate(self, value):
- """Validate value assigned to field.
-
- Args:
- value: Value to validate.
-
- Raises:
- ValidationError if value is not expected type.
- """
- self.__validate(value, self.validate_element)
-
- def validate_default_element(self, value):
- """Validate value as assigned to field default field.
-
- Some fields may allow for delayed resolution of default types necessary
- in the case of circular definition references. In this case, the default
- value might be a place holder that is resolved when needed after all the
- message classes are defined.
-
- Args:
- value: Default value to validate.
-
- Raises:
- ValidationError if value is not expected type.
- """
- self.validate_element(value)
-
- def validate_default(self, value):
- """Validate default value assigned to field.
-
- Args:
- value: Value to validate.
-
- Raises:
- ValidationError if value is not expected type.
- """
- self.__validate(value, self.validate_default_element)
-
- def message_definition(self):
- """Get Message definition that contains this Field definition.
-
- Returns:
- Containing Message definition for Field. Will return None if for
- some reason Field is defined outside of a Message class.
- """
- try:
- return self._message_definition()
- except AttributeError:
- return None
-
- @property
- def default(self):
- """Get default value for field."""
- return self.__default
-
- @classmethod
- def lookup_field_type_by_variant(cls, variant):
- return cls.__variant_to_type[variant]
-
-
-class IntegerField(Field):
- """Field definition for integer values."""
-
- VARIANTS = frozenset([Variant.INT32,
- Variant.INT64,
- Variant.UINT32,
- Variant.UINT64,
- Variant.SINT32,
- Variant.SINT64,
- ])
-
- DEFAULT_VARIANT = Variant.INT64
-
- type = six.integer_types
-
-
-class FloatField(Field):
- """Field definition for float values."""
-
- VARIANTS = frozenset([Variant.FLOAT,
- Variant.DOUBLE,
- ])
-
- DEFAULT_VARIANT = Variant.DOUBLE
-
- type = float
-
-
-class BooleanField(Field):
- """Field definition for boolean values."""
-
- VARIANTS = frozenset([Variant.BOOL])
-
- DEFAULT_VARIANT = Variant.BOOL
-
- type = bool
-
-
-class BytesField(Field):
- """Field definition for byte string values."""
-
- VARIANTS = frozenset([Variant.BYTES])
-
- DEFAULT_VARIANT = Variant.BYTES
-
- type = bytes
-
-
-class StringField(Field):
- """Field definition for unicode string values."""
-
- VARIANTS = frozenset([Variant.STRING])
-
- DEFAULT_VARIANT = Variant.STRING
-
- type = six.text_type
-
- def validate_element(self, value):
- """Validate StringField allowing for str and unicode.
-
- Raises:
- ValidationError if a str value is not 7-bit ascii.
- """
- # If value is str is it considered valid. Satisfies "required=True".
- if isinstance(value, bytes):
- try:
- six.text_type(value, 'ascii')
- except UnicodeDecodeError as err:
- try:
- name = self.name
- except AttributeError:
- validation_error = ValidationError(
- 'Field encountered non-ASCII string %r: %s' % (value,
- err))
- else:
- validation_error = ValidationError(
- 'Field %s encountered non-ASCII string %r: %s' % (self.name,
- value,
- err))
- validation_error.field_name = self.name
- raise validation_error
- else:
- super(StringField, self).validate_element(value)
-
-
-class MessageField(Field):
- """Field definition for sub-message values.
-
- Message fields contain instance of other messages. Instances stored
- on messages stored on message fields are considered to be owned by
- the containing message instance and should not be shared between
- owning instances.
-
- Message fields must be defined to reference a single type of message.
- Normally message field are defined by passing the referenced message
- class in to the constructor.
-
- It is possible to define a message field for a type that does not yet
- exist by passing the name of the message in to the constructor instead
- of a message class. Resolution of the actual type of the message is
- deferred until it is needed, for example, during message verification.
- Names provided to the constructor must refer to a class within the same
- python module as the class that is using it. Names refer to messages
- relative to the containing messages scope. For example, the two fields
- of OuterMessage refer to the same message type:
-
- class Outer(Message):
-
- inner_relative = MessageField('Inner', 1)
- inner_absolute = MessageField('Outer.Inner', 2)
-
- class Inner(Message):
- ...
-
- When resolving an actual type, MessageField will traverse the entire
- scope of nested messages to match a message name. This makes it easy
- for siblings to reference siblings:
-
- class Outer(Message):
-
- class Inner(Message):
-
- sibling = MessageField('Sibling', 1)
-
- class Sibling(Message):
- ...
- """
-
- VARIANTS = frozenset([Variant.MESSAGE])
-
- DEFAULT_VARIANT = Variant.MESSAGE
-
- @util.positional(3)
- def __init__(self,
- message_type,
- number,
- required=False,
- repeated=False,
- variant=None):
- """Constructor.
-
- Args:
- message_type: Message type for field. Must be subclass of Message.
- number: Number of field. Must be unique per message class.
- required: Whether or not field is required. Mutually exclusive to
- 'repeated'.
- repeated: Whether or not field is repeated. Mutually exclusive to
- 'required'.
- variant: Wire-format variant hint.
-
- Raises:
- FieldDefinitionError when invalid message_type is provided.
- """
- valid_type = (isinstance(message_type, six.string_types) or
- (message_type is not Message and
- isinstance(message_type, type) and
- issubclass(message_type, Message)))
-
- if not valid_type:
- raise FieldDefinitionError('Invalid message class: %s' % message_type)
-
- if isinstance(message_type, six.string_types):
- self.__type_name = message_type
- self.__type = None
- else:
- self.__type = message_type
-
- super(MessageField, self).__init__(number,
- required=required,
- repeated=repeated,
- variant=variant)
-
- def __set__(self, message_instance, value):
- """Set value on message.
-
- Args:
- message_instance: Message instance to set value on.
- value: Value to set on message.
- """
- message_type = self.type
- if isinstance(message_type, type) and issubclass(message_type, Message):
- if self.repeated:
- if value and isinstance(value, (list, tuple)):
- value = [(message_type(**v) if isinstance(v, dict) else v)
- for v in value]
- elif isinstance(value, dict):
- value = message_type(**value)
- super(MessageField, self).__set__(message_instance, value)
-
- @property
- def type(self):
- """Message type used for field."""
- if self.__type is None:
- message_type = find_definition(self.__type_name, self.message_definition())
- if not (message_type is not Message and
- isinstance(message_type, type) and
- issubclass(message_type, Message)):
- raise FieldDefinitionError('Invalid message class: %s' % message_type)
- self.__type = message_type
- return self.__type
-
- @property
- def message_type(self):
- """Underlying message type used for serialization.
-
- Will always be a sub-class of Message. This is different from type
- which represents the python value that message_type is mapped to for
- use by the user.
- """
- return self.type
-
- def value_from_message(self, message):
- """Convert a message to a value instance.
-
- Used by deserializers to convert from underlying messages to
- value of expected user type.
-
- Args:
- message: A message instance of type self.message_type.
-
- Returns:
- Value of self.message_type.
- """
- if not isinstance(message, self.message_type):
- raise DecodeError('Expected type %s, got %s: %r' %
- (self.message_type.__name__,
- type(message).__name__,
- message))
- return message
-
- def value_to_message(self, value):
- """Convert a value instance to a message.
-
- Used by serializers to convert Python user types to underlying
- messages for transmission.
-
- Args:
- value: A value of type self.type.
-
- Returns:
- An instance of type self.message_type.
- """
- if not isinstance(value, self.type):
- raise EncodeError('Expected type %s, got %s: %r' %
- (self.type.__name__,
- type(value).__name__,
- value))
- return value
-
-
-class EnumField(Field):
- """Field definition for enum values.
-
- Enum fields may have default values that are delayed until the associated enum
- type is resolved. This is necessary to support certain circular references.
-
- For example:
-
- class Message1(Message):
-
- class Color(Enum):
-
- RED = 1
- GREEN = 2
- BLUE = 3
-
- # This field default value will be validated when default is accessed.
- animal = EnumField('Message2.Animal', 1, default='HORSE')
-
- class Message2(Message):
-
- class Animal(Enum):
-
- DOG = 1
- CAT = 2
- HORSE = 3
-
- # This fields default value will be validated right away since Color is
- # already fully resolved.
- color = EnumField(Message1.Color, 1, default='RED')
- """
-
- VARIANTS = frozenset([Variant.ENUM])
-
- DEFAULT_VARIANT = Variant.ENUM
-
- def __init__(self, enum_type, number, **kwargs):
- """Constructor.
-
- Args:
- enum_type: Enum type for field. Must be subclass of Enum.
- number: Number of field. Must be unique per message class.
- required: Whether or not field is required. Mutually exclusive to
- 'repeated'.
- repeated: Whether or not field is repeated. Mutually exclusive to
- 'required'.
- variant: Wire-format variant hint.
- default: Default value for field if not found in stream.
-
- Raises:
- FieldDefinitionError when invalid enum_type is provided.
- """
- valid_type = (isinstance(enum_type, six.string_types) or
- (enum_type is not Enum and
- isinstance(enum_type, type) and
- issubclass(enum_type, Enum)))
-
- if not valid_type:
- raise FieldDefinitionError('Invalid enum type: %s' % enum_type)
-
- if isinstance(enum_type, six.string_types):
- self.__type_name = enum_type
- self.__type = None
- else:
- self.__type = enum_type
-
- super(EnumField, self).__init__(number, **kwargs)
-
- def validate_default_element(self, value):
- """Validate default element of Enum field.
-
- Enum fields allow for delayed resolution of default values when the type
- of the field has not been resolved. The default value of a field may be
- a string or an integer. If the Enum type of the field has been resolved,
- the default value is validated against that type.
-
- Args:
- value: Value to validate.
-
- Raises:
- ValidationError if value is not expected message type.
- """
- if isinstance(value, (six.string_types, six.integer_types)):
- # Validation of the value does not happen for delayed resolution
- # enumerated types. Ignore if type is not yet resolved.
- if self.__type:
- self.__type(value)
- return
-
- super(EnumField, self).validate_default_element(value)
-
- @property
- def type(self):
- """Enum type used for field."""
- if self.__type is None:
- found_type = find_definition(self.__type_name, self.message_definition())
- if not (found_type is not Enum and
- isinstance(found_type, type) and
- issubclass(found_type, Enum)):
- raise FieldDefinitionError('Invalid enum type: %s' % found_type)
-
- self.__type = found_type
- return self.__type
-
- @property
- def default(self):
- """Default for enum field.
-
- Will cause resolution of Enum type and unresolved default value.
- """
- try:
- return self.__resolved_default
- except AttributeError:
- resolved_default = super(EnumField, self).default
- if isinstance(resolved_default, (six.string_types, six.integer_types)):
- resolved_default = self.type(resolved_default)
- self.__resolved_default = resolved_default
- return self.__resolved_default
-
-
-@util.positional(2)
-def find_definition(name, relative_to=None, importer=__import__):
- """Find definition by name in module-space.
-
- The find algorthm will look for definitions by name relative to a message
- definition or by fully qualfied name. If no definition is found relative
- to the relative_to parameter it will do the same search against the container
- of relative_to. If relative_to is a nested Message, it will search its
- message_definition(). If that message has no message_definition() it will
- search its module. If relative_to is a module, it will attempt to look for
- the containing module and search relative to it. If the module is a top-level
- module, it will look for the a message using a fully qualified name. If
- no message is found then, the search fails and DefinitionNotFoundError is
- raised.
-
- For example, when looking for any definition 'foo.bar.ADefinition' relative to
- an actual message definition abc.xyz.SomeMessage:
-
- find_definition('foo.bar.ADefinition', SomeMessage)
-
- It is like looking for the following fully qualified names:
-
- abc.xyz.SomeMessage. foo.bar.ADefinition
- abc.xyz. foo.bar.ADefinition
- abc. foo.bar.ADefinition
- foo.bar.ADefinition
-
- When resolving the name relative to Message definitions and modules, the
- algorithm searches any Messages or sub-modules found in its path.
- Non-Message values are not searched.
-
- A name that begins with '.' is considered to be a fully qualified name. The
- name is always searched for from the topmost package. For example, assume
- two message types:
-
- abc.xyz.SomeMessage
- xyz.SomeMessage
-
- Searching for '.xyz.SomeMessage' relative to 'abc' will resolve to
- 'xyz.SomeMessage' and not 'abc.xyz.SomeMessage'. For this kind of name,
- the relative_to parameter is effectively ignored and always set to None.
-
- For more information about package name resolution, please see:
-
- http://code.google.com/apis/protocolbuffers/docs/proto.html#packages
-
- Args:
- name: Name of definition to find. May be fully qualified or relative name.
- relative_to: Search for definition relative to message definition or module.
- None will cause a fully qualified name search.
- importer: Import function to use for resolving modules.
-
- Returns:
- Enum or Message class definition associated with name.
-
- Raises:
- DefinitionNotFoundError if no definition is found in any search path.
- """
- # Check parameters.
- if not (relative_to is None or
- isinstance(relative_to, types.ModuleType) or
- isinstance(relative_to, type) and issubclass(relative_to, Message)):
- raise TypeError('relative_to must be None, Message definition or module. '
- 'Found: %s' % relative_to)
-
- name_path = name.split('.')
-
- # Handle absolute path reference.
- if not name_path[0]:
- relative_to = None
- name_path = name_path[1:]
-
- def search_path():
- """Performs a single iteration searching the path from relative_to.
-
- This is the function that searches up the path from a relative object.
-
- fully.qualified.object . relative.or.nested.Definition
- ---------------------------->
- ^
- |
- this part of search --+
-
- Returns:
- Message or Enum at the end of name_path, else None.
- """
- next = relative_to
- for node in name_path:
- # Look for attribute first.
- attribute = getattr(next, node, None)
-
- if attribute is not None:
- next = attribute
- else:
- # If module, look for sub-module.
- if next is None or isinstance(next, types.ModuleType):
- if next is None:
- module_name = node
- else:
- module_name = '%s.%s' % (next.__name__, node)
-
- try:
- fromitem = module_name.split('.')[-1]
- next = importer(module_name, '', '', [str(fromitem)])
- except ImportError:
- return None
- else:
- return None
-
- if (not isinstance(next, types.ModuleType) and
- not (isinstance(next, type) and
- issubclass(next, (Message, Enum)))):
- return None
-
- return next
-
- while True:
- found = search_path()
- if isinstance(found, type) and issubclass(found, (Enum, Message)):
- return found
- else:
- # Find next relative_to to search against.
- #
- # fully.qualified.object . relative.or.nested.Definition
- # <---------------------
- # ^
- # |
- # does this part of search
- if relative_to is None:
- # Fully qualified search was done. Nothing found. Fail.
- raise DefinitionNotFoundError('Could not find definition for %s'
- % (name,))
- else:
- if isinstance(relative_to, types.ModuleType):
- # Find parent module.
- module_path = relative_to.__name__.split('.')[:-1]
- if not module_path:
- relative_to = None
- else:
- # Should not raise ImportError. If it does... weird and
- # unexepected. Propagate.
- relative_to = importer(
- '.'.join(module_path), '', '', [module_path[-1]])
- elif (isinstance(relative_to, type) and
- issubclass(relative_to, Message)):
- parent = relative_to.message_definition()
- if parent is None:
- last_module_name = relative_to.__module__.split('.')[-1]
- relative_to = importer(
- relative_to.__module__, '', '', [last_module_name])
- else:
- relative_to = parent

Powered by Google App Engine
This is Rietveld 408576698