1a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# Protocol Buffers - Google's data interchange format 2a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# Copyright 2008 Google Inc. All rights reserved. 3afb4b72037e3f13db208590fc782c4bc8e27f862Jeff Davidson# https://developers.google.com/protocol-buffers/ 4a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# 5a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# Redistribution and use in source and binary forms, with or without 6a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# modification, are permitted provided that the following conditions are 7a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# met: 8a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# 9a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# * Redistributions of source code must retain the above copyright 10a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# notice, this list of conditions and the following disclaimer. 11a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# * Redistributions in binary form must reproduce the above 12a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# copyright notice, this list of conditions and the following disclaimer 13a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# in the documentation and/or other materials provided with the 14a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# distribution. 15a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# * Neither the name of Google Inc. nor the names of its 16a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# contributors may be used to endorse or promote products derived from 17a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# this software without specific prior written permission. 18a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# 19a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 31a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson#PY25 compatible for GAE. 32a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# 33a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# Copyright 2012 Google Inc. All Rights Reserved. 34a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 35a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson"""Provides a factory class for generating dynamic messages. 36a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 37a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff DavidsonThe easiest way to use this class is if you have access to the FileDescriptor 38a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsonprotos containing the messages you want to create you can just do the following: 39a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 40a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsonmessage_classes = message_factory.GetMessages(iterable_of_file_descriptors) 41a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsonmy_proto_instance = message_classes['some.proto.package.MessageName']() 42a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson""" 43a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 44a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson__author__ = 'matthewtoia@google.com (Matt Toia)' 45a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 46a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsonimport sys ##PY25 47a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsonfrom google.protobuf import descriptor_database 48a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsonfrom google.protobuf import descriptor_pool 49a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsonfrom google.protobuf import message 50a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsonfrom google.protobuf import reflection 51a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 52a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 53a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsonclass MessageFactory(object): 54a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson """Factory for creating Proto2 messages from descriptors in a pool.""" 55a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 56a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson def __init__(self, pool=None): 57a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson """Initializes a new factory.""" 58a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson self.pool = (pool or descriptor_pool.DescriptorPool( 59a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson descriptor_database.DescriptorDatabase())) 60a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 61a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson # local cache of all classes built from protobuf descriptors 62a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson self._classes = {} 63a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 64a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson def GetPrototype(self, descriptor): 65a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson """Builds a proto2 message class based on the passed in descriptor. 66a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 67a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson Passing a descriptor with a fully qualified name matching a previous 68a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson invocation will cause the same class to be returned. 69a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 70a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson Args: 71a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson descriptor: The descriptor to build from. 72a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 73a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson Returns: 74a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson A class describing the passed in descriptor. 75a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson """ 76a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if descriptor.full_name not in self._classes: 77a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson descriptor_name = descriptor.name 78a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if sys.version_info[0] < 3: ##PY25 79a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson##!PY25 if str is bytes: # PY2 80a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson descriptor_name = descriptor.name.encode('ascii', 'ignore') 81a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson result_class = reflection.GeneratedProtocolMessageType( 82a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson descriptor_name, 83a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson (message.Message,), 84a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson {'DESCRIPTOR': descriptor, '__module__': None}) 85a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson # If module not set, it wrongly points to the reflection.py module. 86a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson self._classes[descriptor.full_name] = result_class 87a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson for field in descriptor.fields: 88a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if field.message_type: 89a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson self.GetPrototype(field.message_type) 90a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson for extension in result_class.DESCRIPTOR.extensions: 91a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if extension.containing_type.full_name not in self._classes: 92a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson self.GetPrototype(extension.containing_type) 93a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson extended_class = self._classes[extension.containing_type.full_name] 94a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson extended_class.RegisterExtension(extension) 95a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return self._classes[descriptor.full_name] 96a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 97a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson def GetMessages(self, files): 98a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson """Gets all the messages from a specified file. 99a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 100a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson This will find and resolve dependencies, failing if the descriptor 101a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson pool cannot satisfy them. 102a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 103a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson Args: 104a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson files: The file names to extract messages from. 105a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 106a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson Returns: 107a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson A dictionary mapping proto names to the message classes. This will include 108a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson any dependent messages as well as any messages defined in the same file as 109a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson a specified message. 110a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson """ 111a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson result = {} 112a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson for file_name in files: 113a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson file_desc = self.pool.FindFileByName(file_name) 114a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson for name, msg in file_desc.message_types_by_name.iteritems(): 115a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if file_desc.package: 116a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson full_name = '.'.join([file_desc.package, name]) 117a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson else: 118a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson full_name = msg.name 119a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson result[full_name] = self.GetPrototype( 120a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson self.pool.FindMessageTypeByName(full_name)) 121a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 122a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson # While the extension FieldDescriptors are created by the descriptor pool, 123a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson # the python classes created in the factory need them to be registered 124a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson # explicitly, which is done below. 125a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson # 126a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson # The call to RegisterExtension will specifically check if the 127a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson # extension was already registered on the object and either 128a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson # ignore the registration if the original was the same, or raise 129a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson # an error if they were different. 130a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 131a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson for name, extension in file_desc.extensions_by_name.iteritems(): 132a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if extension.containing_type.full_name not in self._classes: 133a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson self.GetPrototype(extension.containing_type) 134a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson extended_class = self._classes[extension.containing_type.full_name] 135a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson extended_class.RegisterExtension(extension) 136a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return result 137a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 138a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 139a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson_FACTORY = MessageFactory() 140a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 141a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 142a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsondef GetMessages(file_protos): 143a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson """Builds a dictionary of all the messages available in a set of files. 144a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 145a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson Args: 146a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson file_protos: A sequence of file protos to build messages out of. 147a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 148a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson Returns: 149a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson A dictionary mapping proto names to the message classes. This will include 150a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson any dependent messages as well as any messages defined in the same file as 151a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson a specified message. 152a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson """ 153a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson for file_proto in file_protos: 154a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson _FACTORY.pool.Add(file_proto) 155a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return _FACTORY.GetMessages([file_proto.name for file_proto in file_protos]) 156