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

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

98 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# TODO: We should just make these methods all "pure-virtual" and move 

9# all implementation out, into reflection.py for now. 

10 

11 

12"""Contains an abstract base class for protocol messages.""" 

13 

14__author__ = 'robinson@google.com (Will Robinson)' 

15 

16_INCONSISTENT_MESSAGE_ATTRIBUTES = ('Extensions',) 

17 

18 

19class Error(Exception): 

20 """Base error type for this module.""" 

21 pass 

22 

23 

24class DecodeError(Error): 

25 """Exception raised when deserializing messages.""" 

26 pass 

27 

28 

29class EncodeError(Error): 

30 """Exception raised when serializing messages.""" 

31 pass 

32 

33 

34class Message(object): 

35 

36 """Abstract base class for protocol messages. 

37 

38 Protocol message classes are almost always generated by the protocol 

39 compiler. These generated types subclass Message and implement the methods 

40 shown below. 

41 """ 

42 

43 # TODO: Link to an HTML document here. 

44 

45 # TODO: Document that instances of this class will also 

46 # have an Extensions attribute with __getitem__ and __setitem__. 

47 # Again, not sure how to best convey this. 

48 

49 # TODO: Document these fields and methods. 

50 

51 __slots__ = [] 

52 

53 #: The :class:`google.protobuf.Descriptor` 

54 # for this message type. 

55 DESCRIPTOR = None 

56 

57 def __deepcopy__(self, memo=None): 

58 clone = type(self)() 

59 clone.MergeFrom(self) 

60 return clone 

61 

62 def __dir__(self): 

63 """Filters out attributes that would raise AttributeError if accessed.""" 

64 missing_attributes = set() 

65 for attribute in _INCONSISTENT_MESSAGE_ATTRIBUTES: 

66 try: 

67 getattr(self, attribute) 

68 except AttributeError: 

69 missing_attributes.add(attribute) 

70 return [ 

71 attribute 

72 for attribute in super().__dir__() 

73 if attribute not in missing_attributes 

74 ] 

75 

76 def __eq__(self, other_msg): 

77 """Recursively compares two messages by value and structure.""" 

78 raise NotImplementedError 

79 

80 def __ne__(self, other_msg): 

81 # Can't just say self != other_msg, since that would infinitely recurse. :) 

82 return not self == other_msg 

83 

84 def __hash__(self): 

85 raise TypeError('unhashable object') 

86 

87 def __str__(self): 

88 """Outputs a human-readable representation of the message.""" 

89 raise NotImplementedError 

90 

91 def __unicode__(self): 

92 """Outputs a human-readable representation of the message.""" 

93 raise NotImplementedError 

94 

95 def __contains__(self, field_name_or_key): 

96 """Checks if a certain field is set for the message. 

97 

98 Has presence fields return true if the field is set, false if the field is 

99 not set. Fields without presence do raise `ValueError` (this includes 

100 repeated fields, map fields, and implicit presence fields). 

101 

102 If field_name is not defined in the message descriptor, `ValueError` will 

103 be raised. 

104 Note: WKT Struct checks if the key is contained in fields. ListValue checks 

105 if the item is contained in the list. 

106 

107 Args: 

108 field_name_or_key: For Struct, the key (str) of the fields map. For 

109 ListValue, any type that may be contained in the list. For other 

110 messages, name of the field (str) to check for presence. 

111 

112 Returns: 

113 bool: For Struct, whether the item is contained in fields. For ListValue, 

114 whether the item is contained in the list. For other message, 

115 whether a value has been set for the named field. 

116 

117 Raises: 

118 ValueError: For normal messages, if the `field_name_or_key` is not a 

119 member of this message or `field_name_or_key` is not a string. 

120 """ 

121 raise NotImplementedError 

122 

123 def MergeFrom(self, other_msg): 

124 """Merges the contents of the specified message into current message. 

125 

126 This method merges the contents of the specified message into the current 

127 message. Singular fields that are set in the specified message overwrite 

128 the corresponding fields in the current message. Repeated fields are 

129 appended. Singular sub-messages and groups are recursively merged. 

130 

131 Args: 

132 other_msg (Message): A message to merge into the current message. 

133 """ 

134 raise NotImplementedError 

135 

136 def CopyFrom(self, other_msg): 

137 """Copies the content of the specified message into the current message. 

138 

139 The method clears the current message and then merges the specified 

140 message using MergeFrom. 

141 

142 Args: 

143 other_msg (Message): A message to copy into the current one. 

144 """ 

145 if self is other_msg: 

146 return 

147 self.Clear() 

148 self.MergeFrom(other_msg) 

149 

150 def Clear(self): 

151 """Clears all data that was set in the message.""" 

152 raise NotImplementedError 

153 

154 def SetInParent(self): 

155 """Mark this as present in the parent. 

156 

157 This normally happens automatically when you assign a field of a 

158 sub-message, but sometimes you want to make the sub-message 

159 present while keeping it empty. If you find yourself using this, 

160 you may want to reconsider your design. 

161 """ 

