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.
31
"""Provides a factory class for generating dynamic messages."""
31
#PY25 compatible for GAE.
33
# Copyright 2012 Google Inc. All Rights Reserved.
35
"""Provides a factory class for generating dynamic messages.
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:
40
message_classes = message_factory.GetMessages(iterable_of_file_descriptors)
41
my_proto_instance = message_classes['some.proto.package.MessageName']()
33
44
__author__ = 'matthewtoia@google.com (Matt Toia)'
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."""
56
def __init__(self, pool=None):
45
57
"""Initializes a new factory."""
58
self.pool = (pool or descriptor_pool.DescriptorPool(
59
descriptor_database.DescriptorDatabase()))
61
# local cache of all classes built from protobuf descriptors
48
64
def GetPrototype(self, descriptor):
58
74
A class describing the passed in descriptor.
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'),
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]
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.
100
This will find and resolve dependencies, failing if the descriptor
101
pool cannot satisfy them.
104
files: The file names to extract messages from.
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
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])
119
result[full_name] = self.GetPrototype(
120
self.pool.FindMessageTypeByName(full_name))
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.
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.
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)
75
139
_FACTORY = MessageFactory()
82
146
file_protos: A sequence of file protos to build messages out of.
85
A dictionary containing all the message types in the files mapping the
86
fully qualified name to a Message subclass for the descriptor.
90
for file_proto in file_protos:
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)
98
def _GetAllDescriptors(desc_protos, package):
99
"""Gets all levels of nested message types as a flattened list of descriptors.
102
desc_protos: The descriptor protos to process.
103
package: The package where the protos are defined.
106
Each message descriptor for each nested type.
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):
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
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])