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.1, created at 2023-09-25 06:37 +0000

1# Protocol Buffers - Google's data interchange format 

2# Copyright 2008 Google Inc. All rights reserved. 

3# https://developers.google.com/protocol-buffers/ 

4# 

5# Redistribution and use in source and binary forms, with or without 

6# modification, are permitted provided that the following conditions are 

7# met: 

8# 

9# * Redistributions of source code must retain the above copyright 

10# notice, this list of conditions and the following disclaimer. 

11# * Redistributions in binary form must reproduce the above 

12# copyright notice, this list of conditions and the following disclaimer 

13# in the documentation and/or other materials provided with the 

14# distribution. 

15# * Neither the name of Google Inc. nor the names of its 

16# contributors may be used to endorse or promote products derived from 

17# this software without specific prior written permission. 

18# 

19# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 

20# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 

21# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 

22# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 

23# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 

24# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 

25# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 

26# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 

27# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 

28# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 

29# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 

30 

31"""Provides a factory class for generating dynamic messages. 

32 

33The easiest way to use this class is if you have access to the FileDescriptor 

34protos containing the messages you want to create you can just do the following: 

35 

36message_classes = message_factory.GetMessages(iterable_of_file_descriptors) 

37my_proto_instance = message_classes['some.proto.package.MessageName']() 

38""" 

39 

40__author__ = 'matthewtoia@google.com (Matt Toia)' 

41 

42import warnings 

43 

44from google.protobuf.internal import api_implementation 

45from google.protobuf import descriptor_pool 

46from google.protobuf import message 

47 

48if api_implementation.Type() == 'python': 

49 from google.protobuf.internal import python_message as message_impl 

50else: 

51 from google.protobuf.pyext import cpp_message as message_impl # pylint: disable=g-import-not-at-top 

52 

53 

54# The type of all Message classes. 

55_GENERATED_PROTOCOL_MESSAGE_TYPE = message_impl.GeneratedProtocolMessageType 

56 

57 

58def GetMessageClass(descriptor): 

59 """Obtains a proto2 message class based on the passed in descriptor. 

60 

61 Passing a descriptor with a fully qualified name matching a previous 

62 invocation will cause the same class to be returned. 

63 

64 Args: 

65 descriptor: The descriptor to build from. 

66 

67 Returns: 

68 A class describing the passed in descriptor. 

69 """ 

70 concrete_class = getattr(descriptor, '_concrete_class', None) 

71 if concrete_class: 

72 return concrete_class 

73 return _InternalCreateMessageClass(descriptor) 

74 

75 

76def GetMessageClassesForFiles(files, pool): 

77 """Gets all the messages from specified files. 

78 

79 This will find and resolve dependencies, failing if the descriptor 

80 pool cannot satisfy them. 

81 

82 Args: 

83 files: The file names to extract messages from. 

84 pool: The descriptor pool to find the files including the dependent 

85 files. 

86 

87 Returns: 

88 A dictionary mapping proto names to the message classes. 

89 """ 

90 result = {} 

91 for file_name in files: 

92 file_desc = pool.FindFileByName(file_name) 

93 for desc in file_desc.message_types_by_name.values(): 

94 result[desc.full_name] = GetMessageClass(desc) 

95 

96 # While the extension FieldDescriptors are created by the descriptor pool, 

97 # the python classes created in the factory need them to be registered 

98 # explicitly, which is done below. 

99 # 

100 # The call to RegisterExtension will specifically check if the 

101 # extension was already registered on the object and either 

102 # ignore the registration if the original was the same, or raise 

103 # an error if they were different. 

104 

105 for extension in file_desc.extensions_by_name.values(): 

106 extended_class = GetMessageClass(extension.containing_type) 

107 if api_implementation.Type() != 'python': 

108 # TODO(b/286443080): Remove this check here. Duplicate extension 

109 # register check should be in descriptor_pool. 

110 if extension is not pool.FindExtensionByNumber( 

111 extension.containing_type, extension.number 

112 ): 

113 raise ValueError('Double registration of Extensions') 

114 # Recursively load protos for extension field, in order to be able to 

115 # fully represent the extension. This matches the behavior for regular 

116 # fields too. 

117 if extension.message_type: 

118 GetMessageClass(extension.message_type) 

119 return result 

120 

121 

122def _InternalCreateMessageClass(descriptor): 

123 """Builds a proto2 message class based on the passed in descriptor. 

124 

125 Args: 

126 descriptor: The descriptor to build from. 

127 

128 Returns: 

129 A class describing the passed in descriptor. 

130 """ 

131 descriptor_name = descriptor.name 