162 raise NotImplementedError 

163 

164 def IsInitialized(self): 

165 """Checks if the message is initialized. 

166 

167 Returns: 

168 bool: The method returns True if the message is initialized (i.e. all of 

169 its required fields are set). 

170 """ 

171 raise NotImplementedError 

172 

173 # TODO: MergeFromString() should probably return None and be 

174 # implemented in terms of a helper that returns the # of bytes read. Our 

175 # deserialization routines would use the helper when recursively 

176 # deserializing, but the end user would almost always just want the no-return 

177 # MergeFromString(). 

178 

179 def MergeFromString(self, serialized): 

180 """Merges serialized protocol buffer data into this message. 

181 

182 When we find a field in `serialized` that is already present 

183 in this message: 

184 

185 - If it's a "repeated" field, we append to the end of our list. 

186 - Else, if it's a scalar, we overwrite our field. 

187 - Else, (it's a nonrepeated composite), we recursively merge 

188 into the existing composite. 

189 

190 Args: 

191 serialized (bytes): Any object that allows us to call 

192 ``memoryview(serialized)`` to access a string of bytes using the 

193 buffer interface. 

194 

195 Returns: 

196 int: The number of bytes read from `serialized`. 

197 For non-group messages, this will always be `len(serialized)`, 

198 but for messages which are actually groups, this will 

199 generally be less than `len(serialized)`, since we must 

200 stop when we reach an ``END_GROUP`` tag. Note that if 

201 we *do* stop because of an ``END_GROUP`` tag, the number 

202 of bytes returned does not include the bytes 

203 for the ``END_GROUP`` tag information. 

204 

205 Raises: 

206 DecodeError: if the input cannot be parsed. 

207 """ 

208 # TODO: Document handling of unknown fields. 

209 # TODO: When we switch to a helper, this will return None. 

210 raise NotImplementedError 

211 

212 def ParseFromString(self, serialized): 

213 """Parse serialized protocol buffer data in binary form into this message. 

214 

215 Like :func:`MergeFromString()`, except we clear the object first. 

216 

217 Raises: 

218 message.DecodeError if the input cannot be parsed. 

219 """ 

220 self.Clear() 

221 return self.MergeFromString(serialized) 

222 

223 def SerializeToString(self, **kwargs): 

224 """Serializes the protocol message to a binary string. 

225 

226 Keyword Args: 

227 deterministic (bool): If true, requests deterministic serialization 

228 of the protobuf, with predictable ordering of map keys. 

229 

230 Returns: 

231 A binary string representation of the message if all of the required 

232 fields in the message are set (i.e. the message is initialized). 

233 

234 Raises: 

235 EncodeError: if the message isn't initialized (see :func:`IsInitialized`). 

236 """ 

237 raise NotImplementedError 

238 

239 def SerializePartialToString(self, **kwargs): 

240 """Serializes the protocol message to a binary string. 

241 

242 This method is similar to SerializeToString but doesn't check if the 

243 message is initialized. 

244 

245 Keyword Args: 

246 deterministic (bool): If true, requests deterministic serialization 

247 of the protobuf, with predictable ordering of map keys. 

248 

249 Returns: 

250 bytes: A serialized representation of the partial message. 

251 """ 

252 raise NotImplementedError 

253 

254 # TODO: Decide whether we like these better 

255 # than auto-generated has_foo() and clear_foo() methods 

256 # on the instances themselves. This way is less consistent 

257 # with C++, but it makes reflection-type access easier and 

258 # reduces the number of magically autogenerated things. 

259 # 

260 # TODO: Be sure to document (and test) exactly 

261 # which field names are accepted here. Are we case-sensitive? 

262 # What do we do with fields that share names with Python keywords 

263 # like 'lambda' and 'yield'? 

264 # 

265 # nnorwitz says: 

266 # """ 

267 # Typically (in python), an underscore is appended to names that are 

268 # keywords. So they would become lambda_ or yield_. 

269 # """ 

270 def ListFields(self): 

271 """Returns a list of (FieldDescriptor, value) tuples for present fields. 

272 

273 A message field is non-empty if HasField() would return true. A singular 

274 primitive field is non-empty if HasField() would return true in proto2 or it 

275 is non zero in proto3. A repeated field is non-empty if it contains at least 

276 one element. The fields are ordered by field number. 

277 

278 Returns: 

279 list[tuple(FieldDescriptor, value)]: field descriptors and values 

280 for all fields in the message which are not empty. The values vary by 

281 field type. 

282 """ 

283 raise NotImplementedError 

284 

285 def HasField(self, field_name): 

