You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			285 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Python
		
	
			
		
		
	
	
			285 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Python
		
	
# Protocol Buffers - Google's data interchange format
 | 
						|
# Copyright 2008 Google Inc.  All rights reserved.
 | 
						|
# 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
 | 
						|
# met:
 | 
						|
#
 | 
						|
#     * Redistributions of source code must retain the above copyright
 | 
						|
# notice, this list of conditions and the following disclaimer.
 | 
						|
#     * Redistributions in binary form must reproduce the above
 | 
						|
# copyright notice, this list of conditions and the following disclaimer
 | 
						|
# in the documentation and/or other materials provided with the
 | 
						|
# distribution.
 | 
						|
#     * Neither the name of Google Inc. nor the names of its
 | 
						|
# contributors may be used to endorse or promote products derived from
 | 
						|
# this software without specific prior written permission.
 | 
						|
#
 | 
						|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | 
						|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
						|
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | 
						|
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | 
						|
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
						|
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | 
						|
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
						|
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
						|
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
						|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | 
						|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
						|
 | 
						|
# TODO(robinson): We should just make these methods all "pure-virtual" and move
 | 
						|
# all implementation out, into reflection.py for now.
 | 
						|
 | 
						|
 | 
						|
"""Contains an abstract base class for protocol messages."""
 | 
						|
 | 
						|
__author__ = 'robinson@google.com (Will Robinson)'
 | 
						|
 | 
						|
 | 
						|
class Error(Exception): pass
 | 
						|
class DecodeError(Error): pass
 | 
						|
class EncodeError(Error): pass
 | 
						|
 | 
						|
 | 
						|
