Home | History | Annotate | Download | only in protobuf
      1 # Protocol Buffers - Google's data interchange format
      2 # Copyright 2008 Google Inc.  All rights reserved.
      3 # http://code.google.com/p/protobuf/
      4 #
      5 # Redistribution and use in source and binary forms, with or without
      6 # modification, are permitted provided that the following conditions are
      7 # met:
      8 #
      9 #     * Redistributions of source code must retain the above copyright
     10 # notice, this list of conditions and the following disclaimer.
     11 #     * Redistributions in binary form must reproduce the above
     12 # copyright notice, this list of conditions and the following disclaimer
     13 # in the documentation and/or other materials provided with the
     14 # distribution.
     15 #     * Neither the name of Google Inc. nor the names of its
     16 # contributors may be used to endorse or promote products derived from
     17 # this software without specific prior written permission.
     18 #
     19 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     20 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     21 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     22 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     23 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     24 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     25 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     26 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     27 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     28 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     29 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30 
     31 # TODO(robinson): We should just make these methods all "pure-virtual" and move
     32 # all implementation out, into reflection.py for now.
     33 
     34 
     35 """Contains an abstract base class for protocol messages."""
     36 
     37 __author__ = 'robinson (at] google.com (Will Robinson)'
     38 
     39 
     40 class Error(Exception): pass
     41 class DecodeError(Error): pass
     42 class EncodeError(Error): pass
     43 
     44 
     45 class Message(object):
     46 
     47   """Abstract base class for protocol messages.
     48 
     49   Protocol message classes are almost always generated by the protocol
     50   compiler.  These generated types subclass Message and implement the methods
     51   shown below.
     52 
     53   TODO(robinson): Link to an HTML document here.
     54 
     55   TODO(robinson): Document that instances of this class will also
     56   have an Extensions attribute with __getitem__ and __setitem__.
     57   Again, not sure how to best convey this.
     58 
     59   TODO(robinson): Document that the class must also have a static
     60     RegisterExtension(extension_field) method.
     61     Not sure how to best express at this point.
     62   """
     63 
     64   # TODO(robinson): Document these fields and methods.
     65 
     66   __slots__ = []
     67 
     68   DESCRIPTOR = None
     69 
     70   def __eq__(self, other_msg):
     71     raise NotImplementedError
     72 
     73   def __ne__(self, other_msg):
     74     # Can't just say self != other_msg, since that would infinitely recurse. :)
     75     return not self == other_msg
     76 
     77   def __str__(self):
     78     raise NotImplementedError
     79 
     80   def MergeFrom(self, other_msg):
     81     """Merges the contents of the specified message into current message.
     82 
     83     This method merges the contents of the specified message into the current
     84     message. Singular fields that are set in the specified message overwrite
     85     the corresponding fields in the current message. Repeated fields are
     86     appended. Singular sub-messages and groups are recursively merged.
     87 
     88     Args:
     89       other_msg: Message to merge into the current message.
     90     """
     91     raise NotImplementedError
     92 
     93   def CopyFrom(self, other_msg):
     94     """Copies the content of the specified message into the current message.
     95 
     96     The method clears the current message and then merges the specified
     97     message using MergeFrom.
     98 
     99     Args:
    100       other_msg: Message to copy into the current one.
    101     """
    102     if self is other_msg:
    103       return
    104     self.Clear()
    105     self.MergeFrom(other_msg)
    106 
    107   def Clear(self):
    108     """Clears all data that was set in the message."""
    109     raise NotImplementedError
    110 
    111   def SetInParent(self):
    112     """Mark this as present in the parent.
    113 
    114     This normally happens automatically when you assign a field of a
    115     sub-message, but sometimes you want to make the sub-message
    116     present while keeping it empty.  If you find yourself using this,
    117     you may want to reconsider your design."""
    118     raise NotImplementedError
    119 
    120   def IsInitialized(self):
    121     """Checks if the message is initialized.
    122 
    123     Returns:
    124       The method returns True if the message is initialized (i.e. all of its
    125       required fields are set).
    126     """
    127     raise NotImplementedError
    128 
    129   # TODO(robinson): MergeFromString() should probably return None and be
    130   # implemented in terms of a helper that returns the # of bytes read.  Our
    131   # deserialization routines would use the helper when recursively
    132   # deserializing, but the end user would almost always just want the no-return
    133   # MergeFromString().
    134 
    135   def MergeFromString(self, serialized):
    136     """Merges serialized protocol buffer data into this message.
    137 
    138     When we find a field in |serialized| that is already present
    139     in this message:
    140       - If it's a "repeated" field, we append to the end of our list.
    141       - Else, if it's a scalar, we overwrite our field.
    142       - Else, (it's a nonrepeated composite), we recursively merge
    143         into the existing composite.
    144 
    145     TODO(robinson): Document handling of unknown fields.
    146 
    147     Args:
    148       serialized: Any object that allows us to call buffer(serialized)
    149         to access a string of bytes using the buffer interface.
    150 
    151     TODO(robinson): When we switch to a helper, this will return None.
    152 
    153     Returns:
    154       The number of bytes read from |serialized|.
    155       For non-group messages, this will always be len(serialized),
    156       but for messages which are actually groups, this will
    157       generally be less than len(serialized), since we must
    158       stop when we reach an END_GROUP tag.  Note that if
    159       we *do* stop because of an END_GROUP tag, the number
    160       of bytes returned does not include the bytes
    161       for the END_GROUP tag information.
    162     """
    163     raise NotImplementedError
    164 
    165   def ParseFromString(self, serialized):
    166     """Like MergeFromString(), except we clear the object first."""
    167     self.Clear()
    168     self.MergeFromString(serialized)
    169 
    170   def SerializeToString(self):
    171     """Serializes the protocol message to a binary string.
    172 
    173     Returns:
    174       A binary string representation of the message if all of the required
    175       fields in the message are set (i.e. the message is initialized).
    176 
    177     Raises:
    178       message.EncodeError if the message isn't initialized.
    179     """
    180     raise NotImplementedError
    181 
    182   def SerializePartialToString(self):
    183     """Serializes the protocol message to a binary string.
    184 
    185     This method is similar to SerializeToString but doesn't check if the
    186     message is initialized.
    187 
    188     Returns:
    189       A string representation of the partial message.
    190     """
    191     raise NotImplementedError
    192 
    193   # TODO(robinson): Decide whether we like these better
    194   # than auto-generated has_foo() and clear_foo() methods
    195   # on the instances themselves.  This way is less consistent
    196   # with C++, but it makes reflection-type access easier and
    197   # reduces the number of magically autogenerated things.
    198   #
    199   # TODO(robinson): Be sure to document (and test) exactly
    200   # which field names are accepted here.  Are we case-sensitive?
    201   # What do we do with fields that share names with Python keywords
    202   # like 'lambda' and 'yield'?
    203   #
    204   # nnorwitz says:
    205   # """
    206   # Typically (in python), an underscore is appended to names that are
    207   # keywords. So they would become lambda_ or yield_.
    208   # """
    209   def ListFields(self):
    210     """Returns a list of (FieldDescriptor, value) tuples for all
    211     fields in the message which are not empty.  A singular field is non-empty
    212     if HasField() would return true, and a repeated field is non-empty if
    213     it contains at least one element.  The fields are ordered by field
    214     number"""
    215     raise NotImplementedError
    216 
    217   def HasField(self, field_name):
    218     raise NotImplementedError
    219 
    220   def ClearField(self, field_name):
    221     raise NotImplementedError
    222 
    223   def HasExtension(self, extension_handle):
    224     raise NotImplementedError
    225 
    226   def ClearExtension(self, extension_handle):
    227     raise NotImplementedError
    228 
    229   def ByteSize(self):
    230     """Returns the serialized size of this message.
    231     Recursively calls ByteSize() on all contained messages.
    232     """
    233     raise NotImplementedError
    234 
    235   def _SetListener(self, message_listener):
    236     """Internal method used by the protocol message implementation.
    237     Clients should not call this directly.
    238 
    239     Sets a listener that this message will call on certain state transitions.
    240 
    241     The purpose of this method is to register back-edges from children to
    242     parents at runtime, for the purpose of setting "has" bits and
    243     byte-size-dirty bits in the parent and ancestor objects whenever a child or
    244     descendant object is modified.
    245 
    246     If the client wants to disconnect this Message from the object tree, she
    247     explicitly sets callback to None.
    248 
    249     If message_listener is None, unregisters any existing listener.  Otherwise,
    250     message_listener must implement the MessageListener interface in
    251     internal/message_listener.py, and we discard any listener registered
    252     via a previous _SetListener() call.
    253     """
    254     raise NotImplementedError
    255