286 """Checks if a certain field is set for the message. 

287 

288 For a oneof group, checks if any field inside is set. Note that if the 

289 field_name is not defined in the message descriptor, :exc:`ValueError` will 

290 be raised. 

291 

292 Args: 

293 field_name (str): The name of the field to check for presence. 

294 

295 Returns: 

296 bool: Whether a value has been set for the named field. 

297 

298 Raises: 

299 ValueError: if the `field_name` is not a member of this message. 

300 """ 

301 raise NotImplementedError 

302 

303 def ClearField(self, field_name): 

304 """Clears the contents of a given field. 

305 

306 Inside a oneof group, clears the field set. If the name neither refers to a 

307 defined field or oneof group, :exc:`ValueError` is raised. 

308 

309 Args: 

310 field_name (str): The name of the field to check for presence. 

311 

312 Raises: 

313 ValueError: if the `field_name` is not a member of this message. 

314 """ 

315 raise NotImplementedError 

316 

317 def WhichOneof(self, oneof_group): 

318 """Returns the name of the field that is set inside a oneof group. 

319 

320 If no field is set, returns None. 

321 

322 Args: 

323 oneof_group (str): the name of the oneof group to check. 

324 

325 Returns: 

326 str or None: The name of the group that is set, or None. 

327 

328 Raises: 

329 ValueError: no group with the given name exists 

330 """ 

331 raise NotImplementedError 

332 

333 def HasExtension(self, field_descriptor): 

334 """Checks if a certain extension is present for this message. 

335 

336 Extensions are retrieved using the :attr:`Extensions` mapping (if present). 

337 

338 Args: 

339 field_descriptor: The field descriptor for the extension to check. 

340 

341 Returns: 

342 bool: Whether the extension is present for this message. 

343 

344 Raises: 

345 KeyError: if the extension is repeated. Similar to repeated fields, 

346 there is no separate notion of presence: a "not present" repeated 

347 extension is an empty list. 

348 """ 

349 raise NotImplementedError 

350 

351 def ClearExtension(self, field_descriptor): 

352 """Clears the contents of a given extension. 

353 

354 Args: 

355 field_descriptor: The field descriptor for the extension to clear. 

356 """ 

357 raise NotImplementedError 

358 

359 def UnknownFields(self): 

360 """Returns the UnknownFieldSet. 

361 

362 Returns: 

363 UnknownFieldSet: The unknown fields stored in this message. 

364 """ 

365 raise NotImplementedError 

366 

367 def DiscardUnknownFields(self): 

368 """Clears all fields in the :class:`UnknownFieldSet`. 

369 

370 This operation is recursive for nested message. 

371 """ 

372 raise NotImplementedError 

373 

374 def ByteSize(self): 

375 """Returns the serialized size of this message. 

376 

377 Recursively calls ByteSize() on all contained messages. 

378 

379 Returns: 

380 int: The number of bytes required to serialize this message. 

381 """ 

382 raise NotImplementedError 

383 

384 @classmethod 

385 def FromString(cls, s): 

386 raise NotImplementedError 

387 

388 def _SetListener(self, message_listener): 

389 """Internal method used by the protocol message implementation. 

390 Clients should not call this directly. 

391 

392 Sets a listener that this message will call on certain state transitions. 

393 

394 The purpose of this method is to register back-edges from children to 

395 parents at runtime, for the purpose of setting "has" bits and 

396 byte-size-dirty bits in the parent and ancestor objects whenever a child or 

397 descendant object is modified. 

398 

399 If the client wants to disconnect this Message from the object tree, she 

400 explicitly sets callback to None. 

401 

402 If message_listener is None, unregisters any existing listener. Otherwise, 

403 message_listener must implement the MessageListener interface in 

404 internal/message_listener.py, and we discard any listener registered 

405 via a previous _SetListener() call. 

406 """ 

407 raise NotImplementedError 

408 

409 def __getstate__(self): 

410 """Support the pickle protocol.""" 

411 return dict(serialized=self.SerializePartialToString()) 

412 

413 def __setstate__(self, state): 

414 """Support the pickle protocol.""" 

415 self.__init__() 

416 serialized = state['serialized'] 

417 # On Python 3, using encoding='latin1' is required for unpickling 

418 # protos pickled by Python 2. 

419 if not isinstance(serialized, bytes): 

420 serialized = serialized.encode('latin1') 

421 self.ParseFromString(serialized) 

422 

423 def __reduce__(self): 

424 message_descriptor = self.DESCRIPTOR 

425 if message_descriptor.containing_type is None: 

426 return type(self), (), self.__getstate__() 

427 # the message type must be nested. 

428 # Python does not pickle nested classes; use the symbol_database on the 

429 # receiving end. 

430 container = message_descriptor 

431 return (_InternalConstructMessage, (container.full_name,), 

432 self.__getstate__()) 

433 

434 

435def _InternalConstructMessage(full_name): 

436 """Constructs a nested message.""" 

437 from google.protobuf import symbol_database # pylint:disable=g-import-not-at-top 

438 

439 return symbol_database.Default().GetSymbol(full_name)()