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

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

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

Powered by Google App Engine
This is Rietveld 408576698