OLD | NEW |
| (Empty) |
1 # Protocol Buffers - Google's data interchange format | |
2 # Copyright 2008 Google Inc. All rights reserved. | |
3 # http://code.google.com/p/protobuf/ | |
4 # | |
5 # Redistribution and use in source and binary forms, with or without | |
6 # modification, are permitted provided that the following conditions are | |
7 # met: | |
8 # | |
9 # * Redistributions of source code must retain the above copyright | |
10 # notice, this list of conditions and the following disclaimer. | |
11 # * Redistributions in binary form must reproduce the above | |
12 # copyright notice, this list of conditions and the following disclaimer | |
13 # in the documentation and/or other materials provided with the | |
14 # distribution. | |
15 # * Neither the name of Google Inc. nor the names of its | |
16 # contributors may be used to endorse or promote products derived from | |
17 # this software without specific prior written permission. | |
18 # | |
19 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
20 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
21 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
22 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
23 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
24 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
25 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
26 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
27 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
28 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
29 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
30 | |
31 # TODO(robinson): We should just make these methods all "pure-virtual" and move | |
32 # all implementation out, into reflection.py for now. | |
33 | |
34 | |
35 """Contains an abstract base class for protocol messages.""" | |
36 | |
37 __author__ = 'robinson@google.com (Will Robinson)' | |
38 | |
39 | |
40 class Error(Exception): pass | |
41 class DecodeError(Error): pass | |
42 class EncodeError(Error): pass | |
43 | |
44 | |
45 class Message(object): | |
46 | |
47 """Abstract base class for protocol messages. | |
48 | |
49 Protocol message classes are almost always generated by the protocol | |
50 compiler. These generated types subclass Message and implement the methods | |
51 shown below. | |
52 | |
53 TODO(robinson): Link to an HTML document here. | |
54 | |
55 TODO(robinson): Document that instances of this class will also | |
56 have an Extensions attribute with __getitem__ and __setitem__. | |
57 Again, not sure how to best convey this. | |
58 | |
59 TODO(robinson): Document that the class must also have a static | |
60 RegisterExtension(extension_field) method. | |
61 Not sure how to best express at this point. | |
62 """ | |
63 | |
64 # TODO(robinson): Document these fields and methods. | |
65 | |
66 __slots__ = [] | |
67 | |
68 DESCRIPTOR = None | |
69 | |
70 def __deepcopy__(self, memo=None): | |
71 clone = type(self)() | |
72 clone.MergeFrom(self) | |
73 return clone | |
74 | |
75 def __eq__(self, other_msg): | |
76 """Recursively compares two messages by value and structure.""" | |
77 raise NotImplementedError | |
78 | |
79 def __ne__(self, other_msg): | |
80 # Can't just say self != other_msg, since that would infinitely recurse. :) | |
81 return not self == other_msg | |
82 | |
83 def __hash__(self): | |
84 raise TypeError('unhashable object') | |
85 | |
86 def __str__(self): | |
87 """Outputs a human-readable representation of the message.""" | |
88 raise NotImplementedError | |
89 | |
90 def __unicode__(self): | |
91 """Outputs a human-readable representation of the message.""" | |
92 raise NotImplementedError | |
93 | |
94 def MergeFrom(self, other_msg): | |
95 """Merges the contents of the specified message into current message. | |
96 | |
97 This method merges the contents of the specified message into the current | |
98 message. Singular fields that are set in the specified message overwrite | |
99 the corresponding fields in the current message. Repeated fields are | |
100 appended. Singular sub-messages and groups are recursively merged. | |
101 | |
102 Args: | |
103 other_msg: Message to merge into the current message. | |
104 """ | |
105 raise NotImplementedError | |
106 | |
107 def CopyFrom(self, other_msg): | |
108 """Copies the content of the specified message into the current message. | |
109 | |
110 The method clears the current message and then merges the specified | |
111 message using MergeFrom. | |
112 | |
113 Args: | |
114 other_msg: Message to copy into the current one. | |
115 """ | |
116 if self is other_msg: | |
117 return | |
118 self.Clear() | |
119 self.MergeFrom(other_msg) | |
120 | |
121 def Clear(self): | |
122 """Clears all data that was set in the message.""" | |
123 raise NotImplementedError | |
124 | |
125 def SetInParent(self): | |
126 """Mark this as present in the parent. | |
127 | |
128 This normally happens automatically when you assign a field of a | |
129 sub-message, but sometimes you want to make the sub-message | |
130 present while keeping it empty. If you find yourself using this, | |
131 you may want to reconsider your design.""" | |
132 raise NotImplementedError | |
133 | |
134 def IsInitialized(self): | |
135 """Checks if the message is initialized. | |
136 | |
137 Returns: | |
138 The method returns True if the message is initialized (i.e. all of its | |
139 required fields are set). | |
140 """ | |
141 raise NotImplementedError | |
142 | |
143 # TODO(robinson): MergeFromString() should probably return None and be | |
144 # implemented in terms of a helper that returns the # of bytes read. Our | |
145 # deserialization routines would use the helper when recursively | |
146 # deserializing, but the end user would almost always just want the no-return | |
147 # MergeFromString(). | |
148 | |
149 def MergeFromString(self, serialized): | |
150 """Merges serialized protocol buffer data into this message. | |
151 | |
152 When we find a field in |serialized| that is already present | |
153 in this message: | |
154 - If it's a "repeated" field, we append to the end of our list. | |
155 - Else, if it's a scalar, we overwrite our field. | |
156 - Else, (it's a nonrepeated composite), we recursively merge | |
157 into the existing composite. | |
158 | |
159 TODO(robinson): Document handling of unknown fields. | |
160 | |
161 Args: | |
162 serialized: Any object that allows us to call buffer(serialized) | |
163 to access a string of bytes using the buffer interface. | |
164 | |
165 TODO(robinson): When we switch to a helper, this will return None. | |
166 | |
167 Returns: | |
168 The number of bytes read from |serialized|. | |
169 For non-group messages, this will always be len(serialized), | |
170 but for messages which are actually groups, this will | |
171 generally be less than len(serialized), since we must | |
172 stop when we reach an END_GROUP tag. Note that if | |
173 we *do* stop because of an END_GROUP tag, the number | |
174 of bytes returned does not include the bytes | |
175 for the END_GROUP tag information. | |
176 """ | |
177 raise NotImplementedError | |
178 | |
179 def ParseFromString(self, serialized): | |
180 """Parse serialized protocol buffer data into this message. | |
181 | |
182 Like MergeFromString(), except we clear the object first and | |
183 do not return the value that MergeFromString returns. | |
184 """ | |
185 self.Clear() | |
186 self.MergeFromString(serialized) | |
187 | |
188 def SerializeToString(self): | |
189 """Serializes the protocol message to a binary string. | |
190 | |
191 Returns: | |
192 A binary string representation of the message if all of the required | |
193 fields in the message are set (i.e. the message is initialized). | |
194 | |
195 Raises: | |
196 message.EncodeError if the message isn't initialized. | |
197 """ | |
198 raise NotImplementedError | |
199 | |
200 def SerializePartialToString(self): | |
201 """Serializes the protocol message to a binary string. | |
202 | |
203 This method is similar to SerializeToString but doesn't check if the | |
204 message is initialized. | |
205 | |
206 Returns: | |
207 A string representation of the partial message. | |
208 """ | |
209 raise NotImplementedError | |
210 | |
211 # TODO(robinson): Decide whether we like these better | |
212 # than auto-generated has_foo() and clear_foo() methods | |
213 # on the instances themselves. This way is less consistent | |
214 # with C++, but it makes reflection-type access easier and | |
215 # reduces the number of magically autogenerated things. | |
216 # | |
217 # TODO(robinson): Be sure to document (and test) exactly | |
218 # which field names are accepted here. Are we case-sensitive? | |
219 # What do we do with fields that share names with Python keywords | |
220 # like 'lambda' and 'yield'? | |
221 # | |
222 # nnorwitz says: | |
223 # """ | |
224 # Typically (in python), an underscore is appended to names that are | |
225 # keywords. So they would become lambda_ or yield_. | |
226 # """ | |
227 def ListFields(self): | |
228 """Returns a list of (FieldDescriptor, value) tuples for all | |
229 fields in the message which are not empty. A singular field is non-empty | |
230 if HasField() would return true, and a repeated field is non-empty if | |
231 it contains at least one element. The fields are ordered by field | |
232 number""" | |
233 raise NotImplementedError | |
234 | |
235 def HasField(self, field_name): | |
236 """Checks if a certain field is set for the message. Note if the | |
237 field_name is not defined in the message descriptor, ValueError will be | |
238 raised.""" | |
239 raise NotImplementedError | |
240 | |
241 def ClearField(self, field_name): | |
242 raise NotImplementedError | |
243 | |
244 def HasExtension(self, extension_handle): | |
245 raise NotImplementedError | |
246 | |
247 def ClearExtension(self, extension_handle): | |
248 raise NotImplementedError | |
249 | |
250 def ByteSize(self): | |
251 """Returns the serialized size of this message. | |
252 Recursively calls ByteSize() on all contained messages. | |
253 """ | |
254 raise NotImplementedError | |
255 | |
256 def _SetListener(self, message_listener): | |
257 """Internal method used by the protocol message implementation. | |
258 Clients should not call this directly. | |
259 | |
260 Sets a listener that this message will call on certain state transitions. | |
261 | |
262 The purpose of this method is to register back-edges from children to | |
263 parents at runtime, for the purpose of setting "has" bits and | |
264 byte-size-dirty bits in the parent and ancestor objects whenever a child or | |
265 descendant object is modified. | |
266 | |
267 If the client wants to disconnect this Message from the object tree, she | |
268 explicitly sets callback to None. | |
269 | |
270 If message_listener is None, unregisters any existing listener. Otherwise, | |
271 message_listener must implement the MessageListener interface in | |
272 internal/message_listener.py, and we discard any listener registered | |
273 via a previous _SetListener() call. | |
274 """ | |
275 raise NotImplementedError | |
276 | |
277 def __getstate__(self): | |
278 """Support the pickle protocol.""" | |
279 return dict(serialized=self.SerializePartialToString()) | |
280 | |
281 def __setstate__(self, state): | |
282 """Support the pickle protocol.""" | |
283 self.__init__() | |
284 self.ParseFromString(state['serialized']) | |
OLD | NEW |