class Message(object):
 | 
						|
 | 
						|
  """Abstract base class for protocol messages.
 | 
						|
 | 
						|
  Protocol message classes are almost always generated by the protocol
 | 
						|
  compiler.  These generated types subclass Message and implement the methods
 | 
						|
  shown below.
 | 
						|
 | 
						|
  TODO(robinson): Link to an HTML document here.
 | 
						|
 | 
						|
  TODO(robinson): Document that instances of this class will also
 | 
						|
  have an Extensions attribute with __getitem__ and __setitem__.
 | 
						|
  Again, not sure how to best convey this.
 | 
						|
 | 
						|
  TODO(robinson): Document that the class must also have a static
 | 
						|
    RegisterExtension(extension_field) method.
 | 
						|
    Not sure how to best express at this point.
 | 
						|
  """
 | 
						|
 | 
						|
  # TODO(robinson): Document these fields and methods.
 | 
						|
 | 
						|
  __slots__ = []
 | 
						|
 | 
						|
  DESCRIPTOR = None
 | 
						|
 | 
						|
  def __deepcopy__(self, memo=None):
 | 
						|
    clone = type(self)()
 | 
						|
    clone.MergeFrom(self)
 | 
						|
    return clone
 | 
						|
 | 
						|
  def __eq__(self, other_msg):
 | 
						|
    """Recursively compares two messages by value and structure."""
 | 
						|
    raise NotImplementedError
 | 
						|
 | 
						|
  def __ne__(self, other_msg):
 | 
						|
    # Can't just say self != other_msg, since that would infinitely recurse. :)
 | 
						|
    return not self == other_msg
 | 
						|
 | 
						|
  def __hash__(self):
 | 
						|
    raise TypeError('unhashable object')
 | 
						|
 | 
						|
  def __str__(self):
 | 
						|
    """Outputs a human-readable representation of the message."""
 | 
						|
    raise NotImplementedError
 | 
						|
 | 
						|
  def __unicode__(self):
 | 
						|
    """Outputs a human-readable representation of the message."""
 | 
						|
    raise NotImplementedError
 | 
						|
 | 
						|
  def MergeFrom(self, other_msg):
 | 
						|
    """Merges the contents of the specified message into current message.
 | 
						|
 | 
						|
    This method merges the contents of the specified message into the current
 | 
						|
    message. Singular fields that are set in the specified message overwrite
 | 
						|
    the corresponding fields in the current message. Repeated fields are
 | 
						|
    appended. Singular sub-messages and groups are recursively merged.
 | 
						|
 | 
						|
    Args:
 | 
						|
      other_msg: Message to merge into the current message.
 | 
						|
    """
 | 
						|
    raise NotImplementedError
 | 
						|
 | 
						|
  def CopyFrom(self, other_msg):
 | 
						|
    """Copies the content of the specified message into the current message.
 | 
						|
 | 
						|
    The method clears the current message and then merges the specified
 | 
						|
    message using MergeFrom.
 | 
						|
 | 
						|
    Args:
 | 
						|
      other_msg: Message to copy into the current one.
 | 
						|
    """
 | 
						|
    if self is other_msg:
 | 
						|
      return
 | 
						|
    self.Clear()
 | 
						|
    self.MergeFrom(other_msg)
 | 
						|
 | 
						|
  def Clear(self):
 | 
						|
    """Clears all data that was set in the message."""
 | 
						|
    raise NotImplementedError
 | 
						|
 | 
						|
  def SetInParent(self):
 | 
						|
    """Mark this as present in the parent.
 | 
						|
 | 
						|
    This normally happens automatically when you assign a field of a
 | 
						|
    sub-message, but sometimes you want to make the sub-message
 | 
						|
    present while keeping it empty.  If you find yourself using this,
 | 
						|
    you may want to reconsider your design."""
 | 
						|
    raise NotImplementedError
 | 
						|
 | 
						|
  def IsInitialized(self):
 | 
						|
    """Checks if the message is initialized.
 | 
						|
 | 
						|
    Returns:
 | 
						|
      The method returns True if the message is initialized (i.e. all of its
 | 
						|
      required fields are set).
 | 
						|
    """
 | 
						|
    raise NotImplementedError
 | 
						|
 | 
						|
  # TODO(robinson): MergeFromString() should probably return None and be
 | 
						|
  # implemented in terms of a helper that returns the # of bytes read.  Our
 | 
						|
  # deserialization routines would use the helper when recursively
 | 
						|
  # deserializing, but the end user would almost always just want the no-return
 | 
						|
  # MergeFromString().
 | 
						|
 | 
						|
  def MergeFromString(self, serialized):
 | 
						|
    """Merges serialized protocol buffer data into this message.
 | 
						|
 | 
						|
    When we find a field in |serialized| that is already present
 | 
						|
    in this message:
 | 
						|
      - If it's a "repeated" field, we append to the end of our list.
 | 
						|
      - Else, if it's a scalar, we overwrite our field.
 | 
						|
      - Else, (it's a nonrepeated composite), we recursively merge
 | 
						|
        into the existing composite.
 | 
						|
 | 
						|
    TODO(robinson): Document handling of unknown fields.
 | 
						|
 | 
						|
    Args:
 | 
						|
      serialized: Any object that allows us to call buffer(serialized)
 | 
						|
        to access a string of bytes using the buffer interface.
 | 
						|
 | 
						|
    TODO(robinson): When we switch to a helper, this will return None.
 | 
						|
 | 
						|
    Returns:
 | 
						|
      The number of bytes read from |serialized|.
 | 
						|
      For non-group messages, this will always be len(serialized),
 | 
						|
      but for messages which are actually groups, this will
 | 
						|
      generally be less than len(serialized), since we must
 | 
						|
      stop when we reach an END_GROUP tag.  Note that if
 | 
						|
      we *do* stop because of an END_GROUP tag, the number
 | 
						|
      of bytes returned does not include the bytes
 | 
						|
      for the END_GROUP tag information.
 | 
						|
    """
 | 
						|
    raise NotImplementedError
 | 
						|
 | 
						|
  def ParseFromString(self, serialized):
 | 
						|
    """Parse serialized protocol buffer data into this message.
 | 
						|
 | 
						|
    Like MergeFromString(), except we clear the object first and
 | 
						|
    do not return the value that MergeFromString returns.
 | 
						|
    """
 | 
						|
    self.Clear()
 | 
						|
    self.MergeFromString(serialized)
 | 
						|
 | 
						|
  def SerializeToString(self):
 | 
						|
    """Serializes the protocol message to a binary string.
 | 
						|
 | 
						|
    Returns:
 | 
						|
      A binary string representation of the message if all of the required
 | 
						|
      fields in the message are set (i.e. the message is initialized).
 | 
						|
 | 
						|
    Raises:
 | 
						|
      message.EncodeError if the message isn't initialized.
 | 
						|
    """
 | 
						|
    raise NotImplementedError
 | 
						|
 | 
						|
  def SerializePartialToString(self):
 | 
						|
    """Serializes the protocol message to a binary string.
 | 
						|
 | 
						|
    This method is similar to SerializeToString but doesn't check if the
 | 
						|
    message is initialized.
 | 
						|
 | 
						|
    Returns:
 | 
						|
      A string representation of the partial message.
 | 
						|
    """
 | 
						|
    raise NotImplementedError
 | 
						|
 | 
						|
  # TODO(robinson): Decide whether we like these better
 | 
						|
  # than auto-generated has_foo() and clear_foo() methods
 | 
						|
  # on the instances themselves.  This way is less consistent
 | 
						|
  # with C++, but it makes reflection-type access easier and
 | 
						|
  # reduces the number of magically autogenerated things.
 | 
						|
  #
 | 
						|
  # TODO(robinson): Be sure to document (and test) exactly
 | 
						|
  # which field names are accepted here.  Are we case-sensitive?
 | 
						|
  # What do we do with fields that share names with Python keywords
 | 
						|
  # like 'lambda' and 'yield'?
 | 
						|
  #
 | 
						|
  # nnorwitz says:
 | 
						|
  # """
 | 
						|
  # Typically (in python), an underscore is appended to names that are
 | 
						|
  # keywords. So they would become lambda_ or yield_.
 | 
						|
  # """
 | 
						|
  def ListFields(self):
 | 
						|
    """Returns a list of (FieldDescriptor, value) tuples for all
 | 
						|
    fields in the message which are not empty.  A singular field is non-empty
 | 
						|
    if HasField() would return true, and a repeated field is non-empty if
 | 
						|
    it contains at least one element.  The fields are ordered by field
 | 
						|
    number"""
 | 
						|
    raise NotImplementedError
 | 
						|
 | 
						|
  def HasField(self, field_name):
 | 
						|
    """Checks if a certain field is set for the message. Note if the
 | 
						|
    field_name is not defined in the message descriptor, ValueError will be
 | 
						|
    raised."""
 | 
						|
    raise NotImplementedError
 | 
						|
 | 
						|
  def ClearField(self, field_name):
 | 
						|
    raise NotImplementedError
 | 
						|
 | 
						|
  def HasExtension(self, extension_handle):
 | 
						|
    raise NotImplementedError
 | 
						|
 | 
						|
  def ClearExtension(self, extension_handle):
 | 
						|
    raise NotImplementedError
 | 
						|
 | 
						|
  def ByteSize(self):
 | 
						|
    """Returns the serialized size of this message.
 | 
						|
    Recursively calls ByteSize() on all contained messages.
 | 
						|
    """
 | 
						|
    raise NotImplementedError
 | 
						|
 | 
						|
  def _SetListener(self, message_listener):
 | 
						|
    """Internal method used by the protocol message implementation.
 | 
						|
    Clients should not call this directly.
 | 
						|
 | 
						|
    Sets a listener that this message will call on certain state transitions.
 | 
						|
 | 
						|
    The purpose of this method is to register back-edges from children to
 | 
						|
    parents at runtime, for the purpose of setting "has" bits and
 | 
						|
    byte-size-dirty bits in the parent and ancestor objects whenever a child or
 | 
						|
    descendant object is modified.
 | 
						|
 | 
						|
    If the client wants to disconnect this Message from the object tree, she
 | 
						|
    explicitly sets callback to None.
 | 
						|
 | 
						|
    If message_listener is None, unregisters any existing listener.  Otherwise,
 | 
						|
    message_listener must implement the MessageListener interface in
 | 
						|
    internal/message_listener.py, and we discard any listener registered
 | 
						|
    via a previous _SetListener() call.
 | 
						|
    """
 | 
						|
    raise NotImplementedError
 | 
						|
 | 
						|
  def __getstate__(self):
 | 
						|
    """Support the pickle protocol."""
 | 
						|
    return dict(serialized=self.SerializePartialToString())
 | 
						|
 | 
						|
  def __setstate__(self, state):
 | 
						|
    """Support the pickle protocol."""
 | 
						|
    self.__init__()
 | 
						|
    self.ParseFromString(state['serialized'])
 |