Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(448)

Side by Side Diff: recipe_engine/third_party/google/protobuf/json_format.py

Issue 2236673002: Bump vendoring, move to proto3 release. (Closed) Base URL: https://github.com/luci/recipes-py@master
Patch Set: Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 # Protocol Buffers - Google's data interchange format 1 # Protocol Buffers - Google's data interchange format
2 # Copyright 2008 Google Inc. All rights reserved. 2 # Copyright 2008 Google Inc. All rights reserved.
3 # https://developers.google.com/protocol-buffers/ 3 # https://developers.google.com/protocol-buffers/
4 # 4 #
5 # Redistribution and use in source and binary forms, with or without 5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions are 6 # modification, are permitted provided that the following conditions are
7 # met: 7 # met:
8 # 8 #
9 # * Redistributions of source code must retain the above copyright 9 # * Redistributions of source code must retain the above copyright
10 # notice, this list of conditions and the following disclaimer. 10 # notice, this list of conditions and the following disclaimer.
(...skipping 24 matching lines...) Expand all
35 # Create a proto object and serialize it to a json format string. 35 # Create a proto object and serialize it to a json format string.
36 message = my_proto_pb2.MyMessage(foo='bar') 36 message = my_proto_pb2.MyMessage(foo='bar')
37 json_string = json_format.MessageToJson(message) 37 json_string = json_format.MessageToJson(message)
38 38
39 # Parse a json format string to proto object. 39 # Parse a json format string to proto object.
40 message = json_format.Parse(json_string, my_proto_pb2.MyMessage()) 40 message = json_format.Parse(json_string, my_proto_pb2.MyMessage())
41 """ 41 """
42 42
43 __author__ = 'jieluo@google.com (Jie Luo)' 43 __author__ = 'jieluo@google.com (Jie Luo)'
44 44
45 try:
46 from collections import OrderedDict
47 except ImportError:
48 from ordereddict import OrderedDict #PY26
45 import base64 49 import base64
46 import json 50 import json
47 import math 51 import math
52 import re
48 import six 53 import six
49 import sys 54 import sys
50 55
56 from operator import methodcaller
51 from google.protobuf import descriptor 57 from google.protobuf import descriptor
52 from google.protobuf import symbol_database 58 from google.protobuf import symbol_database
53 59
54 _TIMESTAMPFOMAT = '%Y-%m-%dT%H:%M:%S' 60 _TIMESTAMPFOMAT = '%Y-%m-%dT%H:%M:%S'
55 _INT_TYPES = frozenset([descriptor.FieldDescriptor.CPPTYPE_INT32, 61 _INT_TYPES = frozenset([descriptor.FieldDescriptor.CPPTYPE_INT32,
56 descriptor.FieldDescriptor.CPPTYPE_UINT32, 62 descriptor.FieldDescriptor.CPPTYPE_UINT32,
57 descriptor.FieldDescriptor.CPPTYPE_INT64, 63 descriptor.FieldDescriptor.CPPTYPE_INT64,
58 descriptor.FieldDescriptor.CPPTYPE_UINT64]) 64 descriptor.FieldDescriptor.CPPTYPE_UINT64])
59 _INT64_TYPES = frozenset([descriptor.FieldDescriptor.CPPTYPE_INT64, 65 _INT64_TYPES = frozenset([descriptor.FieldDescriptor.CPPTYPE_INT64,
60 descriptor.FieldDescriptor.CPPTYPE_UINT64]) 66 descriptor.FieldDescriptor.CPPTYPE_UINT64])
61 _FLOAT_TYPES = frozenset([descriptor.FieldDescriptor.CPPTYPE_FLOAT, 67 _FLOAT_TYPES = frozenset([descriptor.FieldDescriptor.CPPTYPE_FLOAT,
62 descriptor.FieldDescriptor.CPPTYPE_DOUBLE]) 68 descriptor.FieldDescriptor.CPPTYPE_DOUBLE])
63 _INFINITY = 'Infinity' 69 _INFINITY = 'Infinity'
64 _NEG_INFINITY = '-Infinity' 70 _NEG_INFINITY = '-Infinity'
65 _NAN = 'NaN' 71 _NAN = 'NaN'
66 72
73 _UNPAIRED_SURROGATE_PATTERN = re.compile(six.u(
74 r'[\ud800-\udbff](?![\udc00-\udfff])|(?<![\ud800-\udbff])[\udc00-\udfff]'
75 ))
67 76
68 class Error(Exception): 77 class Error(Exception):
69 """Top-level module error for json_format.""" 78 """Top-level module error for json_format."""
70 79
71 80
72 class SerializeToJsonError(Error): 81 class SerializeToJsonError(Error):
73 """Thrown if serialization to JSON fails.""" 82 """Thrown if serialization to JSON fails."""
74 83
75 84
76 class ParseError(Error): 85 class ParseError(Error):
77 """Thrown in case of parsing error.""" 86 """Thrown in case of parsing error."""
78 87
79 88
80 def MessageToJson(message, including_default_value_fields=False): 89 def MessageToJson(message, including_default_value_fields=False):
81 """Converts protobuf message to JSON format. 90 """Converts protobuf message to JSON format.
82 91
83 Args: 92 Args:
84 message: The protocol buffers message instance to serialize. 93 message: The protocol buffers message instance to serialize.
85 including_default_value_fields: If True, singular primitive fields, 94 including_default_value_fields: If True, singular primitive fields,
86 repeated fields, and map fields will always be serialized. If 95 repeated fields, and map fields will always be serialized. If
87 False, only serialize non-empty fields. Singular message fields 96 False, only serialize non-empty fields. Singular message fields
88 and oneof fields are not affected by this option. 97 and oneof fields are not affected by this option.
89 98
90 Returns: 99 Returns:
91 A string containing the JSON formatted protocol buffer message. 100 A string containing the JSON formatted protocol buffer message.
92 """ 101 """
93 js = _MessageToJsonObject(message, including_default_value_fields) 102 printer = _Printer(including_default_value_fields)
94 return json.dumps(js, indent=2) 103 return printer.ToJsonString(message)
95
96
97 def _MessageToJsonObject(message, including_default_value_fields):
98 """Converts message to an object according to Proto3 JSON Specification."""
99 message_descriptor = message.DESCRIPTOR
100 full_name = message_descriptor.full_name
101 if _IsWrapperMessage(message_descriptor):
102 return _WrapperMessageToJsonObject(message)
103 if full_name in _WKTJSONMETHODS:
104 return _WKTJSONMETHODS[full_name][0](
105 message, including_default_value_fields)
106 js = {}
107 return _RegularMessageToJsonObject(
108 message, js, including_default_value_fields)
109 104
110 105
111 def _IsMapEntry(field): 106 def _IsMapEntry(field):
112 return (field.type == descriptor.FieldDescriptor.TYPE_MESSAGE and 107 return (field.type == descriptor.FieldDescriptor.TYPE_MESSAGE and
113 field.message_type.has_options and 108 field.message_type.has_options and
114 field.message_type.GetOptions().map_entry) 109 field.message_type.GetOptions().map_entry)
115 110
116 111
117 def _RegularMessageToJsonObject(message, js, including_default_value_fields): 112 class _Printer(object):
118 """Converts normal message according to Proto3 JSON Specification.""" 113 """JSON format printer for protocol message."""
119 fields = message.ListFields()
120 include_default = including_default_value_fields
121 114
122 try: 115 def __init__(self,
123 for field, value in fields: 116 including_default_value_fields=False):
124 name = field.camelcase_name 117 self.including_default_value_fields = including_default_value_fields
125 if _IsMapEntry(field): 118
126 # Convert a map field. 119 def ToJsonString(self, message):
127 v_field = field.message_type.fields_by_name['value'] 120 js = self._MessageToJsonObject(message)
128 js_map = {} 121 return json.dumps(js, indent=2)
129 for key in value: 122
130 if isinstance(key, bool): 123 def _MessageToJsonObject(self, message):
131 if key: 124 """Converts message to an object according to Proto3 JSON Specification."""
132 recorded_key = 'true' 125 message_descriptor = message.DESCRIPTOR
126 full_name = message_descriptor.full_name
127 if _IsWrapperMessage(message_descriptor):
128 return self._WrapperMessageToJsonObject(message)
129 if full_name in _WKTJSONMETHODS:
130 return methodcaller(_WKTJSONMETHODS[full_name][0], message)(self)
131 js = {}
132 return self._RegularMessageToJsonObject(message, js)
133
134 def _RegularMessageToJsonObject(self, message, js):
135 """Converts normal message according to Proto3 JSON Specification."""
136 fields = message.ListFields()
137
138 try:
139 for field, value in fields:
140 name = field.camelcase_name
141 if _IsMapEntry(field):
142 # Convert a map field.
143 v_field = field.message_type.fields_by_name['value']
144 js_map = {}
145 for key in value:
146 if isinstance(key, bool):
147 if key:
148 recorded_key = 'true'
149 else:
150 recorded_key = 'false'
133 else: 151 else:
134 recorded_key = 'false' 152 recorded_key = key
153 js_map[recorded_key] = self._FieldToJsonObject(
154 v_field, value[key])
155 js[name] = js_map
156 elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
157 # Convert a repeated field.
158 js[name] = [self._FieldToJsonObject(field, k)
159 for k in value]
160 else:
161 js[name] = self._FieldToJsonObject(field, value)
162
163 # Serialize default value if including_default_value_fields is True.
164 if self.including_default_value_fields:
165 message_descriptor = message.DESCRIPTOR
166 for field in message_descriptor.fields:
167 # Singular message fields and oneof fields will not be affected.
168 if ((field.label != descriptor.FieldDescriptor.LABEL_REPEATED and
169 field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE) or
170 field.containing_oneof):
171 continue
172 name = field.camelcase_name
173 if name in js:
174 # Skip the field which has been serailized already.
175 continue
176 if _IsMapEntry(field):
177 js[name] = {}
178 elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
179 js[name] = []
135 else: 180 else:
136 recorded_key = key 181 js[name] = self._FieldToJsonObject(field, field.default_value)
137 js_map[recorded_key] = _FieldToJsonObject( 182
138 v_field, value[key], including_default_value_fields) 183 except ValueError as e:
139 js[name] = js_map 184 raise SerializeToJsonError(
140 elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED: 185 'Failed to serialize {0} field: {1}.'.format(field.name, e))
141 # Convert a repeated field. 186
142 js[name] = [_FieldToJsonObject(field, k, include_default) 187 return js
143 for k in value] 188
189 def _FieldToJsonObject(self, field, value):
190 """Converts field value according to Proto3 JSON Specification."""
191 if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
192 return self._MessageToJsonObject(value)
193 elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_ENUM:
194 enum_value = field.enum_type.values_by_number.get(value, None)
195 if enum_value is not None:
196 return enum_value.name
144 else: 197 else:
145 js[name] = _FieldToJsonObject(field, value, include_default) 198 raise SerializeToJsonError('Enum field contains an integer value '
199 'which can not mapped to an enum value.')
200 elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_STRING:
201 if field.type == descriptor.FieldDescriptor.TYPE_BYTES:
202 # Use base64 Data encoding for bytes
203 return base64.b64encode(value).decode('utf-8')
204 else:
205 return value
206 elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_BOOL:
207 return bool(value)
208 elif field.cpp_type in _INT64_TYPES:
209 return str(value)
210 elif field.cpp_type in _FLOAT_TYPES:
211 if math.isinf(value):
212 if value < 0.0:
213 return _NEG_INFINITY
214 else:
215 return _INFINITY
216 if math.isnan(value):
217 return _NAN
218 return value
146 219
147 # Serialize default value if including_default_value_fields is True. 220 def _AnyMessageToJsonObject(self, message):
148 if including_default_value_fields: 221 """Converts Any message according to Proto3 JSON Specification."""
149 message_descriptor = message.DESCRIPTOR 222 if not message.ListFields():
150 for field in message_descriptor.fields: 223 return {}
151 # Singular message fields and oneof fields will not be affected. 224 # Must print @type first, use OrderedDict instead of {}
152 if ((field.label != descriptor.FieldDescriptor.LABEL_REPEATED and 225 js = OrderedDict()
153 field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE) or 226 type_url = message.type_url
154 field.containing_oneof): 227 js['@type'] = type_url
155 continue 228 sub_message = _CreateMessageFromTypeUrl(type_url)
156 name = field.camelcase_name 229 sub_message.ParseFromString(message.value)
157 if name in js: 230 message_descriptor = sub_message.DESCRIPTOR
158 # Skip the field which has been serailized already. 231 full_name = message_descriptor.full_name
159 continue 232 if _IsWrapperMessage(message_descriptor):
160 if _IsMapEntry(field): 233 js['value'] = self._WrapperMessageToJsonObject(sub_message)
161 js[name] = {} 234 return js
162 elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED: 235 if full_name in _WKTJSONMETHODS:
163 js[name] = [] 236 js['value'] = methodcaller(_WKTJSONMETHODS[full_name][0],
164 else: 237 sub_message)(self)
165 js[name] = _FieldToJsonObject(field, field.default_value) 238 return js
239 return self._RegularMessageToJsonObject(sub_message, js)
166 240
167 except ValueError as e: 241 def _GenericMessageToJsonObject(self, message):
168 raise SerializeToJsonError( 242 """Converts message according to Proto3 JSON Specification."""
169 'Failed to serialize {0} field: {1}.'.format(field.name, e)) 243 # Duration, Timestamp and FieldMask have ToJsonString method to do the
244 # convert. Users can also call the method directly.
245 return message.ToJsonString()
170 246
171 return js 247 def _ValueMessageToJsonObject(self, message):
248 """Converts Value message according to Proto3 JSON Specification."""
249 which = message.WhichOneof('kind')
250 # If the Value message is not set treat as null_value when serialize
251 # to JSON. The parse back result will be different from original message.
252 if which is None or which == 'null_value':
253 return None
254 if which == 'list_value':
255 return self._ListValueMessageToJsonObject(message.list_value)
256 if which == 'struct_value':
257 value = message.struct_value
258 else:
259 value = getattr(message, which)
260 oneof_descriptor = message.DESCRIPTOR.fields_by_name[which]
261 return self._FieldToJsonObject(oneof_descriptor, value)
172 262
263 def _ListValueMessageToJsonObject(self, message):
264 """Converts ListValue message according to Proto3 JSON Specification."""
265 return [self._ValueMessageToJsonObject(value)
266 for value in message.values]
173 267
174 def _FieldToJsonObject( 268 def _StructMessageToJsonObject(self, message):
175 field, value, including_default_value_fields=False): 269 """Converts Struct message according to Proto3 JSON Specification."""
176 """Converts field value according to Proto3 JSON Specification.""" 270 fields = message.fields
177 if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE: 271 ret = {}
178 return _MessageToJsonObject(value, including_default_value_fields) 272 for key in fields:
179 elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_ENUM: 273 ret[key] = self._ValueMessageToJsonObject(fields[key])
180 enum_value = field.enum_type.values_by_number.get(value, None) 274 return ret
181 if enum_value is not None:
182 return enum_value.name
183 else:
184 raise SerializeToJsonError('Enum field contains an integer value '
185 'which can not mapped to an enum value.')
186 elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_STRING:
187 if field.type == descriptor.FieldDescriptor.TYPE_BYTES:
188 # Use base64 Data encoding for bytes
189 return base64.b64encode(value).decode('utf-8')
190 else:
191 return value
192 elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_BOOL:
193 return bool(value)
194 elif field.cpp_type in _INT64_TYPES:
195 return str(value)
196 elif field.cpp_type in _FLOAT_TYPES:
197 if math.isinf(value):
198 if value < 0.0:
199 return _NEG_INFINITY
200 else:
201 return _INFINITY
202 if math.isnan(value):
203 return _NAN
204 return value
205 275
206 276 def _WrapperMessageToJsonObject(self, message):
207 def _AnyMessageToJsonObject(message, including_default): 277 return self._FieldToJsonObject(
208 """Converts Any message according to Proto3 JSON Specification.""" 278 message.DESCRIPTOR.fields_by_name['value'], message.value)
209 if not message.ListFields():
210 return {}
211 js = {}
212 type_url = message.type_url
213 js['@type'] = type_url
214 sub_message = _CreateMessageFromTypeUrl(type_url)
215 sub_message.ParseFromString(message.value)
216 message_descriptor = sub_message.DESCRIPTOR
217 full_name = message_descriptor.full_name
218 if _IsWrapperMessage(message_descriptor):
219 js['value'] = _WrapperMessageToJsonObject(sub_message)
220 return js
221 if full_name in _WKTJSONMETHODS:
222 js['value'] = _WKTJSONMETHODS[full_name][0](sub_message, including_default)
223 return js
224 return _RegularMessageToJsonObject(sub_message, js, including_default)
225
226
227 def _CreateMessageFromTypeUrl(type_url):
228 # TODO(jieluo): Should add a way that users can register the type resolver
229 # instead of the default one.
230 db = symbol_database.Default()
231 type_name = type_url.split('/')[-1]
232 try:
233 message_descriptor = db.pool.FindMessageTypeByName(type_name)
234 except KeyError:
235 raise TypeError(
236 'Can not find message descriptor by type_url: {0}.'.format(type_url))
237 message_class = db.GetPrototype(message_descriptor)
238 return message_class()
239
240
241 def _GenericMessageToJsonObject(message, unused_including_default):
242 """Converts message by ToJsonString according to Proto3 JSON Specification."""
243 # Duration, Timestamp and FieldMask have ToJsonString method to do the
244 # convert. Users can also call the method directly.
245 return message.ToJsonString()
246
247
248 def _ValueMessageToJsonObject(message, unused_including_default=False):
249 """Converts Value message according to Proto3 JSON Specification."""
250 which = message.WhichOneof('kind')
251 # If the Value message is not set treat as null_value when serialize
252 # to JSON. The parse back result will be different from original message.
253 if which is None or which == 'null_value':
254 return None
255 if which == 'list_value':
256 return _ListValueMessageToJsonObject(message.list_value)
257 if which == 'struct_value':
258 value = message.struct_value
259 else:
260 value = getattr(message, which)
261 oneof_descriptor = message.DESCRIPTOR.fields_by_name[which]
262 return _FieldToJsonObject(oneof_descriptor, value)
263
264
265 def _ListValueMessageToJsonObject(message, unused_including_default=False):
266 """Converts ListValue message according to Proto3 JSON Specification."""
267 return [_ValueMessageToJsonObject(value)
268 for value in message.values]
269
270
271 def _StructMessageToJsonObject(message, unused_including_default=False):
272 """Converts Struct message according to Proto3 JSON Specification."""
273 fields = message.fields
274 ret = {}
275 for key in fields:
276 ret[key] = _ValueMessageToJsonObject(fields[key])
277 return ret
278 279
279 280
280 def _IsWrapperMessage(message_descriptor): 281 def _IsWrapperMessage(message_descriptor):
281 return message_descriptor.file.name == 'google/protobuf/wrappers.proto' 282 return message_descriptor.file.name == 'google/protobuf/wrappers.proto'
282 283
283 284
284 def _WrapperMessageToJsonObject(message):
285 return _FieldToJsonObject(
286 message.DESCRIPTOR.fields_by_name['value'], message.value)
287
288
289 def _DuplicateChecker(js): 285 def _DuplicateChecker(js):
290 result = {} 286 result = {}
291 for name, value in js: 287 for name, value in js:
292 if name in result: 288 if name in result:
293 raise ParseError('Failed to load JSON: duplicate key {0}.'.format(name)) 289 raise ParseError('Failed to load JSON: duplicate key {0}.'.format(name))
294 result[name] = value 290 result[name] = value
295 return result 291 return result
296 292
297 293
298 def Parse(text, message): 294 def _CreateMessageFromTypeUrl(type_url):
295 # TODO(jieluo): Should add a way that users can register the type resolver
296 # instead of the default one.
297 db = symbol_database.Default()
298 type_name = type_url.split('/')[-1]
299 try:
300 message_descriptor = db.pool.FindMessageTypeByName(type_name)
301 except KeyError:
302 raise TypeError(
303 'Can not find message descriptor by type_url: {0}.'.format(type_url))
304 message_class = db.GetPrototype(message_descriptor)
305 return message_class()
306
307
308 def Parse(text, message, ignore_unknown_fields=False):
299 """Parses a JSON representation of a protocol message into a message. 309 """Parses a JSON representation of a protocol message into a message.
300 310
301 Args: 311 Args:
302 text: Message JSON representation. 312 text: Message JSON representation.
303 message: A protocol beffer message to merge into. 313 message: A protocol beffer message to merge into.
314 ignore_unknown_fields: If True, do not raise errors for unknown fields.
304 315
305 Returns: 316 Returns:
306 The same message passed as argument. 317 The same message passed as argument.
307 318
308 Raises:: 319 Raises::
309 ParseError: On JSON parsing problems. 320 ParseError: On JSON parsing problems.
310 """ 321 """
311 if not isinstance(text, six.text_type): text = text.decode('utf-8') 322 if not isinstance(text, six.text_type): text = text.decode('utf-8')
312 try: 323 try:
313 if sys.version_info < (2, 7): 324 if sys.version_info < (2, 7):
314 # object_pair_hook is not supported before python2.7 325 # object_pair_hook is not supported before python2.7
315 js = json.loads(text) 326 js = json.loads(text)
316 else: 327 else:
317 js = json.loads(text, object_pairs_hook=_DuplicateChecker) 328 js = json.loads(text, object_pairs_hook=_DuplicateChecker)
318 except ValueError as e: 329 except ValueError as e:
319 raise ParseError('Failed to load JSON: {0}.'.format(str(e))) 330 raise ParseError('Failed to load JSON: {0}.'.format(str(e)))
320 _ConvertMessage(js, message) 331 parser = _Parser(ignore_unknown_fields)
332 parser.ConvertMessage(js, message)
321 return message 333 return message
322 334
323 335
324 def _ConvertFieldValuePair(js, message): 336 _INT_OR_FLOAT = six.integer_types + (float,)
325 """Convert field value pairs into regular message. 337
326 338
327 Args: 339 class _Parser(object):
328 js: A JSON object to convert the field value pairs. 340 """JSON format parser for protocol message."""
329 message: A regular protocol message to record the data. 341
330 342 def __init__(self,
331 Raises: 343 ignore_unknown_fields):
332 ParseError: In case of problems converting. 344 self.ignore_unknown_fields = ignore_unknown_fields
333 """ 345
334 names = [] 346 def ConvertMessage(self, value, message):
335 message_descriptor = message.DESCRIPTOR 347 """Convert a JSON object into a message.
336 for name in js: 348
349 Args:
350 value: A JSON object.
351 message: A WKT or regular protocol message to record the data.
352
353 Raises:
354 ParseError: In case of convert problems.
355 """
356 message_descriptor = message.DESCRIPTOR
357 full_name = message_descriptor.full_name
358 if _IsWrapperMessage(message_descriptor):
359 self._ConvertWrapperMessage(value, message)
360 elif full_name in _WKTJSONMETHODS:
361 methodcaller(_WKTJSONMETHODS[full_name][1], value, message)(self)
362 else:
363 self._ConvertFieldValuePair(value, message)
364
365 def _ConvertFieldValuePair(self, js, message):
366 """Convert field value pairs into regular message.
367
368 Args:
369 js: A JSON object to convert the field value pairs.
370 message: A regular protocol message to record the data.
371
372 Raises:
373 ParseError: In case of problems converting.
374 """
375 names = []
376 message_descriptor = message.DESCRIPTOR
377 for name in js:
378 try:
379 field = message_descriptor.fields_by_camelcase_name.get(name, None)
380 if not field:
381 if self.ignore_unknown_fields:
382 continue
383 raise ParseError(
384 'Message type "{0}" has no field named "{1}".'.format(
385 message_descriptor.full_name, name))
386 if name in names:
387 raise ParseError('Message type "{0}" should not have multiple '
388 '"{1}" fields.'.format(
389 message.DESCRIPTOR.full_name, name))
390 names.append(name)
391 # Check no other oneof field is parsed.
392 if field.containing_oneof is not None:
393 oneof_name = field.containing_oneof.name
394 if oneof_name in names:
395 raise ParseError('Message type "{0}" should not have multiple '
396 '"{1}" oneof fields.'.format(
397 message.DESCRIPTOR.full_name, oneof_name))
398 names.append(oneof_name)
399
400 value = js[name]
401 if value is None:
402 message.ClearField(field.name)
403 continue
404
405 # Parse field value.
406 if _IsMapEntry(field):
407 message.ClearField(field.name)
408 self._ConvertMapFieldValue(value, message, field)
409 elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
410 message.ClearField(field.name)
411 if not isinstance(value, list):
412 raise ParseError('repeated field {0} must be in [] which is '
413 '{1}.'.format(name, value))
414 if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
415 # Repeated message field.
416 for item in value:
417 sub_message = getattr(message, field.name).add()
418 # None is a null_value in Value.
419 if (item is None and
420 sub_message.DESCRIPTOR.full_name != 'google.protobuf.Value'):
421 raise ParseError('null is not allowed to be used as an element'
422 ' in a repeated field.')
423 self.ConvertMessage(item, sub_message)
424 else:
425 # Repeated scalar field.
426 for item in value:
427 if item is None:
428 raise ParseError('null is not allowed to be used as an element'
429 ' in a repeated field.')
430 getattr(message, field.name).append(
431 _ConvertScalarFieldValue(item, field))
432 elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
433 sub_message = getattr(message, field.name)
434 self.ConvertMessage(value, sub_message)
435 else:
436 setattr(message, field.name, _ConvertScalarFieldValue(value, field))
437 except ParseError as e:
438 if field and field.containing_oneof is None:
439 raise ParseError('Failed to parse {0} field: {1}'.format(name, e))
440 else:
441 raise ParseError(str(e))
442 except ValueError as e:
443 raise ParseError('Failed to parse {0} field: {1}.'.format(name, e))
444 except TypeError as e:
445 raise ParseError('Failed to parse {0} field: {1}.'.format(name, e))
446
447 def _ConvertAnyMessage(self, value, message):
448 """Convert a JSON representation into Any message."""
449 if isinstance(value, dict) and not value:
450 return
337 try: 451 try:
338 field = message_descriptor.fields_by_camelcase_name.get(name, None) 452 type_url = value['@type']
339 if not field: 453 except KeyError:
340 raise ParseError( 454 raise ParseError('@type is missing when parsing any message.')
341 'Message type "{0}" has no field named "{1}".'.format( 455
342 message_descriptor.full_name, name)) 456 sub_message = _CreateMessageFromTypeUrl(type_url)
343 if name in names: 457 message_descriptor = sub_message.DESCRIPTOR
344 raise ParseError( 458 full_name = message_descriptor.full_name
345 'Message type "{0}" should not have multiple "{1}" fields.'.format( 459 if _IsWrapperMessage(message_descriptor):
346 message.DESCRIPTOR.full_name, name)) 460 self._ConvertWrapperMessage(value['value'], sub_message)
347 names.append(name) 461 elif full_name in _WKTJSONMETHODS:
348 # Check no other oneof field is parsed. 462 methodcaller(
349 if field.containing_oneof is not None: 463 _WKTJSONMETHODS[full_name][1], value['value'], sub_message)(self)
350 oneof_name = field.containing_oneof.name 464 else:
351 if oneof_name in names: 465 del value['@type']
352 raise ParseError('Message type "{0}" should not have multiple "{1}" ' 466 self._ConvertFieldValuePair(value, sub_message)
353 'oneof fields.'.format( 467 # Sets Any message
354 message.DESCRIPTOR.full_name, oneof_name)) 468 message.value = sub_message.SerializeToString()
355 names.append(oneof_name) 469 message.type_url = type_url
356 470
357 value = js[name] 471 def _ConvertGenericMessage(self, value, message):
358 if value is None: 472 """Convert a JSON representation into message with FromJsonString."""
359 message.ClearField(field.name) 473 # Durantion, Timestamp, FieldMask have FromJsonString method to do the
360 continue 474 # convert. Users can also call the method directly.
361 475 message.FromJsonString(value)
362 # Parse field value. 476
363 if _IsMapEntry(field): 477 def _ConvertValueMessage(self, value, message):
364 message.ClearField(field.name) 478 """Convert a JSON representation into Value message."""
365 _ConvertMapFieldValue(value, message, field) 479 if isinstance(value, dict):
366 elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED: 480 self._ConvertStructMessage(value, message.struct_value)
367 message.ClearField(field.name) 481 elif isinstance(value, list):
368 if not isinstance(value, list): 482 self. _ConvertListValueMessage(value, message.list_value)
369 raise ParseError('repeated field {0} must be in [] which is ' 483 elif value is None:
370 '{1}.'.format(name, value)) 484 message.null_value = 0
371 if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE: 485 elif isinstance(value, bool):
372 # Repeated message field. 486 message.bool_value = value
373 for item in value: 487 elif isinstance(value, six.string_types):
374 sub_message = getattr(message, field.name).add() 488 message.string_value = value
375 # None is a null_value in Value. 489 elif isinstance(value, _INT_OR_FLOAT):
376 if (item is None and 490 message.number_value = value
377 sub_message.DESCRIPTOR.full_name != 'google.protobuf.Value'): 491 else:
378 raise ParseError('null is not allowed to be used as an element' 492 raise ParseError('Unexpected type for Value message.')
379 ' in a repeated field.') 493
380 _ConvertMessage(item, sub_message) 494 def _ConvertListValueMessage(self, value, message):
381 else: 495 """Convert a JSON representation into ListValue message."""
382 # Repeated scalar field. 496 if not isinstance(value, list):
383 for item in value: 497 raise ParseError(
384 if item is None: 498 'ListValue must be in [] which is {0}.'.format(value))
385 raise ParseError('null is not allowed to be used as an element' 499 message.ClearField('values')
386 ' in a repeated field.') 500 for item in value:
387 getattr(message, field.name).append( 501 self._ConvertValueMessage(item, message.values.add())
388 _ConvertScalarFieldValue(item, field)) 502
389 elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE: 503 def _ConvertStructMessage(self, value, message):
390 sub_message = getattr(message, field.name) 504 """Convert a JSON representation into Struct message."""
391 _ConvertMessage(value, sub_message) 505 if not isinstance(value, dict):
506 raise ParseError(
507 'Struct must be in a dict which is {0}.'.format(value))
508 for key in value:
509 self._ConvertValueMessage(value[key], message.fields[key])
510 return
511
512 def _ConvertWrapperMessage(self, value, message):
513 """Convert a JSON representation into Wrapper message."""
514 field = message.DESCRIPTOR.fields_by_name['value']
515 setattr(message, 'value', _ConvertScalarFieldValue(value, field))
516
517 def _ConvertMapFieldValue(self, value, message, field):
518 """Convert map field value for a message map field.
519
520 Args:
521 value: A JSON object to convert the map field value.
522 message: A protocol message to record the converted data.
523 field: The descriptor of the map field to be converted.
524
525 Raises:
526 ParseError: In case of convert problems.
527 """
528 if not isinstance(value, dict):
529 raise ParseError(
530 'Map field {0} must be in a dict which is {1}.'.format(
531 field.name, value))
532 key_field = field.message_type.fields_by_name['key']
533 value_field = field.message_type.fields_by_name['value']
534 for key in value:
535 key_value = _ConvertScalarFieldValue(key, key_field, True)
536 if value_field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
537 self.ConvertMessage(value[key], getattr(
538 message, field.name)[key_value])
392 else: 539 else:
393 setattr(message, field.name, _ConvertScalarFieldValue(value, field)) 540 getattr(message, field.name)[key_value] = _ConvertScalarFieldValue(
394 except ParseError as e: 541 value[key], value_field)
395 if field and field.containing_oneof is None:
396 raise ParseError('Failed to parse {0} field: {1}'.format(name, e))
397 else:
398 raise ParseError(str(e))
399 except ValueError as e:
400 raise ParseError('Failed to parse {0} field: {1}.'.format(name, e))
401 except TypeError as e:
402 raise ParseError('Failed to parse {0} field: {1}.'.format(name, e))
403
404
405 def _ConvertMessage(value, message):
406 """Convert a JSON object into a message.
407
408 Args:
409 value: A JSON object.
410 message: A WKT or regular protocol message to record the data.
411
412 Raises:
413 ParseError: In case of convert problems.
414 """
415 message_descriptor = message.DESCRIPTOR
416 full_name = message_descriptor.full_name
417 if _IsWrapperMessage(message_descriptor):
418 _ConvertWrapperMessage(value, message)
419 elif full_name in _WKTJSONMETHODS:
420 _WKTJSONMETHODS[full_name][1](value, message)
421 else:
422 _ConvertFieldValuePair(value, message)
423
424
425 def _ConvertAnyMessage(value, message):
426 """Convert a JSON representation into Any message."""
427 if isinstance(value, dict) and not value:
428 return
429 try:
430 type_url = value['@type']
431 except KeyError:
432 raise ParseError('@type is missing when parsing any message.')
433
434 sub_message = _CreateMessageFromTypeUrl(type_url)
435 message_descriptor = sub_message.DESCRIPTOR
436 full_name = message_descriptor.full_name
437 if _IsWrapperMessage(message_descriptor):
438 _ConvertWrapperMessage(value['value'], sub_message)
439 elif full_name in _WKTJSONMETHODS:
440 _WKTJSONMETHODS[full_name][1](value['value'], sub_message)
441 else:
442 del value['@type']
443 _ConvertFieldValuePair(value, sub_message)
444 # Sets Any message
445 message.value = sub_message.SerializeToString()
446 message.type_url = type_url
447
448
449 def _ConvertGenericMessage(value, message):
450 """Convert a JSON representation into message with FromJsonString."""
451 # Durantion, Timestamp, FieldMask have FromJsonString method to do the
452 # convert. Users can also call the method directly.
453 message.FromJsonString(value)
454
455
456 _INT_OR_FLOAT = six.integer_types + (float,)
457
458
459 def _ConvertValueMessage(value, message):
460 """Convert a JSON representation into Value message."""
461 if isinstance(value, dict):
462 _ConvertStructMessage(value, message.struct_value)
463 elif isinstance(value, list):
464 _ConvertListValueMessage(value, message.list_value)
465 elif value is None:
466 message.null_value = 0
467 elif isinstance(value, bool):
468 message.bool_value = value
469 elif isinstance(value, six.string_types):
470 message.string_value = value
471 elif isinstance(value, _INT_OR_FLOAT):
472 message.number_value = value
473 else:
474 raise ParseError('Unexpected type for Value message.')
475
476
477 def _ConvertListValueMessage(value, message):
478 """Convert a JSON representation into ListValue message."""
479 if not isinstance(value, list):
480 raise ParseError(
481 'ListValue must be in [] which is {0}.'.format(value))
482 message.ClearField('values')
483 for item in value:
484 _ConvertValueMessage(item, message.values.add())
485
486
487 def _ConvertStructMessage(value, message):
488 """Convert a JSON representation into Struct message."""
489 if not isinstance(value, dict):
490 raise ParseError(
491 'Struct must be in a dict which is {0}.'.format(value))
492 for key in value:
493 _ConvertValueMessage(value[key], message.fields[key])
494 return
495
496
497 def _ConvertWrapperMessage(value, message):
498 """Convert a JSON representation into Wrapper message."""
499 field = message.DESCRIPTOR.fields_by_name['value']
500 setattr(message, 'value', _ConvertScalarFieldValue(value, field))
501
502
503 def _ConvertMapFieldValue(value, message, field):
504 """Convert map field value for a message map field.
505
506 Args:
507 value: A JSON object to convert the map field value.
508 message: A protocol message to record the converted data.
509 field: The descriptor of the map field to be converted.
510
511 Raises:
512 ParseError: In case of convert problems.
513 """
514 if not isinstance(value, dict):
515 raise ParseError(
516 'Map field {0} must be in a dict which is {1}.'.format(
517 field.name, value))
518 key_field = field.message_type.fields_by_name['key']
519 value_field = field.message_type.fields_by_name['value']
520 for key in value:
521 key_value = _ConvertScalarFieldValue(key, key_field, True)
522 if value_field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
523 _ConvertMessage(value[key], getattr(message, field.name)[key_value])
524 else:
525 getattr(message, field.name)[key_value] = _ConvertScalarFieldValue(
526 value[key], value_field)
527 542
528 543
529 def _ConvertScalarFieldValue(value, field, require_str=False): 544 def _ConvertScalarFieldValue(value, field, require_str=False):
530 """Convert a single scalar field value. 545 """Convert a single scalar field value.
531 546
532 Args: 547 Args:
533 value: A scalar value to convert the scalar field value. 548 value: A scalar value to convert the scalar field value.
534 field: The descriptor of the field to convert. 549 field: The descriptor of the field to convert.
535 require_str: If True, the field value must be a str. 550 require_str: If True, the field value must be a str.
536 551
537 Returns: 552 Returns:
538 The converted scalar field value 553 The converted scalar field value
539 554
540 Raises: 555 Raises:
541 ParseError: In case of convert problems. 556 ParseError: In case of convert problems.
542 """ 557 """
543 if field.cpp_type in _INT_TYPES: 558 if field.cpp_type in _INT_TYPES:
544 return _ConvertInteger(value) 559 return _ConvertInteger(value)
545 elif field.cpp_type in _FLOAT_TYPES: 560 elif field.cpp_type in _FLOAT_TYPES:
546 return _ConvertFloat(value) 561 return _ConvertFloat(value)
547 elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_BOOL: 562 elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_BOOL:
548 return _ConvertBool(value, require_str) 563 return _ConvertBool(value, require_str)
549 elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_STRING: 564 elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_STRING:
550 if field.type == descriptor.FieldDescriptor.TYPE_BYTES: 565 if field.type == descriptor.FieldDescriptor.TYPE_BYTES:
551 return base64.b64decode(value) 566 return base64.b64decode(value)
552 else: 567 else:
568 # Checking for unpaired surrogates appears to be unreliable,
569 # depending on the specific Python version, so we check manually.
570 if _UNPAIRED_SURROGATE_PATTERN.search(value):
571 raise ParseError('Unpaired surrogate')
553 return value 572 return value
554 elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_ENUM: 573 elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_ENUM:
555 # Convert an enum value. 574 # Convert an enum value.
556 enum_value = field.enum_type.values_by_name.get(value, None) 575 enum_value = field.enum_type.values_by_name.get(value, None)
557 if enum_value is None: 576 if enum_value is None:
558 raise ParseError( 577 raise ParseError(
559 'Enum value must be a string literal with double quotes. ' 578 'Enum value must be a string literal with double quotes. '
560 'Type "{0}" has no value named {1}.'.format( 579 'Type "{0}" has no value named {1}.'.format(
561 field.enum_type.full_name, value)) 580 field.enum_type.full_name, value))
562 return enum_value.number 581 return enum_value.number
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
621 elif value == 'false': 640 elif value == 'false':
622 return False 641 return False
623 else: 642 else:
624 raise ParseError('Expected "true" or "false", not {0}.'.format(value)) 643 raise ParseError('Expected "true" or "false", not {0}.'.format(value))
625 644
626 if not isinstance(value, bool): 645 if not isinstance(value, bool):
627 raise ParseError('Expected true or false without quotes.') 646 raise ParseError('Expected true or false without quotes.')
628 return value 647 return value
629 648
630 _WKTJSONMETHODS = { 649 _WKTJSONMETHODS = {
631 'google.protobuf.Any': [_AnyMessageToJsonObject, 650 'google.protobuf.Any': ['_AnyMessageToJsonObject',
632 _ConvertAnyMessage], 651 '_ConvertAnyMessage'],
633 'google.protobuf.Duration': [_GenericMessageToJsonObject, 652 'google.protobuf.Duration': ['_GenericMessageToJsonObject',
634 _ConvertGenericMessage], 653 '_ConvertGenericMessage'],
635 'google.protobuf.FieldMask': [_GenericMessageToJsonObject, 654 'google.protobuf.FieldMask': ['_GenericMessageToJsonObject',
636 _ConvertGenericMessage], 655 '_ConvertGenericMessage'],
637 'google.protobuf.ListValue': [_ListValueMessageToJsonObject, 656 'google.protobuf.ListValue': ['_ListValueMessageToJsonObject',
638 _ConvertListValueMessage], 657 '_ConvertListValueMessage'],
639 'google.protobuf.Struct': [_StructMessageToJsonObject, 658 'google.protobuf.Struct': ['_StructMessageToJsonObject',
640 _ConvertStructMessage], 659 '_ConvertStructMessage'],
641 'google.protobuf.Timestamp': [_GenericMessageToJsonObject, 660 'google.protobuf.Timestamp': ['_GenericMessageToJsonObject',
642 _ConvertGenericMessage], 661 '_ConvertGenericMessage'],
643 'google.protobuf.Value': [_ValueMessageToJsonObject, 662 'google.protobuf.Value': ['_ValueMessageToJsonObject',
644 _ConvertValueMessage] 663 '_ConvertValueMessage']
645 } 664 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698