Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/proto/fields.py: 89%

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

64 statements  

1# Copyright 2018 Google LLC 

2# 

3# Licensed under the Apache License, Version 2.0 (the "License"); 

4# you may not use this file except in compliance with the License. 

5# You may obtain a copy of the License at 

6# 

7# https://www.apache.org/licenses/LICENSE-2.0 

8# 

9# Unless required by applicable law or agreed to in writing, software 

10# distributed under the License is distributed on an "AS IS" BASIS, 

11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 

12# See the License for the specific language governing permissions and 

13# limitations under the License. 

14 

15from enum import EnumMeta 

16 

17from google.protobuf import descriptor_pb2 

18from google.protobuf.internal.enum_type_wrapper import EnumTypeWrapper 

19 

20from proto.primitives import ProtoType 

21 

22 

23class Field: 

24 """A representation of a type of field in protocol buffers.""" 

25 

26 # Fields are NOT repeated nor maps. 

27 # The RepeatedField overrides this values. 

28 repeated = False 

29 

30 def __init__( 

31 self, 

32 proto_type, 

33 *, 

34 number: int, 

35 message=None, 

36 enum=None, 

37 oneof: str = None, 

38 json_name: str = None, 

39 optional: bool = False 

40 ): 

41 # This class is not intended to stand entirely alone; 

42 # data is augmented by the metaclass for Message. 

43 self.mcls_data = None 

44 self.parent = None 

45 

46 # If the proto type sent is an object or a string, it is really 

47 # a message or enum. 

48 if not isinstance(proto_type, int): 

49 # Note: We only support the "shortcut syntax" for enums 

50 # when receiving the actual class. 

51 if isinstance(proto_type, (EnumMeta, EnumTypeWrapper)): 

52 enum = proto_type 

53 proto_type = ProtoType.ENUM 

54 else: 

55 message = proto_type 

56 proto_type = ProtoType.MESSAGE 

57 

58 # Save the direct arguments. 

59 self.number = number 

60 self.proto_type = proto_type 

61 self.message = message 

62 self.enum = enum 

63 self.json_name = json_name 

64 self.optional = optional 

65 self.oneof = oneof 

66 

67 # Once the descriptor is accessed the first time, cache it. 

68 # This is important because in rare cases the message or enum 

69 # types are written later. 

70 self._descriptor = None 

71 

72 @property 

73 def descriptor(self): 

74 """Return the descriptor for the field.""" 

75 if not self._descriptor: 

76 # Resolve the message type, if any, to a string. 

77 type_name = None 

78 if isinstance(self.message, str): 

79 if not self.message.startswith(self.package): 

80 self.message = "{package}.{name}".format( 

81 package=self.package, 

82 name=self.message, 

83 ) 

84 type_name = self.message 

85 elif self.message: 

86 type_name = ( 

87 self.message.DESCRIPTOR.full_name 

88 if hasattr(self.message, "DESCRIPTOR") 

89 else self.message._meta.full_name 

90 ) 

91 elif isinstance(self.enum, str): 

92 if not self.enum.startswith(self.package): 

93 self.enum = "{package}.{name}".format( 

94 package=self.package, 

95 name=self.enum, 

96 ) 

97 type_name = self.enum 

98 elif self.enum: 

99 type_name = ( 

100 self.enum.DESCRIPTOR.full_name 

101 if hasattr(self.enum, "DESCRIPTOR") 

102 else self.enum._meta.full_name 

103 ) 

104 

105 # Set the descriptor. 

106 self._descriptor = descriptor_pb2.FieldDescriptorProto( 

107 name=self.name, 

108 number=self.number, 

109 label=3 if self.repeated else 1, 

110 type=self.proto_type, 

111 type_name=type_name, 

112 json_name=self.json_name, 

113 proto3_optional=self.optional, 

114 ) 

115 

116 # Return the descriptor. 

117 return self._descriptor 

118 

119 @property 

120 def name(self) -> str: 

121 """Return the name of the field.""" 

122 return self.mcls_data["name"] 

123 

124 @property 

125 def package(self) -> str: 

126 """Return the package of the field.""" 

127 return self.mcls_data["package"] 

128 

129 @property 

130 def pb_type(self): 

131 """Return the composite type of the field, or the primitive type if a primitive.""" 

132 # For enums, return the Python enum. 

133 if self.enum: 

134 return self.enum 

135 

136 # For primitive fields, we still want to know 

137 # what the type is. 

138 if not self.message: 

139 return self.proto_type 

140 

141 # Return the internal protobuf message. 

142 if hasattr(self.message, "_meta"): 

143 return self.message.pb() 

144 return self.message 

145 

146 

147class RepeatedField(Field): 

148 """A representation of a repeated field in protocol buffers.""" 

149 

150 repeated = True 

151 

152 

153class MapField(Field): 

154 """A representation of a map field in protocol buffers.""" 

155 

156 def __init__(self, key_type, value_type, *, number: int, message=None, enum=None): 

157 super().__init__(value_type, number=number, message=message, enum=enum) 

158 self.map_key_type = key_type 

159 

160 

161__all__ = ( 

162 "Field", 

163 "MapField", 

164 "RepeatedField", 

165)