Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/google/protobuf/message_factory.py: 27%
67 statements
« prev ^ index » next coverage.py v7.3.2, created at 2023-12-08 06:40 +0000
« prev ^ index » next coverage.py v7.3.2, created at 2023-12-08 06:40 +0000
1# Protocol Buffers - Google's data interchange format
2# Copyright 2008 Google Inc. All rights reserved.
3#
4# Use of this source code is governed by a BSD-style
5# license that can be found in the LICENSE file or at
6# https://developers.google.com/open-source/licenses/bsd
8"""Provides a factory class for generating dynamic messages.
10The easiest way to use this class is if you have access to the FileDescriptor
11protos containing the messages you want to create you can just do the following:
13message_classes = message_factory.GetMessages(iterable_of_file_descriptors)
14my_proto_instance = message_classes['some.proto.package.MessageName']()
15"""
17__author__ = 'matthewtoia@google.com (Matt Toia)'
19import warnings
21from google.protobuf.internal import api_implementation
22from google.protobuf import descriptor_pool
23from google.protobuf import message
25if api_implementation.Type() == 'python':
26 from google.protobuf.internal import python_message as message_impl
27else:
28 from google.protobuf.pyext import cpp_message as message_impl # pylint: disable=g-import-not-at-top
31# The type of all Message classes.
32_GENERATED_PROTOCOL_MESSAGE_TYPE = message_impl.GeneratedProtocolMessageType
35def GetMessageClass(descriptor):
36 """Obtains a proto2 message class based on the passed in descriptor.
38 Passing a descriptor with a fully qualified name matching a previous
39 invocation will cause the same class to be returned.
41 Args:
42 descriptor: The descriptor to build from.
44 Returns:
45 A class describing the passed in descriptor.
46 """
47 concrete_class = getattr(descriptor, '_concrete_class', None)
48 if concrete_class:
49 return concrete_class
50 return _InternalCreateMessageClass(descriptor)
53def GetMessageClassesForFiles(files, pool):
54 """Gets all the messages from specified files.
56 This will find and resolve dependencies, failing if the descriptor
57 pool cannot satisfy them.
59 Args:
60 files: The file names to extract messages from.
61 pool: The descriptor pool to find the files including the dependent
62 files.
64 Returns:
65 A dictionary mapping proto names to the message classes.
66 """
67 result = {}
68 for file_name in files:
69 file_desc = pool.FindFileByName(file_name)
70 for desc in file_desc.message_types_by_name.values():
71 result[desc.full_name] = GetMessageClass(desc)
73 # While the extension FieldDescriptors are created by the descriptor pool,
74 # the python classes created in the factory need them to be registered
75 # explicitly, which is done below.
76 #
77 # The call to RegisterExtension will specifically check if the
78 # extension was already registered on the object and either
79 # ignore the registration if the original was the same, or raise
80 # an error if they were different.
82 for extension in file_desc.extensions_by_name.values():
83 extended_class = GetMessageClass(extension.containing_type)
84 if api_implementation.Type() != 'python':
85 # TODO: Remove this check here. Duplicate extension
86 # register check should be in descriptor_pool.
87 if extension is not pool.FindExtensionByNumber(
88 extension.containing_type, extension.number
89 ):
90 raise ValueError('Double registration of Extensions')
91 # Recursively load protos for extension field, in order to be able to
92 # fully represent the extension. This matches the behavior for regular
93 # fields too.
94 if extension.message_type:
95 GetMessageClass(extension.message_type)
96 return result
99def _InternalCreateMessageClass(descriptor):
100 """Builds a proto2 message class based on the passed in descriptor.
102 Args:
103 descriptor: The descriptor to build from.
105 Returns:
106 A class describing the passed in descriptor.
107 """
108 descriptor_name = descriptor.name
109 result_class = _GENERATED_PROTOCOL_MESSAGE_TYPE(
110 descriptor_name,
111 (message.Message,),
112 {
113 'DESCRIPTOR': descriptor,
114 # If module not set, it wrongly points to message_factory module.
115 '__module__': None,
116 })
117 for field in descriptor.fields:
118 if field.message_type:
119 GetMessageClass(field.message_type)
120 for extension in result_class.DESCRIPTOR.extensions:
121 extended_class = GetMessageClass(extension.containing_type)
122 if api_implementation.Type() != 'python':
123 # TODO: Remove this check here. Duplicate extension
124 # register check should be in descriptor_pool.
125 pool = extension.containing_type.file.pool
126 if extension is not pool.FindExtensionByNumber(
127 extension.containing_type, extension.number
128 ):
129 raise ValueError('Double registration of Extensions')
130 if extension.message_type:
131 GetMessageClass(extension.message_type)
132 return result_class
135# Deprecated. Please use GetMessageClass() or GetMessageClassesForFiles()
136# method above instead.
137class MessageFactory(object):
138 """Factory for creating Proto2 messages from descriptors in a pool."""
140 def __init__(self, pool=None):
141 """Initializes a new factory."""
142 self.pool = pool or descriptor_pool.DescriptorPool()
144 def GetPrototype(self, descriptor):
145 """Obtains a proto2 message class based on the passed in descriptor.
147 Passing a descriptor with a fully qualified name matching a previous
148 invocation will cause the same class to be returned.
150 Args:
151 descriptor: The descriptor to build from.
153 Returns:
154 A class describing the passed in descriptor.
155 """
156 warnings.warn(
157 'MessageFactory class is deprecated. Please use '
158 'GetMessageClass() instead of MessageFactory.GetPrototype. '
159 'MessageFactory class will be removed after 2024.',
160 stacklevel=2,
161 )
162 return GetMessageClass(descriptor)
164 def CreatePrototype(self, descriptor):
165 """Builds a proto2 message class based on the passed in descriptor.
167 Don't call this function directly, it always creates a new class. Call
168 GetMessageClass() instead.
170 Args:
171 descriptor: The descriptor to build from.
173 Returns:
174 A class describing the passed in descriptor.
175 """
176 warnings.warn(
177 'Directly call CreatePrototype is wrong. Please use '
178 'GetMessageClass() method instead. Directly use '
179 'CreatePrototype will raise error after July 2023.',
180 stacklevel=2,
181 )
182 return _InternalCreateMessageClass(descriptor)
184 def GetMessages(self, files):
185 """Gets all the messages from a specified file.
187 This will find and resolve dependencies, failing if the descriptor
188 pool cannot satisfy them.
190 Args:
191 files: The file names to extract messages from.
193 Returns:
194 A dictionary mapping proto names to the message classes. This will include
195 any dependent messages as well as any messages defined in the same file as
196 a specified message.
197 """
198 warnings.warn(
199 'MessageFactory class is deprecated. Please use '
200 'GetMessageClassesForFiles() instead of '
201 'MessageFactory.GetMessages(). MessageFactory class '
202 'will be removed after 2024.',
203 stacklevel=2,
204 )
205 return GetMessageClassesForFiles(files, self.pool)
208def GetMessages(file_protos, pool=None):
209 """Builds a dictionary of all the messages available in a set of files.
211 Args:
212 file_protos: Iterable of FileDescriptorProto to build messages out of.
213 pool: The descriptor pool to add the file protos.
215 Returns:
216 A dictionary mapping proto names to the message classes. This will include
217 any dependent messages as well as any messages defined in the same file as
218 a specified message.
219 """
220 # The cpp implementation of the protocol buffer library requires to add the
221 # message in topological order of the dependency graph.
222 des_pool = pool or descriptor_pool.DescriptorPool()
223 file_by_name = {file_proto.name: file_proto for file_proto in file_protos}
224 def _AddFile(file_proto):
225 for dependency in file_proto.dependency:
226 if dependency in file_by_name:
227 # Remove from elements to be visited, in order to cut cycles.
228 _AddFile(file_by_name.pop(dependency))
229 des_pool.Add(file_proto)
230 while file_by_name:
231 _AddFile(file_by_name.popitem()[1])
232 return GetMessageClassesForFiles(
233 [file_proto.name for file_proto in file_protos], des_pool)