aboutsummaryrefslogblamecommitdiff
path: root/python/google/protobuf/message.py
blob: 9b48f889900a3ecf63f69c9d07f7e926e0030c06 (plain) (tree)























































































































































































                                                                               
# Protocol Buffers - Google's data interchange format
# Copyright 2008 Google Inc.
# http://code.google.com/p/protobuf/
#
# 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.

# 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)'

from google.protobuf import text_format

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 __eq__(self, other_msg):
    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 __str__(self):
    return text_format.MessageToString(self)

  def MergeFrom(self, other_msg):
    raise NotImplementedError

  def CopyFrom(self, other_msg):
    raise NotImplementedError

  def Clear(self):
    raise NotImplementedError

  def IsInitialized(self):
    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):
    """Like MergeFromString(), except we clear the object first."""
    self.Clear()
    self.MergeFromString(serialized)

  def SerializeToString(self):
    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, field_name):
    """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):
    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