Package google :: Package protobuf :: Module json_format
[hide private]
[frames] | no frames]

Source Code for Module google.protobuf.json_format

  1  # Protocol Buffers - Google's data interchange format 
  2  # Copyright 2008 Google Inc.  All rights reserved. 
  3  # https://developers.google.com/protocol-buffers/ 
  4  # 
  5  # Redistribution and use in source and binary forms, with or without 
  6  # modification, are permitted provided that the following conditions are 
  7  # met: 
  8  # 
  9  #     * Redistributions of source code must retain the above copyright 
 10  # notice, this list of conditions and the following disclaimer. 
 11  #     * Redistributions in binary form must reproduce the above 
 12  # copyright notice, this list of conditions and the following disclaimer 
 13  # in the documentation and/or other materials provided with the 
 14  # distribution. 
 15  #     * Neither the name of Google Inc. nor the names of its 
 16  # contributors may be used to endorse or promote products derived from 
 17  # this software without specific prior written permission. 
 18  # 
 19  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 20  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 21  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
 22  # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
 23  # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
 24  # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
 25  # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
 26  # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
 27  # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
 28  # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
 29  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 30   
 31  """Contains routines for printing protocol messages in JSON format. 
 32   
 33  Simple usage example: 
 34   
 35    # Create a proto object and serialize it to a json format string. 
 36    message = my_proto_pb2.MyMessage(foo='bar') 
 37    json_string = json_format.MessageToJson(message) 
 38   
 39    # Parse a json format string to proto object. 
 40    message = json_format.Parse(json_string, my_proto_pb2.MyMessage()) 
 41  """ 
 42   
 43  __author__ = 'jieluo@google.com (Jie Luo)' 
 44   
 45  # pylint: disable=g-statement-before-imports,g-import-not-at-top 
 46  try: 
 47    from collections import OrderedDict 
 48  except ImportError: 
 49    from ordereddict import OrderedDict  # PY26 
 50  # pylint: enable=g-statement-before-imports,g-import-not-at-top 
 51   
 52  import base64 
 53  import json 
 54  import math 
 55   
 56  from operator import methodcaller 
 57   
 58  import re 
 59  import sys 
 60   
 61  import six 
 62   
 63  from google.protobuf import descriptor 
 64  from google.protobuf import symbol_database 
 65   
 66   
 67  _TIMESTAMPFOMAT = '%Y-%m-%dT%H:%M:%S' 
 68  _INT_TYPES = frozenset([descriptor.FieldDescriptor.CPPTYPE_INT32, 
 69                          descriptor.FieldDescriptor.CPPTYPE_UINT32, 
 70                          descriptor.FieldDescriptor.CPPTYPE_INT64, 
 71                          descriptor.FieldDescriptor.CPPTYPE_UINT64]) 
 72  _INT64_TYPES = frozenset([descriptor.FieldDescriptor.CPPTYPE_INT64, 
 73                            descriptor.FieldDescriptor.CPPTYPE_UINT64]) 
 74  _FLOAT_TYPES = frozenset([descriptor.FieldDescriptor.CPPTYPE_FLOAT, 
 75                            descriptor.FieldDescriptor.CPPTYPE_DOUBLE]) 
 76  _INFINITY = 'Infinity' 
 77  _NEG_INFINITY = '-Infinity' 
 78  _NAN = 'NaN' 
 79   
 80  _UNPAIRED_SURROGATE_PATTERN = re.compile(six.u( 
 81      r'[\ud800-\udbff](?![\udc00-\udfff])|(?<![\ud800-\udbff])[\udc00-\udfff]' 
 82  )) 
 83   
 84  _VALID_EXTENSION_NAME = re.compile(r'\[[a-zA-Z0-9\._]*\]$') 
 85   
 86   
