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
16class Error(Exception):
17 """Base error type for this module."""
18 pass
19
20
21class DecodeError(Error):
22 """Exception raised when deserializing messages."""
23 pass
24
25
26class EncodeError(Error):
27 """Exception raised when serializing messages."""
28 pass
29
30
31class Message(object):
32
33 """Abstract base class for protocol messages.
34
35 Protocol message classes are almost always generated by the protocol
36 compiler. These generated types subclass Message and implement the methods
37 shown below.
38 """
39
40 # TODO: Link to an HTML document here.
41
42 # TODO: Document that instances of this class will also
43 # have an Extensions attribute with __getitem__ and __setitem__.
44 # Again, not sure how to best convey this.
45
46 # TODO: Document these fields and methods.
47
48 __slots__ = []
49
50 #: The :class:`google.protobuf.Descriptor`
51 # for this message type.
52 DESCRIPTOR = None
53
54 def __deepcopy__(self, memo=None):
55 clone = type(self)()
56 clone.MergeFrom(self)
57 return clone
58
59 def __eq__(self, other_msg):
60 """Recursively compares two messages by value and structure."""
61 raise NotImplementedError
62
63 def __ne__(self, other_msg):
64 # Can't just say self != other_msg, since that would infinitely recurse. :)
65 return not self == other_msg
66
67 def __hash__(self):
68 raise TypeError('unhashable object')
69
70 def __str__(self):
71 """Outputs a human-readable representation of the message."""
72 raise NotImplementedError
73
74 def __unicode__(self):
75 """Outputs a human-readable representation of the message."""
76 raise NotImplementedError
77
78 def MergeFrom(self, other_msg):
79 """Merges the contents of the specified message into current message.
80
81 This method merges the contents of the specified message into the current
82 message. Singular fields that are set in the specified message overwrite
83 the corresponding fields in the current message. Repeated fields are
84 appended. Singular sub-messages and groups are recursively merged.
85
86 Args:
87 other_msg (Message): A message to merge into the current message.
88 """
89 raise NotImplementedError
90
91 def CopyFrom(self, other_msg):
92 """Copies the content of the specified message into the current message.
93
94 The method clears the current message and then merges the specified
95 message using MergeFrom.
96
97 Args:
98 other_msg (Message): A message to copy into the current one.
99 """
100 if self is other_msg:
101 return
102 self.Clear()
103 self.MergeFrom(other_msg)
104
105 def Clear(self):
106 """Clears all data that was set in the message."""
107 raise NotImplementedError
108
109 def SetInParent(self):
110 """Mark this as present in the parent.
111
112 This normally happens automatically when you assign a field of a
113 sub-message, but sometimes you want to make the sub-message
114 present while keeping it empty. If you find yourself using this,
115 you may want to reconsider your design.
116 """
117 raise NotImplementedError
118
119 def IsInitialized(self):
120 """Checks if the message is initialized.
121
122 Returns:
123 bool: The method returns True if the message is initialized (i.e. all of
124 its required fields are set).
125 """
126 raise NotImplementedError
127
128 # TODO: MergeFromString() should probably return None and be
129 # implemented in terms of a helper that returns the # of bytes read. Our
130 # deserialization routines would use the helper when recursively
131 # deserializing, but the end user would almost always just want the no-return
132 # MergeFromString().
133
134 def MergeFromString(self, serialized):
135 """Merges serialized protocol buffer data into this message.
136
137 When we find a field in `serialized` that is already present
138 in this message:
139
140 - If it's a "repeated" field, we append to the end of our list.
141 - Else, if it's a scalar, we overwrite our field.
142 - Else, (it's a nonrepeated composite), we recursively merge
143 into the existing composite.
144
145 Args:
146 serialized (bytes): Any object that allows us to call
147 ``memoryview(serialized)`` to access a string of bytes using the
148 buffer interface.
149
150 Returns:
151 int: The number of bytes read from `serialized`.
152 For non-group messages, this will always be `len(serialized)`,
153 but for messages which are actually groups, this will
154 generally be less than `len(serialized)`, since we must
155 stop when we reach an ``END_GROUP`` tag. Note that if
156 we *do* stop because of an ``END_GROUP`` tag, the number
157 of bytes returned does not include the bytes
158 for the ``END_GROUP`` tag information.
159
160 Raises:
161 DecodeError: if the input cannot be parsed.
162 """
163 # TODO: Document handling of unknown fields.
164 # TODO: When we switch to a helper, this will return None.
165 raise NotImplementedError
166
167 def ParseFromString(self, serialized):
168 """Parse serialized protocol buffer data in binary form into this message.
169
170 Like :func:`MergeFromString()`, except we clear the object first.
171
172 Raises:
173 message.DecodeError if the input cannot be parsed.
174 """
175 self.Clear()
176 return self.MergeFromString(serialized)
177
178 def SerializeToString(self, **kwargs):
179 """Serializes the protocol message to a binary string.
180
181 Keyword Args:
182 deterministic (bool): If true, requests deterministic serialization
183 of the protobuf, with predictable ordering of map keys.
184
185 Returns:
186 A binary string representation of the message if all of the required
187 fields in the message are set (i.e. the message is initialized).
188
189 Raises:
190 EncodeError: if the message isn't initialized (see :func:`IsInitialized`).
191 """
192 raise NotImplementedError
193
194 def SerializePartialToString(self, **kwargs):
195 """Serializes the protocol message to a binary string.
196
197 This method is similar to SerializeToString but doesn't check if the
198 message is initialized.
199
200 Keyword Args:
201 deterministic (bool): If true, requests deterministic serialization
202 of the protobuf, with predictable ordering of map keys.
203
204 Returns:
205 bytes: A serialized representation of the partial message.
206 """
207 raise NotImplementedError
208
209 # TODO: Decide whether we like these better
210 # than auto-generated has_foo() and clear_foo() methods
211 # on the instances themselves. This way is less consistent
212 # with C++, but it makes reflection-type access easier and
213 # reduces the number of magically autogenerated things.
214 #
215 # TODO: Be sure to document (and test) exactly
216 # which field names are accepted here. Are we case-sensitive?
217 # What do we do with fields that share names with Python keywords
218 # like 'lambda' and 'yield'?
219 #
220 # nnorwitz says:
221 # """
222 # Typically (in python), an underscore is appended to names that are
223 # keywords. So they would become lambda_ or yield_.
224 # """
225 def ListFields(self):
226 """Returns a list of (FieldDescriptor, value) tuples for present fields.
227
228 A message field is non-empty if HasField() would return true. A singular
229 primitive field is non-empty if HasField() would return true in proto2 or it
230 is non zero in proto3. A repeated field is non-empty if it contains at least
231 one element. The fields are ordered by field number.
232
233 Returns:
234 list[tuple(FieldDescriptor, value)]: field descriptors and values
235 for all fields in the message which are not empty. The values vary by
236 field type.
237 """
238 raise NotImplementedError
239
240 def HasField(self, field_name):
241 """Checks if a certain field is set for the message.
242
243 For a oneof group, checks if any field inside is set. Note that if the
244 field_name is not defined in the message descriptor, :exc:`ValueError` will
245 be raised.
246
247 Args:
248 field_name (str): The name of the field to check for presence.
249
250 Returns:
251 bool: Whether a value has been set for the named field.
252
253 Raises:
254 ValueError: if the `field_name` is not a member of this message.
255 """
256 raise NotImplementedError
257
258 def ClearField(self, field_name):
259 """Clears the contents of a given field.
260
261 Inside a oneof group, clears the field set. If the name neither refers to a
262 defined field or oneof group, :exc:`ValueError` is raised.
263
264 Args:
265 field_name (str): The name of the field to check for presence.
266
267 Raises:
268 ValueError: if the `field_name` is not a member of this message.
269 """
270 raise NotImplementedError
271
272 def WhichOneof(self, oneof_group):
273 """Returns the name of the field that is set inside a oneof group.
274
275 If no field is set, returns None.
276
277 Args:
278 oneof_group (str): the name of the oneof group to check.
279
280 Returns:
281 str or None: The name of the group that is set, or None.
282
283 Raises:
284 ValueError: no group with the given name exists
285 """
286 raise NotImplementedError
287
288 def HasExtension(self, field_descriptor):
289 """Checks if a certain extension is present for this message.
290
291 Extensions are retrieved using the :attr:`Extensions` mapping (if present).
292
293 Args:
294 field_descriptor: The field descriptor for the extension to check.
295
296 Returns:
297 bool: Whether the extension is present for this message.
298
299 Raises:
300 KeyError: if the extension is repeated. Similar to repeated fields,
301 there is no separate notion of presence: a "not present" repeated
302 extension is an empty list.
303 """
304 raise NotImplementedError
305
306 def ClearExtension(self, field_descriptor):
307 """Clears the contents of a given extension.
308
309 Args:
310 field_descriptor: The field descriptor for the extension to clear.
311 """
312 raise NotImplementedError
313
314 def UnknownFields(self):
315 """Returns the UnknownFieldSet.
316
317 Returns:
318 UnknownFieldSet: The unknown fields stored in this message.
319 """
320 raise NotImplementedError
321
322 def DiscardUnknownFields(self):
323 """Clears all fields in the :class:`UnknownFieldSet`.
324
325 This operation is recursive for nested message.
326 """
327 raise NotImplementedError
328
329 def ByteSize(self):
330 """Returns the serialized size of this message.
331
332 Recursively calls ByteSize() on all contained messages.
333
334 Returns:
335 int: The number of bytes required to serialize this message.
336 """
337 raise NotImplementedError
338
339 @classmethod
340 def FromString(cls, s):
341 raise NotImplementedError
342
343# TODO: Remove it in OSS
344 @staticmethod
345 def RegisterExtension(field_descriptor):
346 raise NotImplementedError
347
348 def _SetListener(self, message_listener):
349 """Internal method used by the protocol message implementation.
350 Clients should not call this directly.
351
352 Sets a listener that this message will call on certain state transitions.
353
354 The purpose of this method is to register back-edges from children to
355 parents at runtime, for the purpose of setting "has" bits and
356 byte-size-dirty bits in the parent and ancestor objects whenever a child or
357 descendant object is modified.
358
359 If the client wants to disconnect this Message from the object tree, she
360 explicitly sets callback to None.
361
362 If message_listener is None, unregisters any existing listener. Otherwise,
363 message_listener must implement the MessageListener interface in
364 internal/message_listener.py, and we discard any listener registered
365 via a previous _SetListener() call.
366 """
367 raise NotImplementedError
368
369 def __getstate__(self):
370 """Support the pickle protocol."""
371 return dict(serialized=self.SerializePartialToString())
372
373 def __setstate__(self, state):
374 """Support the pickle protocol."""
375 self.__init__()
376 serialized = state['serialized']
377 # On Python 3, using encoding='latin1' is required for unpickling
378 # protos pickled by Python 2.
379 if not isinstance(serialized, bytes):
380 serialized = serialized.encode('latin1')
381 self.ParseFromString(serialized)
382
383 def __reduce__(self):
384 message_descriptor = self.DESCRIPTOR
385 if message_descriptor.containing_type is None:
386 return type(self), (), self.__getstate__()
387 # the message type must be nested.
388 # Python does not pickle nested classes; use the symbol_database on the
389 # receiving end.
390 container = message_descriptor
391 return (_InternalConstructMessage, (container.full_name,),
392 self.__getstate__())
393
394
395def _InternalConstructMessage(full_name):
396 """Constructs a nested message."""
397 from google.protobuf import symbol_database # pylint:disable=g-import-not-at-top
398
399 return symbol_database.Default().GetSymbol(full_name)()