~ubuntu-branches/debian/stretch/protobuf/stretch

« back to all changes in this revision

Viewing changes to python/google/protobuf/message_factory.py

  • Committer: Package Import Robot
  • Author(s): Robert S. Edmonds
  • Date: 2014-09-11 22:50:10 UTC
  • mfrom: (10.1.9 experimental)
  • Revision ID: package-import@ubuntu.com-20140911225010-wt4yo9dpc1fzuq5g
Tags: 2.6.0-3
Upload to unstable.

Show diffs side-by-side

added added

removed removed

Lines of Context:
28
28
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
29
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
30
 
31
 
"""Provides a factory class for generating dynamic messages."""
 
31
#PY25 compatible for GAE.
 
32
#
 
33
# Copyright 2012 Google Inc. All Rights Reserved.
 
34
 
 
35
"""Provides a factory class for generating dynamic messages.
 
36
 
 
37
The easiest way to use this class is if you have access to the FileDescriptor
 
38
protos containing the messages you want to create you can just do the following:
 
39
 
 
40
message_classes = message_factory.GetMessages(iterable_of_file_descriptors)
 
41
my_proto_instance = message_classes['some.proto.package.MessageName']()
 
42
"""
32
43
 
33
44
__author__ = 'matthewtoia@google.com (Matt Toia)'
34
45
 
 
46
import sys  ##PY25
35
47
from google.protobuf import descriptor_database
36
48
from google.protobuf import descriptor_pool
37
49
from google.protobuf import message
41
53
class MessageFactory(object):
42
54
  """Factory for creating Proto2 messages from descriptors in a pool."""
43
55
 
44
 
  def __init__(self):
 
56
  def __init__(self, pool=None):
45
57
    """Initializes a new factory."""
 
58
    self.pool = (pool or descriptor_pool.DescriptorPool(
 
59
        descriptor_database.DescriptorDatabase()))
 
60
 
 
61
    # local cache of all classes built from protobuf descriptors
46
62
    self._classes = {}
47
63
 
48
64
  def GetPrototype(self, descriptor):
57
73
    Returns:
58
74
      A class describing the passed in descriptor.
59
75
    """
60
 
 
61
76
    if descriptor.full_name not in self._classes:
 
77
      descriptor_name = descriptor.name
 
78
      if sys.version_info[0] < 3:  ##PY25
 
79
##!PY25      if str is bytes:  # PY2
 
80
        descriptor_name = descriptor.name.encode('ascii', 'ignore')
62
81
      result_class = reflection.GeneratedProtocolMessageType(
63
 
          descriptor.name.encode('ascii', 'ignore'),
 
82
          descriptor_name,
64
83
          (message.Message,),
65
 
          {'DESCRIPTOR': descriptor})
 
84
          {'DESCRIPTOR': descriptor, '__module__': None})
 
85
          # If module not set, it wrongly points to the reflection.py module.
66
86
      self._classes[descriptor.full_name] = result_class
67
87
      for field in descriptor.fields:
68
88
        if field.message_type:
69
89
          self.GetPrototype(field.message_type)
 
90
      for extension in result_class.DESCRIPTOR.extensions:
 
91
        if extension.containing_type.full_name not in self._classes:
 
92
          self.GetPrototype(extension.containing_type)
 
93
        extended_class = self._classes[extension.containing_type.full_name]
 
94
        extended_class.RegisterExtension(extension)
70
95
    return self._classes[descriptor.full_name]
71
96
 
72
 
 
73
 
_DB = descriptor_database.DescriptorDatabase()
74
 
_POOL = descriptor_pool.DescriptorPool(_DB)
 
97
  def GetMessages(self, files):
 
98
    """Gets all the messages from a specified file.
 
99
 
 
100
    This will find and resolve dependencies, failing if the descriptor
 
101
    pool cannot satisfy them.
 
102
 
 
103
    Args:
 
104
      files: The file names to extract messages from.
 
105
 
 
106
    Returns:
 
107
      A dictionary mapping proto names to the message classes. This will include
 
108
      any dependent messages as well as any messages defined in the same file as
 
109
      a specified message.
 
110
    """
 
111
    result = {}
 
112
    for file_name in files:
 
113
      file_desc = self.pool.FindFileByName(file_name)
 
114
      for name, msg in file_desc.message_types_by_name.iteritems():
 
115
        if file_desc.package:
 
116
          full_name = '.'.join([file_desc.package, name])
 
117
        else:
 
118
          full_name = msg.name
 
119
        result[full_name] = self.GetPrototype(
 
120
            self.pool.FindMessageTypeByName(full_name))
 
121
 
 
122
      # While the extension FieldDescriptors are created by the descriptor pool,
 
123
      # the python classes created in the factory need them to be registered
 
124
      # explicitly, which is done below.
 
125
      #
 
126
      # The call to RegisterExtension will specifically check if the
 
127
      # extension was already registered on the object and either
 
128
      # ignore the registration if the original was the same, or raise
 
129
      # an error if they were different.
 
130
 
 
131
      for name, extension in file_desc.extensions_by_name.iteritems():
 
132
        if extension.containing_type.full_name not in self._classes:
 
133
          self.GetPrototype(extension.containing_type)
 
134
        extended_class = self._classes[extension.containing_type.full_name]
 
135
        extended_class.RegisterExtension(extension)
 
136
    return result
 
137
 
 
138
 
75
139
_FACTORY = MessageFactory()
76
140
 
77
141
 
82
146
    file_protos: A sequence of file protos to build messages out of.
83
147
 
84
148
  Returns:
85
 
    A dictionary containing all the message types in the files mapping the
86
 
    fully qualified name to a Message subclass for the descriptor.
87
 
  """
88
 
 
89
 
  result = {}
90
 
  for file_proto in file_protos:
91
 
    _DB.Add(file_proto)
92
 
  for file_proto in file_protos:
93
 
    for desc in _GetAllDescriptors(file_proto.message_type, file_proto.package):
94
 
      result[desc.full_name] = _FACTORY.GetPrototype(desc)
95
 
  return result
96
 
 
97
 
 
98
 
def _GetAllDescriptors(desc_protos, package):
99
 
  """Gets all levels of nested message types as a flattened list of descriptors.
100
 
 
101
 
  Args:
102
 
    desc_protos: The descriptor protos to process.
103
 
    package: The package where the protos are defined.
104
 
 
105
 
  Yields:
106
 
    Each message descriptor for each nested type.
107
 
  """
108
 
 
109
 
  for desc_proto in desc_protos:
110
 
    name = '.'.join((package, desc_proto.name))
111
 
    yield _POOL.FindMessageTypeByName(name)
112
 
    for nested_desc in _GetAllDescriptors(desc_proto.nested_type, name):
113
 
      yield nested_desc
 
149
    A dictionary mapping proto names to the message classes. This will include
 
150
    any dependent messages as well as any messages defined in the same file as
 
151
    a specified message.
 
152
  """
 
153
  for file_proto in file_protos:
 
154
    _FACTORY.pool.Add(file_proto)
 
155
  return _FACTORY.GetMessages([file_proto.name for file_proto in file_protos])