You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			156 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			Python
		
	
			
		
		
	
	
			156 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			Python
		
	
# Protocol Buffers - Google's data interchange format
 | 
						|
# Copyright 2008 Google Inc.  All rights reserved.
 | 
						|
# http://code.google.com/p/protobuf/
 | 
						|
#
 | 
						|
# Redistribution and use in source and binary forms, with or without
 | 
						|
# modification, are permitted provided that the following conditions are
 | 
						|
# met:
 | 
						|
#
 | 
						|
#     * Redistributions of source code must retain the above copyright
 | 
						|
# notice, this list of conditions and the following disclaimer.
 | 
						|
#     * Redistributions in binary form must reproduce the above
 | 
						|
# copyright notice, this list of conditions and the following disclaimer
 | 
						|
# in the documentation and/or other materials provided with the
 | 
						|
# distribution.
 | 
						|
#     * Neither the name of Google Inc. nor the names of its
 | 
						|
# contributors may be used to endorse or promote products derived from
 | 
						|
# this software without specific prior written permission.
 | 
						|
#
 | 
						|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | 
						|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
						|
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | 
						|
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | 
						|
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
						|
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | 
						|
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
						|
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
						|
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
						|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | 
						|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
						|
 | 
						|
#PY25 compatible for GAE.
 | 
						|
#
 | 
						|
# Copyright 2012 Google Inc. All Rights Reserved.
 | 
						|
 | 
						|
"""Provides a factory class for generating dynamic messages.
 | 
						|
 | 
						|
The easiest way to use this class is if you have access to the FileDescriptor
 | 
						|
protos containing the messages you want to create you can just do the following:
 | 
						|
 | 
						|
message_classes = message_factory.GetMessages(iterable_of_file_descriptors)
 | 
						|
my_proto_instance = message_classes['some.proto.package.MessageName']()
 | 
						|
"""
 | 
						|
 | 
						|
__author__ = 'matthewtoia@google.com (Matt Toia)'
 | 
						|
 | 
						|
import sys  ##PY25
 | 
						|
from protobuf26 import descriptor_database
 | 
						|
from protobuf26 import descriptor_pool
 | 
						|
from protobuf26 import message
 | 
						|
from protobuf26 import reflection
 | 
						|
 | 
						|
 | 
						|
class MessageFactory(object):
 | 
						|
  """Factory for creating Proto2 messages from descriptors in a pool."""
 | 
						|
 | 
						|
  def __init__(self, pool=None):
 | 
						|
    """Initializes a new factory."""
 | 
						|
    self.pool = (pool or descriptor_pool.DescriptorPool(
 | 
						|
        descriptor_database.DescriptorDatabase()))
 | 
						|
 | 
						|
    # local cache of all classes built from protobuf descriptors
 | 
						|
    self._classes = {}
 | 
						|
 | 
						|
  def GetPrototype(self, descriptor):
 | 
						|
    """Builds a proto2 message class based on the passed in descriptor.
 | 
						|
 | 
						|
    Passing a descriptor with a fully qualified name matching a previous
 | 
						|
    invocation will cause the same class to be returned.
 | 
						|
 | 
						|
    Args:
 | 
						|
      descriptor: The descriptor to build from.
 | 
						|
 | 
						|
    Returns:
 | 
						|
      A class describing the passed in descriptor.
 | 
						|
    """
 | 
						|
    if descriptor.full_name not in self._classes:
 | 
						|
      descriptor_name = descriptor.name
 | 
						|
      if sys.version_info[0] < 3:  ##PY25
 | 
						|
##!PY25      if str is bytes:  # PY2
 | 
						|
        descriptor_name = descriptor.name.encode('ascii', 'ignore')
 | 
						|
      result_class = reflection.GeneratedProtocolMessageType(
 | 
						|
          descriptor_name,
 | 
						|
          (message.Message,),
 | 
						|
          {'DESCRIPTOR': descriptor, '__module__': None})
 | 
						|
          # If module not set, it wrongly points to the reflection.py module.
 | 
						|
      self._classes[descriptor.full_name] = result_class
 | 
						|
      for field in descriptor.fields:
 | 
						|
        if field.message_type:
 | 
						|
          self.GetPrototype(field.message_type)
 | 
						|
      for extension in result_class.DESCRIPTOR.extensions:
 | 
						|
        if extension.containing_type.full_name not in self._classes:
 | 
						|
          self.GetPrototype(extension.containing_type)
 | 
						|
        extended_class = self._classes[extension.containing_type.full_name]
 | 
						|
        extended_class.RegisterExtension(extension)
 | 
						|
    return self._classes[descriptor.full_name]
 | 
						|
 | 
						|
  def GetMessages(self, files):
 | 
						|
    """Gets all the messages from a specified file.
 | 
						|
 | 
						|
    This will find and resolve dependencies, failing if the descriptor
 | 
						|
    pool cannot satisfy them.
 | 
						|
 | 
						|
    Args:
 | 
						|
      files: The file names to extract messages from.
 | 
						|
 | 
						|
    Returns:
 | 
						|
      A dictionary mapping proto names to the message classes. This will include
 | 
						|
      any dependent messages as well as any messages defined in the same file as
 | 
						|
      a specified message.
 | 
						|
    """
 | 
						|
    result = {}
 | 
						|
    for file_name in files:
 | 
						|
      file_desc = self.pool.FindFileByName(file_name)
 | 
						|
      for name, msg in file_desc.message_types_by_name.iteritems():
 | 
						|
        if file_desc.package:
 | 
						|
          full_name = '.'.join([file_desc.package, name])
 | 
						|
        else:
 | 
						|
          full_name = msg.name
 | 
						|
        result[full_name] = self.GetPrototype(
 | 
						|
            self.pool.FindMessageTypeByName(full_name))
 | 
						|
 | 
						|
      # While the extension FieldDescriptors are created by the descriptor pool,
 | 
						|
      # the python classes created in the factory need them to be registered
 | 
						|
      # explicitly, which is done below.
 | 
						|
      #
 | 
						|
      # The call to RegisterExtension will specifically check if the
 | 
						|
      # extension was already registered on the object and either
 | 
						|
      # ignore the registration if the original was the same, or raise
 | 
						|
      # an error if they were different.
 | 
						|
 | 
						|
      for name, extension in file_desc.extensions_by_name.iteritems():
 | 
						|
        if extension.containing_type.full_name not in self._classes:
 | 
						|
          self.GetPrototype(extension.containing_type)
 | 
						|
        extended_class = self._classes[extension.containing_type.full_name]
 | 
						|
        extended_class.RegisterExtension(extension)
 | 
						|
    return result
 | 
						|
 | 
						|
 | 
						|
_FACTORY = MessageFactory()
 | 
						|
 | 
						|
 | 
						|
def GetMessages(file_protos):
 | 
						|
  """Builds a dictionary of all the messages available in a set of files.
 | 
						|
 | 
						|
  Args:
 | 
						|
    file_protos: A sequence of file protos to build messages out of.
 | 
						|
 | 
						|
  Returns:
 | 
						|
    A dictionary mapping proto names to the message classes. This will include
 | 
						|
    any dependent messages as well as any messages defined in the same file as
 | 
						|
    a specified message.
 | 
						|
  """
 | 
						|
  for file_proto in file_protos:
 | 
						|
    _FACTORY.pool.Add(file_proto)
 | 
						|
  return _FACTORY.GetMessages([file_proto.name for file_proto in file_protos])
 |