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"""Provides a factory class for generating dynamic messages. 

8 

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

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

11 

12message_classes = message_factory.GetMessages(iterable_of_file_descriptors) 

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

14""" 

15 

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

17 

18import warnings 

19 

20from google.protobuf import descriptor_pool 

21from google.protobuf import message 

22from google.protobuf.internal import api_implementation 

23 

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

25 from google.protobuf.internal import python_message as message_impl 

26else: 

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

28 

29# The type of all Message classes. 

30_GENERATED_PROTOCOL_MESSAGE_TYPE = message_impl.GeneratedProtocolMessageType 

31 

32 

33def GetMessageClass(descriptor): 

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

35 

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

37 invocation will cause the same class to be returned. 

38 

39 Args: 

40 descriptor: The descriptor to build from. 

41 

42 Returns: 

43 A class describing the passed in descriptor. 

44 """ 

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

46 if concrete_class: 

47 return concrete_class 

48 return _InternalCreateMessageClass(descriptor) 

49 

50 

51def GetMessageClassesForFiles(files, pool): 

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

53 

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

55 pool cannot satisfy them. 

56 

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

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

59 messages. 

60 

61 For example, for the message: 

62 

63 message NestedTypeMessage { 

64 message NestedType { 

65 string data = 1; 

66 } 

67 NestedType nested = 1; 

68 } 

69 

70 NestedTypeMessage will be in the result, but not 

71 NestedTypeMessage.NestedType. 

72 

73 Args: 

74 files: The file names to extract messages from. 

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

76 

77 Returns: 

78 A dictionary mapping proto names to the message classes. 

79 """ 

80 result = {} 

81 for file_name in files: 

82 file_desc = pool.FindFileByName(file_name) 

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

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

85 

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

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

88 # explicitly, which is done below. 

89 # 

90 # The call to RegisterExtension will specifically check if the 

91 # extension was already registered on the object and either 

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

93 # an error if they were different. 

94 

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

96 _ = GetMessageClass(extension.containing_type) 

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

98 # TODO: Remove this check here. Duplicate extension 

99 # register check should be in descriptor_pool. 

100 if extension is not pool.FindExtensionByNumber( 

101 extension.containing_type, extension.number 

102 ): 

103 raise ValueError('Double registration of Extensions') 

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

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

106 # fields too. 

107 if extension.message_type: 

108 GetMessageClass(extension.message_type) 

109 return result 

110 

111 

112def _InternalCreateMessageClass(descriptor): 

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

114 

115 Args: 

116 descriptor: The descriptor to build from. 

117 

118 Returns: 

119 A class describing the passed in descriptor. 

120 """ 

121 descriptor_name = descriptor.name 

122 result_class = _GENERATED_PROTOCOL_MESSAGE_TYPE( 

123 descriptor_name, 

124 (message.Message,), 

125 { 

126 'DESCRIPTOR': descriptor, 

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

128 '__module__': None, 

129 }, 

130 ) 

131 for field in descriptor.fields: 

132 if field.message_type: 

133 GetMessageClass(field.message_type) 

134 

135 for extension in result_class.DESCRIPTOR.extensions: 

136 extended_class = GetMessageClass(extension.containing_type) 

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

138 # TODO: Remove this check here. Duplicate extension 

139 # register check should be in descriptor_pool. 

140 pool = extension.containing_type.file.pool 

141 if extension is not pool.FindExtensionByNumber( 

142 extension.containing_type, extension.number 

143 ): 

144 raise ValueError('Double registration of Extensions') 

145 if extension.message_type: 

146 GetMessageClass(extension.message_type) 

147 return result_class 

148 

149 

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

151# method above instead. 

152class MessageFactory(object): 

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

154 

155 def __init__(self, pool=None): 

156 """Initializes a new factory.""" 

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

158 

159 

160def GetMessages(file_protos, pool=None): 

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

162 

163 Args: 

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

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

166 

167 Returns: 

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

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

170 a specified message. 

171 """ 

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

173 # message in topological order of the dependency graph. 

174 des_pool = pool or descriptor_pool.DescriptorPool() 

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

176 

177 def _AddFile(file_proto): 

178 for dependency in file_proto.dependency: 

179 if dependency in file_by_name: 

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

181 _AddFile(file_by_name.pop(dependency)) 

182 des_pool.Add(file_proto) 

183 

184 while file_by_name: 

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

186 return GetMessageClassesForFiles( 

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

188 )