Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/google/protobuf/message_factory.py: 25%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

59 statements  

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 

7 

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

9 

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: 

12 

13message_classes = message_factory.GetMessages(iterable_of_file_descriptors) 

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

15""" 

16 

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

18 

19import warnings 

20 

21from google.protobuf import descriptor_pool 

22from google.protobuf import message 

23from google.protobuf.internal import api_implementation 

24 

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 

29 

30 

31# The type of all Message classes. 

32_GENERATED_PROTOCOL_MESSAGE_TYPE = message_impl.GeneratedProtocolMessageType 

33 

34 

35def GetMessageClass(descriptor): 

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

37 

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

39 invocation will cause the same class to be returned. 

40 

41 Args: 

42 descriptor: The descriptor to build from. 

43 

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) 

51 

52 

53def GetMessageClassesForFiles(files, pool): 

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

55 

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

57 pool cannot satisfy them. 

58 

59 This will not return the classes for nested types within those classes, for 

60 those, use GetMessageClass() on the nested types within their containing 

61 messages. 

62 

63 For example, for the message: 

64 

65 message NestedTypeMessage { 

66 message NestedType { 

67 string data = 1; 

68 } 

69 NestedType nested = 1; 

70 } 

71 

72 NestedTypeMessage will be in the result, but not 

73 NestedTypeMessage.NestedType. 

74 

75 Args: 

76 files: The file names to extract messages from. 

77 pool: The descriptor pool to find the files including the dependent files. 

78 

79 Returns: 

80 A dictionary mapping proto names to the message classes. 

81 """ 

82 result = {} 

83 for file_name in files: 

84 file_desc = pool.FindFileByName(file_name) 

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

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

87 

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

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

90 # explicitly, which is done below. 

91 # 

92 # The call to RegisterExtension will specifically check if the 

93 # extension was already registered on the object and either 

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

95 # an error if they were different. 

96 

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

98 _ = GetMessageClass(extension.containing_type) 

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

100 # TODO: Remove this check here. Duplicate extension 

101 # register check should be in descriptor_pool. 

102 if extension is not pool.FindExtensionByNumber( 

103 extension.containing_type, extension.number 

104 ): 

105 raise ValueError('Double registration of Extensions') 

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

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

108 # fields too. 

109 if extension.message_type: 

110 GetMessageClass(extension.message_type) 

111 return result 

112 

113 

114def _InternalCreateMessageClass(descriptor): 

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

116 

117 Args: 

118 descriptor: The descriptor to build from. 

119 

120 Returns: 

121 A class describing the passed in descriptor. 

122 """ 

123 descriptor_name = descriptor.name 

124 result_class = _GENERATED_PROTOCOL_MESSAGE_TYPE( 

125 descriptor_name, 

126 (message.Message,), 

127 { 

128 'DESCRIPTOR': descriptor, 

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

130 '__module__': None, 

131 }, 

132 ) 

133 for field in descriptor.fields: 

134 if field.message_type: 

135 GetMessageClass(field.message_type) 

136 

137 for extension in result_class.DESCRIPTOR.extensions: 

138 extended_class = GetMessageClass(extension.containing_type) 

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

140 # TODO: Remove this check here. Duplicate extension 

141 # register check should be in descriptor_pool. 

142 pool = extension.containing_type.file.pool 

143 if extension is not pool.FindExtensionByNumber( 

144 extension.containing_type, extension.number 

145 ): 

146 raise ValueError('Double registration of Extensions') 

147 if extension.message_type: 

148 GetMessageClass(extension.message_type) 

149 return result_class 

150 

151 

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

153# method above instead. 

154class MessageFactory(object): 

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

156 

157 def __init__(self, pool=None): 

158 """Initializes a new factory.""" 

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

160 

161 

162def GetMessages(file_protos, pool=None): 

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

164 

165 Args: 

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

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

168 

169 Returns: 

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

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

172 a specified message. 

173 """ 

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

175 # message in topological order of the dependency graph. 

176 des_pool = pool or descriptor_pool.DescriptorPool() 

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

178 

179 def _AddFile(file_proto): 

180 for dependency in file_proto.dependency: 

181 if dependency in file_by_name: 

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

183 _AddFile(file_by_name.pop(dependency)) 

184 des_pool.Add(file_proto) 

185 

186 while file_by_name: 

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

188 return GetMessageClassesForFiles( 

189 [file_proto.name for file_proto in file_protos], des_pool 

190 )