87 -class Error(Exception):
88 """Top-level module error for json_format."""
89 90
91 -class SerializeToJsonError(Error):
92 """Thrown if serialization to JSON fails."""
93 94
95 -class ParseError(Error):
96 """Thrown in case of parsing error."""
97 98
99 -def MessageToJson( 100 message, 101 including_default_value_fields=False, 102 preserving_proto_field_name=False, 103 indent=2, 104 sort_keys=False, 105 use_integers_for_enums=False, 106 descriptor_pool=None):
107 """Converts protobuf message to JSON format. 108 109 Args: 110 message: The protocol buffers message instance to serialize. 111 including_default_value_fields: If True, singular primitive fields, 112 repeated fields, and map fields will always be serialized. If 113 False, only serialize non-empty fields. Singular message fields 114 and oneof fields are not affected by this option. 115 preserving_proto_field_name: If True, use the original proto field 116 names as defined in the .proto file. If False, convert the field 117 names to lowerCamelCase. 118 indent: The JSON object will be pretty-printed with this indent level. 119 An indent level of 0 or negative will only insert newlines. 120 sort_keys: If True, then the output will be sorted by field names. 121 use_integers_for_enums: If true, print integers instead of enum names. 122 descriptor_pool: A Descriptor Pool for resolving types. If None use the 123 default. 124 125 Returns: 126 A string containing the JSON formatted protocol buffer message. 127 """ 128 printer = _Printer( 129 including_default_value_fields, 130 preserving_proto_field_name, 131 use_integers_for_enums, 132 descriptor_pool) 133 return printer.ToJsonString(message, indent, sort_keys)
134 135
136 -def MessageToDict( 137 message, 138 including_default_value_fields=False, 139 preserving_proto_field_name=False, 140 use_integers_for_enums=False, 141 descriptor_pool=None):
142 """Converts protobuf message to a dictionary. 143 144 When the dictionary is encoded to JSON, it conforms to proto3 JSON spec. 145 146 Args: 147 message: The protocol buffers message instance to serialize. 148 including_default_value_fields: If True, singular primitive fields, 149 repeated fields, and map fields will always be serialized. If 150 False, only serialize non-empty fields. Singular message fields 151 and oneof fields are not affected by this option. 152 preserving_proto_field_name: If True, use the original proto field 153 names as defined in the .proto file. If False, convert the field 154 names to lowerCamelCase. 155 use_integers_for_enums: If true, print integers instead of enum names. 156 descriptor_pool: A Descriptor Pool for resolving types. If None use the 157 default. 158 159 Returns: 160 A dict representation of the protocol buffer message. 161 """ 162 printer = _Printer( 163 including_default_value_fields, 164 preserving_proto_field_name, 165 use_integers_for_enums, 166 descriptor_pool) 167 # pylint: disable=protected-access 168 return printer._MessageToJsonObject(message)
169 170
171 -def _IsMapEntry(field):
172 return (field.type == descriptor.FieldDescriptor.TYPE_MESSAGE and 173 field.message_type.has_options and 174 field.message_type.GetOptions().map_entry)
175 176
177 -class _Printer(object):
178 """JSON format printer for protocol message.""" 179
180 - def __init__( 181 self, 182 including_default_value_fields=False, 183 preserving_proto_field_name=False, 184 use_integers_for_enums=False, 185 descriptor_pool=None):
186 self.including_default_value_fields = including_default_value_fields 187 self.preserving_proto_field_name = preserving_proto_field_name 188 self.use_integers_for_enums = use_integers_for_enums 189 self.descriptor_pool = descriptor_pool
190
191 - def ToJsonString(self, message, indent, sort_keys):
192 js = self._MessageToJsonObject(message) 193 return json.dumps(js, indent=indent, sort_keys=sort_keys)
194
195 - def _MessageToJsonObject(self, message):
196 """Converts message to an object according to Proto3 JSON Specification.""" 197 message_descriptor = message.DESCRIPTOR 198 full_name = message_descriptor.full_name 199 if _IsWrapperMessage(message_descriptor): 200 return self._WrapperMessageToJsonObject(message) 201 if full_name in _WKTJSONMETHODS: 202 return methodcaller(_WKTJSONMETHODS[full_name][0], message)(self) 203 js = {} 204 return self._RegularMessageToJsonObject(message, js)
205
206 - def _RegularMessageToJsonObject(self, message, js):
207 """Converts normal message according to Proto3 JSON Specification.""" 208 fields = message.ListFields() 209 210 try: 211 for field, value in fields: 212 if self.preserving_proto_field_name: 213 name = field.name 214 else: 215 name = field.json_name 216 if _IsMapEntry(field): 217 # Convert a map field. 218 v_field = field.message_type.fields_by_name['value'] 219 js_map = {} 220 for key in value: 221 if isinstance(key, bool): 222 if key: 223 recorded_key = 'true' 224 else: 225 recorded_key = 'false' 226 else: 227 recorded_key = key 228 js_map[recorded_key] = self._FieldToJsonObject( 229 v_field, value[key]) 230 js[name] = js_map 231 elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED: 232 # Convert a repeated field. 233 js[name] = [self._FieldToJsonObject(field, k) 234 for k in value] 235 elif field.is_extension: 236 full_qualifier = field.full_name[:-len(field.name)] 237 name = '[%s%s]' % (full_qualifier, name) 238 js[name] = self._FieldToJsonObject(field, value) 239 else: 240 js[name] = self._FieldToJsonObject(field, value) 241 242 # Serialize default value if including_default_value_fields is True. 243 if self.including_default_value_fields: 244 message_descriptor = message.DESCRIPTOR 245 for field in message_descriptor.fields: 246 # Singular message fields and oneof fields will not be affected. 247 if ((field.label != descriptor.FieldDescriptor.LABEL_REPEATED and 248 field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE) or 249 field.containing_oneof): 250 continue 251 if self.preserving_proto_field_name: 252 name = field.name 253 else: 254 name = field.json_name 255 if name in js: 256 # Skip the field which has been serailized already. 257 continue 258 if _IsMapEntry(field): 259 js[name] = {} 260 elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED: 261 js[name] = [] 262 else: 263 js[name] = self._FieldToJsonObject(field, field.default_value) 264 265 except ValueError as e: 266 raise SerializeToJsonError( 267 'Failed to serialize {0} field: {1}.'.format(field.name, e)) 268 269 return js
270
271 - def _FieldToJsonObject(self, field, value):
272 """Converts field value according to Proto3 JSON Specification.""" 273 if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE: 274 return self._MessageToJsonObject(value) 275 elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_ENUM: 276 if self.use_integers_for_enums: 277 return value 278 enum_value = field.enum_type.values_by_number.get(value, None) 279 if enum_value is not None: 280 return enum_value.name 281 else: 282 if field.file.syntax == 'proto3': 283 return value 284 raise SerializeToJsonError('Enum field contains an integer value ' 285 'which can not mapped to an enum value.') 286 elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_STRING: 287 if field.type == descriptor.FieldDescriptor.TYPE_BYTES: 288 # Use base64 Data encoding for bytes 289 return base64.b64encode(value).decode('utf-8') 290 else: 291 return value 292 elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_BOOL: 293 return bool(value) 294 elif field.cpp_type in _INT64_TYPES: 295 return str(value) 296 elif field.cpp_type in _FLOAT_TYPES: 297 if math.isinf(value): 298 if value < 0.0: 299 return _NEG_INFINITY 300 else: 301 return _INFINITY 302 if math.isnan(value): 303 return _NAN 304 return value
305
306 - def _AnyMessageToJsonObject(self, message):
307 """Converts Any message according to Proto3 JSON Specification.""" 308 if not message.ListFields(): 309 return {} 310 # Must print @type first, use OrderedDict instead of {} 311 js = OrderedDict() 312 type_url = message.type_url 313 js['@type'] = type_url 314 sub_message = _CreateMessageFromTypeUrl(type_url, self.descriptor_pool) 315 sub_message.ParseFromString(message.value) 316 message_descriptor = sub_message.DESCRIPTOR 317 full_name = message_descriptor.full_name 318 if _IsWrapperMessage(message_descriptor): 319 js['value'] = self._WrapperMessageToJsonObject(sub_message) 320 return js 321 if full_name in _WKTJSONMETHODS: 322 js['value'] = methodcaller(_WKTJSONMETHODS[full_name][0], 323 sub_message)(self) 324 return js 325 return self._RegularMessageToJsonObject(sub_message, js)
326
327 - def _GenericMessageToJsonObject(self, message):
328 """Converts message according to Proto3 JSON Specification.""" 329 # Duration, Timestamp and FieldMask have ToJsonString method to do the 330 # convert. Users can also call the method directly. 331 return message.ToJsonString()
332
333 - def _ValueMessageToJsonObject(self, message):
334 """Converts Value message according to Proto3 JSON Specification.""" 335 which = message.WhichOneof('kind') 336 # If the Value message is not set treat as null_value when serialize 337 # to JSON. The parse back result will be different from original message. 338 if which is None or which == 'null_value': 339 return None 340 if which == 'list_value': 341 return self._ListValueMessageToJsonObject(message.list_value) 342 if which == 'struct_value': 343 value = message.struct_value 344 else: 345 value = getattr(message, which) 346 oneof_descriptor = message.DESCRIPTOR.fields_by_name[which] 347 return self._FieldToJsonObject(oneof_descriptor, value)
348
349 - def _ListValueMessageToJsonObject(self, message):
350 """Converts ListValue message according to Proto3 JSON Specification.""" 351 return [self._ValueMessageToJsonObject(value) 352 for value in message.values]
353
354 - def _StructMessageToJsonObject(self, message):
355 """Converts Struct message according to Proto3 JSON Specification.""" 356 fields = message.fields 357 ret = {} 358 for key in fields: 359 ret[key] = self._ValueMessageToJsonObject(fields[key]) 360 return ret
361
362 - def _WrapperMessageToJsonObject(self, message):
363 return self._FieldToJsonObject( 364 message.DESCRIPTOR.fields_by_name['value'], message.value)
365 366
367 -def _IsWrapperMessage(message_descriptor):
368 return message_descriptor.file.name == 'google/protobuf/wrappers.proto'
369 370
371 -def _DuplicateChecker(js):
372 result = {} 373 for name, value in js: 374 if name in result: 375 raise ParseError('Failed to load JSON: duplicate key {0}.'.format(name)) 376 result[name] = value 377 return result
378 379
380 -def _CreateMessageFromTypeUrl(type_url, descriptor_pool):
381 """Creates a message from a type URL.""" 382 db = symbol_database.Default() 383 pool = db.pool if descriptor_pool is None else descriptor_pool 384 type_name = type_url.split('/')[-1] 385 try: 386 message_descriptor = pool.FindMessageTypeByName(type_name) 387 except KeyError: 388 raise TypeError( 389 'Can not find message descriptor by type_url: {0}.'.format(type_url)) 390 message_class = db.GetPrototype(message_descriptor) 391 return message_class()
392 393
394 -def Parse(text, message, ignore_unknown_fields=False, descriptor_pool=None):
395 """Parses a JSON representation of a protocol message into a message. 396 397 Args: 398 text: Message JSON representation. 399 message: A protocol buffer message to merge into. 400 ignore_unknown_fields: If True, do not raise errors for unknown fields. 401 descriptor_pool: A Descriptor Pool for resolving types. If None use the 402 default. 403 404 Returns: 405 The same message passed as argument. 406 407 Raises:: 408 ParseError: On JSON parsing problems. 409 """ 410 if not isinstance(text, six.text_type): text = text.decode('utf-8') 411 try: 412 js = json.loads(text, object_pairs_hook=_DuplicateChecker) 413 except ValueError as e: 414 raise ParseError('Failed to load JSON: {0}.'.format(str(e))) 415 return ParseDict(js, message, ignore_unknown_fields, descriptor_pool)
416 417
418 -def ParseDict(js_dict, 419 message, 420 ignore_unknown_fields=False, 421 descriptor_pool=None):
422 """Parses a JSON dictionary representation into a message. 423 424 Args: 425 js_dict: Dict representation of a JSON message. 426 message: A protocol buffer message to merge into. 427 ignore_unknown_fields: If True, do not raise errors for unknown fields. 428 descriptor_pool: A Descriptor Pool for resolving types. If None use the 429 default. 430 431 Returns: 432 The same message passed as argument. 433 """ 434 parser = _Parser(ignore_unknown_fields, descriptor_pool) 435 parser.ConvertMessage(js_dict, message) 436 return message
437 438 439 _INT_OR_FLOAT = six.integer_types + (float,) 440 441
442 -class _Parser(object):
443 """JSON format parser for protocol message.""" 444
445 - def __init__(self, ignore_unknown_fields, descriptor_pool):
446 self.ignore_unknown_fields = ignore_unknown_fields 447 self.descriptor_pool = descriptor_pool
448
449 - def ConvertMessage(self, value, message):
450 """Convert a JSON object into a message. 451 452 Args: 453 value: A JSON object. 454 message: A WKT or regular protocol message to record the data. 455 456 Raises: 457 ParseError: In case of convert problems. 458 """ 459 message_descriptor = message.DESCRIPTOR 460 full_name = message_descriptor.full_name 461 if _IsWrapperMessage(message_descriptor): 462 self._ConvertWrapperMessage(value, message) 463 elif full_name in _WKTJSONMETHODS: 464 methodcaller(_WKTJSONMETHODS[full_name][1], value, message)(self) 465 else: 466 self._ConvertFieldValuePair(value, message)
467
468 - def _ConvertFieldValuePair(self, js, message):
469 """Convert field value pairs into regular message. 470 471 Args: 472 js: A JSON object to convert the field value pairs. 473 message: A regular protocol message to record the data. 474 475 Raises: 476 ParseError: In case of problems converting. 477 """ 478 names = [] 479 message_descriptor = message.DESCRIPTOR 480 fields_by_json_name = dict((f.json_name, f) 481 for f in message_descriptor.fields) 482 for name in js: 483 try: 484 field = fields_by_json_name.get(name, None) 485 if not field: 486 field = message_descriptor.fields_by_name.get(name, None) 487 if not field and _VALID_EXTENSION_NAME.match(name): 488 if not message_descriptor.is_extendable: 489 raise ParseError('Message type {0} does not have extensions'.format( 490 message_descriptor.full_name)) 491 identifier = name[1:-1] # strip [] brackets 492 # pylint: disable=protected-access 493 field = message.Extensions._FindExtensionByName(identifier) 494 # pylint: enable=protected-access 495 if not field: 496 # Try looking for extension by the message type name, dropping the 497 # field name following the final . separator in full_name. 498 identifier = '.'.join(identifier.split('.')[:-1]) 499 # pylint: disable=protected-access 500 field = message.Extensions._FindExtensionByName(identifier) 501 # pylint: enable=protected-access 502 if not field: 503 if self.ignore_unknown_fields: 504 continue 505 raise ParseError( 506 ('Message type "{0}" has no field named "{1}".\n' 507 ' Available Fields(except extensions): {2}').format( 508 message_descriptor.full_name, name, 509 [f.json_name for f in message_descriptor.fields])) 510 if name in names: 511 raise ParseError('Message type "{0}" should not have multiple ' 512 '"{1}" fields.'.format( 513 message.DESCRIPTOR.full_name, name)) 514 names.append(name) 515 # Check no other oneof field is parsed. 516 if field.containing_oneof is not None: 517 oneof_name = field.containing_oneof.name 518 if oneof_name in names: 519 raise ParseError('Message type "{0}" should not have multiple ' 520 '"{1}" oneof fields.'.format( 521 message.DESCRIPTOR.full_name, oneof_name)) 522 names.append(oneof_name) 523 524 value = js[name] 525 if value is None: 526 if (field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE 527 and field.message_type.full_name == 'google.protobuf.Value'): 528 sub_message = getattr(message, field.name) 529 sub_message.null_value = 0 530 else: 531 message.ClearField(field.name) 532 continue 533 534 # Parse field value. 535 if _IsMapEntry(field): 536 message.ClearField(field.name) 537 self._ConvertMapFieldValue(value, message, field) 538 elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED: 539 message.ClearField(field.name) 540 if not isinstance(value, list): 541 raise ParseError('repeated field {0} must be in [] which is ' 542 '{1}.'.format(name, value)) 543 if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE: 544 # Repeated message field. 545 for item in value: 546 sub_message = getattr(message, field.name).add() 547 # None is a null_value in Value. 548 if (item is None and 549 sub_message.DESCRIPTOR.full_name != 'google.protobuf.Value'): 550 raise ParseError('null is not allowed to be used as an element' 551 ' in a repeated field.') 552 self.ConvertMessage(item, sub_message) 553 else: 554 # Repeated scalar field. 555 for item in value: 556 if item is None: 557 raise ParseError('null is not allowed to be used as an element' 558 ' in a repeated field.') 559 getattr(message, field.name).append( 560 _ConvertScalarFieldValue(item, field)) 561 elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE: 562 if field.is_extension: 563 sub_message = message.Extensions[field] 564 else: 565 sub_message = getattr(message, field.name) 566 sub_message.SetInParent() 567 self.ConvertMessage(value, sub_message) 568 else: 569 if field.is_extension: 570 message.Extensions[field] = _ConvertScalarFieldValue(value, field) 571 else: 572 setattr(message, field.name, _ConvertScalarFieldValue(value, field)) 573 except ParseError as e: 574 if field and field.containing_oneof is None: 575 raise ParseError('Failed to parse {0} field: {1}.'.format(name, e)) 576 else: 577 raise ParseError(str(e)) 578 except ValueError as e: 579 raise ParseError('Failed to parse {0} field: {1}.'.format(name, e)) 580 except TypeError as e: 581 raise ParseError('Failed to parse {0} field: {1}.'.format(name, e))
582
583 - def _ConvertAnyMessage(self, value, message):
584 """Convert a JSON representation into Any message.""" 585 if isinstance(value, dict) and not value: 586 return 587 try: 588 type_url = value['@type'] 589 except KeyError: 590 raise ParseError('@type is missing when parsing any message.') 591 592 sub_message = _CreateMessageFromTypeUrl(type_url, self.descriptor_pool) 593 message_descriptor = sub_message.DESCRIPTOR 594 full_name = message_descriptor.full_name 595 if _IsWrapperMessage(message_descriptor): 596 self._ConvertWrapperMessage(value['value'], sub_message) 597 elif full_name in _WKTJSONMETHODS: 598 methodcaller( 599 _WKTJSONMETHODS[full_name][1], value['value'], sub_message)(self) 600 else: 601 del value['@type'] 602 self._ConvertFieldValuePair(value, sub_message) 603 value['@type'] = type_url 604 # Sets Any message 605 message.value = sub_message.SerializeToString() 606 message.type_url = type_url
607
608 - def _ConvertGenericMessage(self, value, message):
609 """Convert a JSON representation into message with FromJsonString.""" 610 # Duration, Timestamp, FieldMask have a FromJsonString method to do the 611 # conversion. Users can also call the method directly. 612 try: 613 message.FromJsonString(value) 614 except ValueError as e: 615 raise ParseError(e)
616
617 - def _ConvertValueMessage(self, value, message):
618 """Convert a JSON representation into Value message.""" 619 if isinstance(value, dict): 620 self._ConvertStructMessage(value, message.struct_value) 621 elif isinstance(value, list): 622 self. _ConvertListValueMessage(value, message.list_value) 623 elif value is None: 624 message.null_value = 0 625 elif isinstance(value, bool): 626 message.bool_value = value 627 elif isinstance(value, six.string_types): 628 message.string_value = value 629 elif isinstance(value, _INT_OR_FLOAT): 630 message.number_value = value 631 else: 632 raise ParseError('Unexpected type for Value message.')
633
634 - def _ConvertListValueMessage(self, value, message):
635 """Convert a JSON representation into ListValue message.""" 636 if not isinstance(value, list): 637 raise ParseError( 638 'ListValue must be in [] which is {0}.'.format(value)) 639 message.ClearField('values') 640 for item in value: 641 self._ConvertValueMessage(item, message.values.add())
642
643 - def _ConvertStructMessage(self, value, message):
644 """Convert a JSON representation into Struct message.""" 645 if not isinstance(value, dict): 646 raise ParseError( 647 'Struct must be in a dict which is {0}.'.format(value)) 648 # Clear will mark the struct as modified so it will be created even if 649 # there are no values. 650 message.Clear() 651 for key in value: 652 self._ConvertValueMessage(value[key], message.fields[key]) 653 return
654
655 - def _ConvertWrapperMessage(self, value, message):
656 """Convert a JSON representation into Wrapper message.""" 657 field = message.DESCRIPTOR.fields_by_name['value'] 658 setattr(message, 'value', _ConvertScalarFieldValue(value, field))
659
660 - def _ConvertMapFieldValue(self, value, message, field):
661 """Convert map field value for a message map field. 662 663 Args: 664 value: A JSON object to convert the map field value. 665 message: A protocol message to record the converted data. 666 field: The descriptor of the map field to be converted. 667 668 Raises: 669 ParseError: In case of convert problems. 670 """ 671 if not isinstance(value, dict): 672 raise ParseError( 673 'Map field {0} must be in a dict which is {1}.'.format( 674 field.name, value)) 675 key_field = field.message_type.fields_by_name['key'] 676 value_field = field.message_type.fields_by_name['value'] 677 for key in value: 678 key_value = _ConvertScalarFieldValue(key, key_field, True) 679 if value_field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE: 680 self.ConvertMessage(value[key], getattr( 681 message, field.name)[key_value]) 682 else: 683 getattr(message, field.name)[key_value] = _ConvertScalarFieldValue( 684 value[key], value_field)
685 686
687 -def _ConvertScalarFieldValue(value, field, require_str=False):
688 """Convert a single scalar field value. 689 690 Args: 691 value: A scalar value to convert the scalar field value. 692 field: The descriptor of the field to convert. 693 require_str: If True, the field value must be a str. 694 695 Returns: 696 The converted scalar field value 697 698 Raises: 699 ParseError: In case of convert problems. 700 """ 701 if field.cpp_type in _INT_TYPES: 702 return _ConvertInteger(value) 703 elif field.cpp_type in _FLOAT_TYPES: 704 return _ConvertFloat(value) 705 elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_BOOL: 706 return _ConvertBool(value, require_str) 707 elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_STRING: 708 if field.type == descriptor.FieldDescriptor.TYPE_BYTES: 709 return base64.b64decode(value) 710 else: 711 # Checking for unpaired surrogates appears to be unreliable, 712 # depending on the specific Python version, so we check manually. 713 if _UNPAIRED_SURROGATE_PATTERN.search(value): 714 raise ParseError('Unpaired surrogate') 715 return value 716 elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_ENUM: 717 # Convert an enum value. 718 enum_value = field.enum_type.values_by_name.get(value, None) 719 if enum_value is None: 720 try: 721 number = int(value) 722 enum_value = field.enum_type.values_by_number.get(number, None) 723 except ValueError: 724 raise ParseError('Invalid enum value {0} for enum type {1}.'.format( 725 value, field.enum_type.full_name)) 726 if enum_value is None: 727 if field.file.syntax == 'proto3': 728 # Proto3 accepts unknown enums. 729 return number 730 raise ParseError('Invalid enum value {0} for enum type {1}.'.format( 731 value, field.enum_type.full_name)) 732 return enum_value.number
733 734
735 -def _ConvertInteger(value):
736 """Convert an integer. 737 738 Args: 739 value: A scalar value to convert. 740 741 Returns: 742 The integer value. 743 744 Raises: 745 ParseError: If an integer couldn't be consumed. 746 """ 747 if isinstance(value, float) and not value.is_integer(): 748 raise ParseError('Couldn\'t parse integer: {0}.'.format(value)) 749 750 if isinstance(value, six.text_type) and value.find(' ') != -1: 751 raise ParseError('Couldn\'t parse integer: "{0}".'.format(value)) 752 753 return int(value)
754 755
756 -def _ConvertFloat(value):
757 """Convert an floating point number.""" 758 if value == 'nan': 759 raise ParseError('Couldn\'t parse float "nan", use "NaN" instead.') 760 try: 761 # Assume Python compatible syntax. 762 return float(value) 763 except ValueError: 764 # Check alternative spellings. 765 if value == _NEG_INFINITY: 766 return float('-inf') 767 elif value == _INFINITY: 768 return float('inf') 769 elif value == _NAN: 770 return float('nan') 771 else: 772 raise ParseError('Couldn\'t parse float: {0}.'.format(value))
773 774
775 -def _ConvertBool(value, require_str):
776 """Convert a boolean value. 777 778 Args: 779 value: A scalar value to convert. 780 require_str: If True, value must be a str. 781 782 Returns: 783 The bool parsed. 784 785 Raises: 786 ParseError: If a boolean value couldn't be consumed. 787 """ 788 if require_str: 789 if value == 'true': 790 return True 791 elif value == 'false': 792 return False 793 else: 794 raise ParseError('Expected "true" or "false", not {0}.'.format(value)) 795 796 if not isinstance(value, bool): 797 raise ParseError('Expected true or false without quotes.') 798 return value
799 800 _WKTJSONMETHODS = { 801 'google.protobuf.Any': ['_AnyMessageToJsonObject', 802 '_ConvertAnyMessage'], 803 'google.protobuf.Duration': ['_GenericMessageToJsonObject', 804 '_ConvertGenericMessage'], 805 'google.protobuf.FieldMask': ['_GenericMessageToJsonObject', 806 '_ConvertGenericMessage'], 807 'google.protobuf.ListValue': ['_ListValueMessageToJsonObject', 808 '_ConvertListValueMessage'], 809 'google.protobuf.Struct': ['_StructMessageToJsonObject', 810 '_ConvertStructMessage'], 811 'google.protobuf.Timestamp': ['_GenericMessageToJsonObject', 812 '_ConvertGenericMessage'], 813 'google.protobuf.Value': ['_ValueMessageToJsonObject', 814 '_ConvertValueMessage'] 815 } 816