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

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

58 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 Args: 

60 files: The file names to extract messages from. 

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

62 

63 Returns: 

64 A dictionary mapping proto names to the message classes. 

65 """ 

66 result = {} 

67 for file_name in files: 

68 file_desc = pool.FindFileByName(file_name) 

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

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

71 

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

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

74 # explicitly, which is done below. 

75 # 

76 # The call to RegisterExtension will specifically check if the 

77 # extension was already registered on the object and either 

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

79 # an error if they were different. 

80 

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

82 _ = GetMessageClass(extension.containing_type) 

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

84 # TODO: Remove this check here. Duplicate extension 

85 # register check should be in descriptor_pool. 

86 if extension is not pool.FindExtensionByNumber( 

87 extension.containing_type, extension.number 

88 ): 

89 raise ValueError('Double registration of Extensions') 

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

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

92 # fields too. 

93 if extension.message_type: 

94 GetMessageClass(extension.message_type) 

95 return result 

96 

97 

98def _InternalCreateMessageClass(descriptor): 

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

100 

101 Args: 

102 descriptor: The descriptor to build from. 

103 

104 Returns: 

105 A class describing the passed in descriptor. 

106 """ 

107 descriptor_name = descriptor.name 

108 result_class = _GENERATED_PROTOCOL_MESSAGE_TYPE( 

109 descriptor_name, 

110 (message.Message,), 

111 { 

112 'DESCRIPTOR': descriptor, 

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

114 '__module__': None, 

115 }, 

116 ) 

117 for field in descriptor.fields: 

118 if field.message_type: 

119 GetMessageClass(field.message_type) 

120 

121 for extension in result_class.DESCRIPTOR.extensions: 

122 extended_class = GetMessageClass(extension.containing_type) 

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

124 # TODO: Remove this check here. Duplicate extension 

125 # register check should be in descriptor_pool. 

126 pool = extension.containing_type.file.pool 

127 if extension is not pool.FindExtensionByNumber( 

128 extension.containing_type, extension.number 

129 ): 

130 raise ValueError('Double registration of Extensions') 

131 if extension.message_type: 

132 GetMessageClass(extension.message_type) 

133 return result_class 

134 

135 

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

137# method above instead. 

138class MessageFactory(object): 

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

140 

141 def __init__(self, pool=None): 

142 """Initializes a new factory.""" 

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

144 

145 

146def GetMessages(file_protos, pool=None): 

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

148 

149 Args: 

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

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

152 

153 Returns: 

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

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

156 a specified message. 

157 """ 

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

159 # message in topological order of the dependency graph. 

160 des_pool = pool or descriptor_pool.DescriptorPool() 

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

162 

163 def _AddFile(file_proto): 

164 for dependency in file_proto.dependency: 

165 if dependency in file_by_name: 

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

167 _AddFile(file_by_name.pop(dependency)) 

168 des_pool.Add(file_proto) 

169 

170 while file_by_name: 

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

172 return GetMessageClassesForFiles( 

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

174 )