17e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# Protocol Buffers - Google's data interchange format 27e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# Copyright 2008 Google Inc. All rights reserved. 37e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# http://code.google.com/p/protobuf/ 47e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# 57e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# Redistribution and use in source and binary forms, with or without 67e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# modification, are permitted provided that the following conditions are 77e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# met: 87e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# 97e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# * Redistributions of source code must retain the above copyright 107e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# notice, this list of conditions and the following disclaimer. 117e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# * Redistributions in binary form must reproduce the above 127e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# copyright notice, this list of conditions and the following disclaimer 137e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# in the documentation and/or other materials provided with the 147e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# distribution. 157e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# * Neither the name of Google Inc. nor the names of its 167e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# contributors may be used to endorse or promote products derived from 177e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# this software without specific prior written permission. 187e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# 197e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 207e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 217e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 227e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 237e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 247e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 257e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 267e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 277e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 287e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 297e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 307e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang 317e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# This code is meant to work on Python 2.4 and above only. 327e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang 337e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang"""Contains a metaclass and helper functions used to create 347e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wangprotocol message classes from Descriptor objects at runtime. 357e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang 367e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing WangRecall that a metaclass is the "type" of a class. 377e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang(A class is to a metaclass what an instance is to a class.) 387e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang 397e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing WangIn this case, we use the GeneratedProtocolMessageType metaclass 407e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wangto inject all the useful functionality into the classes 417e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wangoutput by the protocol compiler at compile-time. 427e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang 437e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing WangThe upshot of all this is that the real implementation 447e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wangdetails for ALL pure-Python protocol buffers are *here in 457e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wangthis file*. 467e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang""" 477e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang 487e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang__author__ = 'robinson@google.com (Will Robinson)' 497e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang 507e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang 517e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wangfrom google.protobuf.internal import api_implementation 527e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wangfrom google.protobuf import descriptor as descriptor_mod 537e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wangfrom google.protobuf import message 547e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang 557e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang_FieldDescriptor = descriptor_mod.FieldDescriptor 567e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang 577e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang 587e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wangif api_implementation.Type() == 'cpp': 597e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang if api_implementation.Version() == 2: 607e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang from google.protobuf.internal.cpp import cpp_message 617e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang _NewMessage = cpp_message.NewMessage 627e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang _InitMessage = cpp_message.InitMessage 637e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang else: 647e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang from google.protobuf.internal import cpp_message 657e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang _NewMessage = cpp_message.NewMessage 667e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang _InitMessage = cpp_message.InitMessage 677e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wangelse: 687e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang from google.protobuf.internal import python_message 697e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang _NewMessage = python_message.NewMessage 707e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang _InitMessage = python_message.InitMessage 717e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang 727e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang 737e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wangclass GeneratedProtocolMessageType(type): 747e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang 757e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang """Metaclass for protocol message classes created at runtime from Descriptors. 767e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang 777e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang We add implementations for all methods described in the Message class. We 787e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang also create properties to allow getting/setting all fields in the protocol 797e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang message. Finally, we create slots to prevent users from accidentally 807e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang "setting" nonexistent fields in the protocol message, which then wouldn't get 817e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang serialized / deserialized properly. 827e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang 837e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang The protocol compiler currently uses this metaclass to create protocol 847e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang message classes at runtime. Clients can also manually create their own 857e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang classes at runtime, as in this example: 867e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang 877e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang mydescriptor = Descriptor(.....) 887e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang class MyProtoClass(Message): 897e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang __metaclass__ = GeneratedProtocolMessageType 907e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang DESCRIPTOR = mydescriptor 917e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang myproto_instance = MyProtoClass() 927e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang myproto.foo_field = 23 937e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang ... 947e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang """ 957e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang 967e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang # Must be consistent with the protocol-compiler code in 977e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang # proto2/compiler/internal/generator.*. 987e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang _DESCRIPTOR_KEY = 'DESCRIPTOR' 997e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang 1007e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang def __new__(cls, name, bases, dictionary): 1017e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang """Custom allocation for runtime-generated class types. 1027e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang 1037e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang We override __new__ because this is apparently the only place 1047e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang where we can meaningfully set __slots__ on the class we're creating(?). 1057e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang (The interplay between metaclasses and slots is not very well-documented). 1067e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang 1077e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang Args: 1087e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang name: Name of the class (ignored, but required by the 1097e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang metaclass protocol). 1107e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang bases: Base classes of the class we're constructing. 1117e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang (Should be message.Message). We ignore this field, but 1127e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang it's required by the metaclass protocol 1137e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang dictionary: The class dictionary of the class we're 1147e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang constructing. dictionary[_DESCRIPTOR_KEY] must contain 1157e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang a Descriptor object describing this protocol message 1167e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang type. 1177e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang 1187e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang Returns: 1197e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang Newly-allocated class. 1207e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang """ 1217e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang descriptor = dictionary[GeneratedProtocolMessageType._DESCRIPTOR_KEY] 1227e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang bases = _NewMessage(bases, descriptor, dictionary) 1237e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang superclass = super(GeneratedProtocolMessageType, cls) 1247e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang 1257e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang new_class = superclass.__new__(cls, name, bases, dictionary) 1267e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang setattr(descriptor, '_concrete_class', new_class) 1277e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang return new_class 1287e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang 1297e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang def __init__(cls, name, bases, dictionary): 1307e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang """Here we perform the majority of our work on the class. 1317e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang We add enum getters, an __init__ method, implementations 1327e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang of all Message methods, and properties for all fields 1337e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang in the protocol type. 1347e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang 1357e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang Args: 1367e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang name: Name of the class (ignored, but required by the 1377e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang metaclass protocol). 1387e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang bases: Base classes of the class we're constructing. 1397e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang (Should be message.Message). We ignore this field, but 1407e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang it's required by the metaclass protocol 1417e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang dictionary: The class dictionary of the class we're 1427e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang constructing. dictionary[_DESCRIPTOR_KEY] must contain 1437e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang a Descriptor object describing this protocol message 1447e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang type. 1457e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang """ 1467e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang descriptor = dictionary[GeneratedProtocolMessageType._DESCRIPTOR_KEY] 1477e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang _InitMessage(descriptor, cls) 1487e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang superclass = super(GeneratedProtocolMessageType, cls) 1497e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang superclass.__init__(name, bases, dictionary) 1507e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang 1517e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang 1527e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wangdef ParseMessage(descriptor, byte_str): 1537e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang """Generate a new Message instance from this Descriptor and a byte string. 1547e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang 1557e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang Args: 1567e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang descriptor: Protobuf Descriptor object 1577e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang byte_str: Serialized protocol buffer byte string 1587e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang 1597e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang Returns: 1607e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang Newly created protobuf Message object. 1617e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang """ 1627e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang 1637e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang class _ResultClass(message.Message): 1647e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang __metaclass__ = GeneratedProtocolMessageType 1657e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang DESCRIPTOR = descriptor 1667e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang 1677e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang new_msg = _ResultClass() 1687e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang new_msg.ParseFromString(byte_str) 1697e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang return new_msg 170