Home | History | Annotate | Download | only in protobuf
      1 # Protocol Buffers - Google's data interchange format
      2 # Copyright 2008 Google Inc.  All rights reserved.
      3 # https://developers.google.com/protocol-buffers/
      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 # This code is meant to work on Python 2.4 and above only.
     32 
     33 """Contains a metaclass and helper functions used to create
     34 protocol message classes from Descriptor objects at runtime.
     35 
     36 Recall that a metaclass is the "type" of a class.
     37 (A class is to a metaclass what an instance is to a class.)
     38 
     39 In this case, we use the GeneratedProtocolMessageType metaclass
     40 to inject all the useful functionality into the classes
     41 output by the protocol compiler at compile-time.
     42 
     43 The upshot of all this is that the real implementation
     44 details for ALL pure-Python protocol buffers are *here in
     45 this file*.
     46 """
     47 
     48 __author__ = 'robinson (at] google.com (Will Robinson)'
     49 
     50 
     51 from google.protobuf.internal import api_implementation
     52 from google.protobuf import message
     53 
     54 
     55 if api_implementation.Type() == 'cpp':
     56   from google.protobuf.pyext import cpp_message as message_impl
     57 else:
     58   from google.protobuf.internal import python_message as message_impl
     59 
     60 # The type of all Message classes.
     61 # Part of the public interface.
     62 #
     63 # Used by generated files, but clients can also use it at runtime:
     64 #   mydescriptor = pool.FindDescriptor(.....)
     65 #   class MyProtoClass(Message):
     66 #     __metaclass__ = GeneratedProtocolMessageType
     67 #     DESCRIPTOR = mydescriptor
     68 GeneratedProtocolMessageType = message_impl.GeneratedProtocolMessageType
     69 
     70 
     71 def ParseMessage(descriptor, byte_str):
     72   """Generate a new Message instance from this Descriptor and a byte string.
     73 
     74   Args:
     75     descriptor: Protobuf Descriptor object
     76     byte_str: Serialized protocol buffer byte string
     77 
     78   Returns:
     79     Newly created protobuf Message object.
     80   """
     81   result_class = MakeClass(descriptor)
     82   new_msg = result_class()
     83   new_msg.ParseFromString(byte_str)
     84   return new_msg
     85 
     86 
     87 def MakeClass(descriptor):
     88   """Construct a class object for a protobuf described by descriptor.
     89 
     90   Composite descriptors are handled by defining the new class as a member of the
     91   parent class, recursing as deep as necessary.
     92   This is the dynamic equivalent to:
     93 
     94   class Parent(message.Message):
     95     __metaclass__ = GeneratedProtocolMessageType
     96     DESCRIPTOR = descriptor
     97     class Child(message.Message):
     98       __metaclass__ = GeneratedProtocolMessageType
     99       DESCRIPTOR = descriptor.nested_types[0]
    100 
    101   Sample usage:
    102     file_descriptor = descriptor_pb2.FileDescriptorProto()
    103     file_descriptor.ParseFromString(proto2_string)
    104     msg_descriptor = descriptor.MakeDescriptor(file_descriptor.message_type[0])
    105     msg_class = reflection.MakeClass(msg_descriptor)
    106     msg = msg_class()
    107 
    108   Args:
    109     descriptor: A descriptor.Descriptor object describing the protobuf.
    110   Returns:
    111     The Message class object described by the descriptor.
    112   """
    113   attributes = {}
    114   for name, nested_type in descriptor.nested_types_by_name.items():
    115     attributes[name] = MakeClass(nested_type)
    116 
    117   attributes[GeneratedProtocolMessageType._DESCRIPTOR_KEY] = descriptor
    118 
    119   return GeneratedProtocolMessageType(str(descriptor.name), (message.Message,),
    120                                       attributes)
    121