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

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

104 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 """Provides the list of all accessible Message attributes.""" 

64 message_attributes = set(super().__dir__()) 

65 

66 # TODO: Remove this once the UPB implementation is improved. 

67 # The UPB proto implementation currently doesn't provide proto fields as 

68 # attributes and they have to added. 

69 if self.DESCRIPTOR is not None: 

70 for field in self.DESCRIPTOR.fields: 

71 message_attributes.add(field.name) 

72 

73 # The Fast C++ proto implementation provides inaccessible attributes that 

74 # have to be removed. 

75 for attribute in _INCONSISTENT_MESSAGE_ATTRIBUTES: 

76 if attribute not in message_attributes: 

77 continue 

78 try: 

79 getattr(self, attribute) 

80 except AttributeError: 

81 message_attributes.remove(attribute) 

82 

83 return sorted(message_attributes) 

84 

85 def __eq__(self, other_msg): 

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

87 raise NotImplementedError 

88 

89 def __ne__(self, other_msg): 

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

91 return not self == other_msg 

92 

93 def __hash__(self): 

94 raise TypeError('unhashable object') 

95 

96 def __str__(self): 

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

98 raise NotImplementedError 

99 

100 def __unicode__(self): 

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

102 raise NotImplementedError 

103 

104 def __contains__(self, field_name_or_key): 

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

106 

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

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

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

110 

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

112 be raised. 

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

114 if the item is contained in the list. 

115 

116 Args: 

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

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

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

120 

121 Returns: 

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

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

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

125 

126 Raises: 

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

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

129 """ 

130 raise NotImplementedError 

131 

132 def MergeFrom(self, other_msg): 

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

134 

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

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

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

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

139 

140 Args: 

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

142 """ 

143 raise NotImplementedError 

144 

145 def CopyFrom(self, other_msg): 

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

147 

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

149 message using MergeFrom. 

150 

151 Args: 

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

153 """ 

154 if self is other_msg: 

155 return 

156 self.Clear() 

157 self.MergeFrom(other_msg) 

158 

159 def Clear(self): 

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

161 raise NotImplementedError 

162 

163 def SetInParent(self): 

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

165 

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

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

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

169 you may want to reconsider your design. 

170 """ 

171 raise NotImplementedError 

172 

173 def IsInitialized(self): 

174 """Checks if the message is initialized. 

175 

176 Returns: 

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

178 its required fields are set). 

179 """ 

180 raise NotImplementedError 

181 

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

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

184 # deserialization routines would use the helper when recursively 

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

186 # MergeFromString(). 

187 

188 def MergeFromString(self, serialized): 

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

190 

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

192 in this message: 

193 

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

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

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

197 into the existing composite. 

198 

199 Args: 

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

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

202 buffer interface. 

203 

204 Returns: 

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

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

207 but for messages which are actually groups, this will 

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

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

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

211 of bytes returned does not include the bytes 

212 for the ``END_GROUP`` tag information. 

213 

214 Raises: 

215 DecodeError: if the input cannot be parsed. 

216 """ 

217 # TODO: Document handling of unknown fields. 

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

219 raise NotImplementedError 

220 

221 def ParseFromString(self, serialized): 

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

223 

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

225 

226 Raises: 

227 message.DecodeError if the input cannot be parsed. 

228 """ 

229 self.Clear() 

230 return self.MergeFromString(serialized) 

231 

232 def SerializeToString(self, **kwargs): 

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

234 

235 Keyword Args: 

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

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

238 

239 Returns: 

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

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

242 

243 Raises: 

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

245 """ 

246 raise NotImplementedError 

247 

248 def SerializePartialToString(self, **kwargs): 

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

250 

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

252 message is initialized. 

253 

254 Keyword Args: 

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

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

257 

258 Returns: 

259 bytes: A serialized representation of the partial message. 

260 """ 

261 raise NotImplementedError 

262 

263 # TODO: Decide whether we like these better 

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

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

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

267 # reduces the number of magically autogenerated things. 

268 # 

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

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

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

272 # like 'lambda' and 'yield'? 

273 # 

274 # nnorwitz says: 

275 # """ 

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

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

278 # """ 

279 def ListFields(self): 

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

281 

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

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

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

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

286 

287 Returns: 

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

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

290 field type. 

291 """ 

292 raise NotImplementedError 

293 

294 def HasField(self, field_name): 

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

296 

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

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

299 be raised. 

300 

301 Args: 

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

303 

304 Returns: 

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

306 

307 Raises: 

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

309 """ 

310 raise NotImplementedError 

311 

312 def ClearField(self, field_name): 

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

314 

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

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

317 

318 Args: 

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

320 

321 Raises: 

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

323 """ 

324 raise NotImplementedError 

325 

326 def WhichOneof(self, oneof_group): 

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

328 

329 If no field is set, returns None. 

330 

331 Args: 

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

333 

334 Returns: 

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

336 

337 Raises: 

338 ValueError: no group with the given name exists 

339 """ 

340 raise NotImplementedError 

341 

342 def HasExtension(self, field_descriptor): 

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

344 

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

346 

347 Args: 

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

349 

350 Returns: 

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

352 

353 Raises: 

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

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

356 extension is an empty list. 

357 """ 

358 raise NotImplementedError 

359 

360 def ClearExtension(self, field_descriptor): 

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

362 

363 Args: 

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

365 """ 

366 raise NotImplementedError 

367 

368 def UnknownFields(self): 

369 """Returns the UnknownFieldSet. 

370 

371 Returns: 

372 UnknownFieldSet: The unknown fields stored in this message. 

373 """ 

374 raise NotImplementedError 

375 

376 def DiscardUnknownFields(self): 

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

378 

379 This operation is recursive for nested message. 

380 """ 

381 raise NotImplementedError 

382 

383 def ByteSize(self): 

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

385 

386 Recursively calls ByteSize() on all contained messages. 

387 

388 Returns: 

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

390 """ 

391 raise NotImplementedError 

392 

393 @classmethod 

394 def FromString(cls, s): 

395 raise NotImplementedError 

396 

397 def _SetListener(self, message_listener): 

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

399 Clients should not call this directly. 

400 

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

402 

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

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

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

406 descendant object is modified. 

407 

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

409 explicitly sets callback to None. 

410 

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

412 message_listener must implement the MessageListener interface in 

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

414 via a previous _SetListener() call. 

415 """ 

416 raise NotImplementedError 

417 

418 def __getstate__(self): 

419 """Support the pickle protocol.""" 

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

421 

422 def __setstate__(self, state): 

423 """Support the pickle protocol.""" 

424 self.__init__() 

425 serialized = state['serialized'] 

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

427 # protos pickled by Python 2. 

428 if not isinstance(serialized, bytes): 

429 serialized = serialized.encode('latin1') 

430 self.ParseFromString(serialized) 

431 

432 def __reduce__(self): 

433 message_descriptor = self.DESCRIPTOR 

434 if message_descriptor.containing_type is None: 

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

436 # the message type must be nested. 

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

438 # receiving end. 

439 container = message_descriptor 

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

441 self.__getstate__()) 

442 

443 

444def _InternalConstructMessage(full_name): 

445 """Constructs a nested message.""" 

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

447 

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