132 result_class = _GENERATED_PROTOCOL_MESSAGE_TYPE( 

133 descriptor_name, 

134 (message.Message,), 

135 { 

136 'DESCRIPTOR': descriptor, 

137 # If module not set, it wrongly points to message_factory module. 

138 '__module__': None, 

139 }) 

140 for field in descriptor.fields: 

141 if field.message_type: 

142 GetMessageClass(field.message_type) 

143 for extension in result_class.DESCRIPTOR.extensions: 

144 extended_class = GetMessageClass(extension.containing_type) 

145 if api_implementation.Type() != 'python': 

146 # TODO(b/286443080): Remove this check here. Duplicate extension 

147 # register check should be in descriptor_pool. 

148 pool = extension.containing_type.file.pool 

149 if extension is not pool.FindExtensionByNumber( 

150 extension.containing_type, extension.number 

151 ): 

152 raise ValueError('Double registration of Extensions') 

153 if extension.message_type: 

154 GetMessageClass(extension.message_type) 

155 return result_class 

156 

157 

158# Deprecated. Please use GetMessageClass() or GetMessageClassesForFiles() 

159# method above instead. 

160class MessageFactory(object): 

161 """Factory for creating Proto2 messages from descriptors in a pool.""" 

162 

163 def __init__(self, pool=None): 

164 """Initializes a new factory.""" 

165 self.pool = pool or descriptor_pool.DescriptorPool() 

166 

167 def GetPrototype(self, descriptor): 

168 """Obtains a proto2 message class based on the passed in descriptor. 

169 

170 Passing a descriptor with a fully qualified name matching a previous 

171 invocation will cause the same class to be returned. 

172 

173 Args: 

174 descriptor: The descriptor to build from. 

175 

176 Returns: 

177 A class describing the passed in descriptor. 

178 """ 

179 warnings.warn( 

180 'MessageFactory class is deprecated. Please use ' 

181 'GetMessageClass() instead of MessageFactory.GetPrototype. ' 

182 'MessageFactory class will be removed after 2024.', 

183 stacklevel=2, 

184 ) 

185 return GetMessageClass(descriptor) 

186 

187 def CreatePrototype(self, descriptor): 

188 """Builds a proto2 message class based on the passed in descriptor. 

189 

190 Don't call this function directly, it always creates a new class. Call 

191 GetMessageClass() instead. 

192 

193 Args: 

194 descriptor: The descriptor to build from. 

195 

196 Returns: 

197 A class describing the passed in descriptor. 

198 """ 

199 warnings.warn( 

200 'Directly call CreatePrototype is wrong. Please use ' 

201 'GetMessageClass() method instead. Directly use ' 

202 'CreatePrototype will raise error after July 2023.', 

203 stacklevel=2, 

204 ) 

205 return _InternalCreateMessageClass(descriptor) 

206 

207 def GetMessages(self, files): 

208 """Gets all the messages from a specified file. 

209 

210 This will find and resolve dependencies, failing if the descriptor 

211 pool cannot satisfy them. 

212 

213 Args: 

214 files: The file names to extract messages from. 

215 

216 Returns: 

217 A dictionary mapping proto names to the message classes. This will include 

218 any dependent messages as well as any messages defined in the same file as 

219 a specified message. 

220 """ 

221 warnings.warn( 

222 'MessageFactory class is deprecated. Please use ' 

223 'GetMessageClassesForFiles() instead of ' 

224 'MessageFactory.GetMessages(). MessageFactory class ' 

225 'will be removed after 2024.', 

226 stacklevel=2, 

227 ) 

228 return GetMessageClassesForFiles(files, self.pool) 

229 

230 

231def GetMessages(file_protos, pool=None): 

232 """Builds a dictionary of all the messages available in a set of files. 

233 

234 Args: 

235 file_protos: Iterable of FileDescriptorProto to build messages out of. 

236 pool: The descriptor pool to add the file protos. 

237 

238 Returns: 

239 A dictionary mapping proto names to the message classes. This will include 

240 any dependent messages as well as any messages defined in the same file as 

241 a specified message. 

242 """ 

243 # The cpp implementation of the protocol buffer library requires to add the 

244 # message in topological order of the dependency graph. 

245 des_pool = pool or descriptor_pool.DescriptorPool() 

246 file_by_name = {file_proto.name: file_proto for file_proto in file_protos} 

247 def _AddFile(file_proto): 

248 for dependency in file_proto.dependency: 

249 if dependency in file_by_name: 

250 # Remove from elements to be visited, in order to cut cycles. 

251 _AddFile(file_by_name.pop(dependency)) 

252 des_pool.Add(file_proto) 

253 while file_by_name: 

254 _AddFile(file_by_name.popitem()[1]) 

255 return GetMessageClassesForFiles( 

256 [file_proto.name for file_proto in file_protos], des_pool)