PageRenderTime 47ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/thirdparty/google_appengine/lib/protorpc/protorpc/protobuf.py

https://code.google.com/
Python | 321 lines | 154 code | 49 blank | 118 comment | 22 complexity | 3aec6eb4b64ac0301d70d9a14517888a MD5 | raw file
Possible License(s): Apache-2.0, BSD-3-Clause, BSD-2-Clause, LGPL-2.1, GPL-2.0, MIT
  1. #!/usr/bin/env python
  2. #
  3. # Copyright 2010 Google Inc.
  4. #
  5. # Licensed under the Apache License, Version 2.0 (the "License");
  6. # you may not use this file except in compliance with the License.
  7. # You may obtain a copy of the License at
  8. #
  9. # http://www.apache.org/licenses/LICENSE-2.0
  10. #
  11. # Unless required by applicable law or agreed to in writing, software
  12. # distributed under the License is distributed on an "AS IS" BASIS,
  13. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. # See the License for the specific language governing permissions and
  15. # limitations under the License.
  16. #
  17. """Protocol buffer support for message types.
  18. For more details about protocol buffer encoding and decoding please see:
  19. http://code.google.com/apis/protocolbuffers/docs/encoding.html
  20. Public Exceptions:
  21. DecodeError: Raised when a decode error occurs from incorrect protobuf format.
  22. Public Functions:
  23. encode_message: Encodes a message in to a protocol buffer string.
  24. decode_message: Decode from a protocol buffer string to a message.
  25. """
  26. __author__ = 'rafek@google.com (Rafe Kaplan)'
  27. import array
  28. import cStringIO
  29. from . import messages
  30. # TODO(rafek): Do something about this dependency maybe.
  31. from google.net.proto import ProtocolBuffer
  32. __all__ = ['ALTERNATIVE_CONTENT_TYPES',
  33. 'CONTENT_TYPE',
  34. 'encode_message',
  35. 'decode_message',
  36. ]
  37. CONTENT_TYPE = 'application/octet-stream'
  38. ALTERNATIVE_CONTENT_TYPES = ['application/x-google-protobuf']
  39. class _Encoder(ProtocolBuffer.Encoder):
  40. """Extension of protocol buffer encoder.
  41. Original protocol buffer encoder does not have complete set of methods
  42. for handling required encoding. This class adds them.
  43. """
  44. # TODO(rafek): Implement the missing encoding types.
  45. def no_encoding(self, value):
  46. """No encoding available for type.
  47. Args:
  48. value: Value to encode.
  49. Raises:
  50. NotImplementedError at all times.
  51. """
  52. raise NotImplementedError()
  53. def encode_enum(self, value):
  54. """Encode an enum value.
  55. Args:
  56. value: Enum to encode.
  57. """
  58. self.putVarInt32(value.number)
  59. def encode_message(self, value):
  60. """Encode a Message in to an embedded message.
  61. Args:
  62. value: Message instance to encode.
  63. """
  64. self.putPrefixedString(encode_message(value))
  65. def encode_unicode_string(self, value):
  66. """Helper to properly pb encode unicode strings to UTF-8.
  67. Args:
  68. value: String value to encode.
  69. """
  70. if isinstance(value, unicode):
  71. value = value.encode('utf-8')
  72. self.putPrefixedString(value)
  73. class _Decoder(ProtocolBuffer.Decoder):
  74. """Extension of protocol buffer decoder.
  75. Original protocol buffer decoder does not have complete set of methods
  76. for handling required decoding. This class adds them.
  77. """
  78. # TODO(rafek): Implement the missing encoding types.
  79. def no_decoding(self):
  80. """No decoding available for type.
  81. Raises:
  82. NotImplementedError at all times.
  83. """
  84. raise NotImplementedError()
  85. def decode_string(self):
  86. """Decode a unicode string.
  87. Returns:
  88. Next value in stream as a unicode string.
  89. """
  90. return self.getPrefixedString().decode('UTF-8')
  91. def decode_boolean(self):
  92. """Decode a boolean value.
  93. Returns:
  94. Next value in stream as a boolean.
  95. """
  96. return bool(self.getBoolean())
  97. # Number of bits used to describe a protocol buffer bits used for the variant.
  98. _WIRE_TYPE_BITS = 3
  99. _WIRE_TYPE_MASK = 7
  100. # Maps variant to underlying wire type. Many variants map to same type.
  101. _VARIANT_TO_WIRE_TYPE = {
  102. messages.Variant.DOUBLE: _Encoder.DOUBLE,
  103. messages.Variant.FLOAT: _Encoder.FLOAT,
  104. messages.Variant.INT64: _Encoder.NUMERIC,
  105. messages.Variant.UINT64: _Encoder.NUMERIC,
  106. messages.Variant.INT32: _Encoder.NUMERIC,
  107. messages.Variant.BOOL: _Encoder.NUMERIC,
  108. messages.Variant.STRING: _Encoder.STRING,
  109. messages.Variant.MESSAGE: _Encoder.STRING,
  110. messages.Variant.BYTES: _Encoder.STRING,
  111. messages.Variant.UINT32: _Encoder.NUMERIC,
  112. messages.Variant.ENUM: _Encoder.NUMERIC,
  113. messages.Variant.SINT32: _Encoder.NUMERIC,
  114. messages.Variant.SINT64: _Encoder.NUMERIC,
  115. }
  116. # Maps variant to encoder method.
  117. _VARIANT_TO_ENCODER_MAP = {
  118. messages.Variant.DOUBLE: _Encoder.putDouble,
  119. messages.Variant.FLOAT: _Encoder.putFloat,
  120. messages.Variant.INT64: _Encoder.putVarInt64,
  121. messages.Variant.UINT64: _Encoder.putVarUint64,
  122. messages.Variant.INT32: _Encoder.putVarInt32,
  123. messages.Variant.BOOL: _Encoder.putBoolean,
  124. messages.Variant.STRING: _Encoder.encode_unicode_string,
  125. messages.Variant.MESSAGE: _Encoder.encode_message,
  126. messages.Variant.BYTES: _Encoder.encode_unicode_string,
  127. messages.Variant.UINT32: _Encoder.no_encoding,
  128. messages.Variant.ENUM: _Encoder.encode_enum,
  129. messages.Variant.SINT32: _Encoder.no_encoding,
  130. messages.Variant.SINT64: _Encoder.no_encoding,
  131. }
  132. # Basic wire format decoders. Used for skipping unknown values.
  133. _WIRE_TYPE_TO_DECODER_MAP = {
  134. _Encoder.NUMERIC: _Decoder.getVarInt32,
  135. _Encoder.DOUBLE: _Decoder.getDouble,
  136. _Encoder.STRING: _Decoder.getPrefixedString,
  137. _Encoder.FLOAT: _Decoder.getFloat,
  138. }
  139. # Wire type to name mapping for error messages.
  140. _WIRE_TYPE_NAME = {
  141. _Encoder.NUMERIC: 'NUMERIC',
  142. _Encoder.DOUBLE: 'DOUBLE',
  143. _Encoder.STRING: 'STRING',
  144. _Encoder.FLOAT: 'FLOAT',
  145. }
  146. # Maps variant to decoder method.
  147. _VARIANT_TO_DECODER_MAP = {
  148. messages.Variant.DOUBLE: _Decoder.getDouble,
  149. messages.Variant.FLOAT: _Decoder.getFloat,
  150. messages.Variant.INT64: _Decoder.getVarInt64,
  151. messages.Variant.UINT64: _Decoder.getVarUint64,
  152. messages.Variant.INT32: _Decoder.getVarInt32,
  153. messages.Variant.BOOL: _Decoder.decode_boolean,
  154. messages.Variant.STRING: _Decoder.decode_string,
  155. messages.Variant.MESSAGE: _Decoder.getPrefixedString,
  156. messages.Variant.BYTES: _Decoder.getPrefixedString,
  157. messages.Variant.UINT32: _Decoder.no_decoding,
  158. messages.Variant.ENUM: _Decoder.getVarInt32,
  159. messages.Variant.SINT32: _Decoder.no_decoding,
  160. messages.Variant.SINT64: _Decoder.no_decoding,
  161. }
  162. def encode_message(message):
  163. """Encode Message instance to protocol buffer.
  164. Args:
  165. Message instance to encode in to protocol buffer.
  166. Returns:
  167. String encoding of Message instance in protocol buffer format.
  168. Raises:
  169. messages.ValidationError if message is not initialized.
  170. """
  171. message.check_initialized()
  172. encoder = _Encoder()
  173. for field in sorted(message.all_fields(), key=lambda field: field.number):
  174. value = message.get_assigned_value(field.name)
  175. if value is not None:
  176. # Encode tag.
  177. tag = ((field.number << _WIRE_TYPE_BITS) |
  178. _VARIANT_TO_WIRE_TYPE[field.variant])
  179. # Write value to wire.
  180. if field.repeated:
  181. values = value
  182. else:
  183. values = [value]
  184. for next in values:
  185. encoder.putVarInt32(tag)
  186. field_encoder = _VARIANT_TO_ENCODER_MAP[field.variant]
  187. field_encoder(encoder, next)
  188. return encoder.buffer().tostring()
  189. def decode_message(message_type, encoded_message):
  190. """Decode protocol buffer to Message instance.
  191. Args:
  192. message_type: Message type to decode data to.
  193. encoded_message: Encoded version of message as string.
  194. Returns:
  195. Decoded instance of message_type.
  196. Raises:
  197. DecodeError if an error occurs during decoding, such as incompatible
  198. wire format for a field.
  199. messages.ValidationError if merged message is not initialized.
  200. """
  201. message = message_type()
  202. message_array = array.array('B')
  203. message_array.fromstring(encoded_message)
  204. try:
  205. decoder = _Decoder(message_array, 0, len(message_array))
  206. while decoder.avail() > 0:
  207. # Decode tag and variant information.
  208. encoded_tag = decoder.getVarInt32()
  209. tag = encoded_tag >> _WIRE_TYPE_BITS
  210. wire_type = encoded_tag & _WIRE_TYPE_MASK
  211. try:
  212. found_wire_type_decoder = _WIRE_TYPE_TO_DECODER_MAP[wire_type]
  213. except:
  214. raise messages.DecodeError('No such wire type %d' % wire_type)
  215. if tag < 1:
  216. raise messages.DecodeError('Invalid tag value %d' % tag)
  217. try:
  218. field = message.field_by_number(tag)
  219. except KeyError:
  220. # Unexpected tags are ok, just ignored unless below 0.
  221. field = None
  222. wire_type_decoder = found_wire_type_decoder
  223. else:
  224. expected_wire_type = _VARIANT_TO_WIRE_TYPE[field.variant]
  225. if expected_wire_type != wire_type:
  226. raise messages.DecodeError('Expected wire type %s but found %s' % (
  227. _WIRE_TYPE_NAME[expected_wire_type],
  228. _WIRE_TYPE_NAME[wire_type]))
  229. wire_type_decoder = _VARIANT_TO_DECODER_MAP[field.variant]
  230. value = wire_type_decoder(decoder)
  231. # Skip additional processing if unknown field.
  232. if not field:
  233. continue
  234. # Special case Enum and Message types.
  235. if isinstance(field, messages.EnumField):
  236. value = field.type(value)
  237. elif isinstance(field, messages.MessageField):
  238. nested_message = decode_message(field.type, value)
  239. value = nested_message
  240. # Merge value in to message.
  241. if field.repeated:
  242. values = getattr(message, field.name)
  243. if values is None:
  244. setattr(message, field.name, [value])
  245. else:
  246. values.append(value)
  247. else:
  248. setattr(message, field.name, value)
  249. except ProtocolBuffer.ProtocolBufferDecodeError, err:
  250. raise messages.DecodeError('Decoding error: %s' % str(err))
  251. message.check_initialized()
  252. return message