31 """Contains routines for printing protocol messages in JSON format.
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)
39 # Parse a json format string to proto object.
40 message = json_format.Parse(json_string, my_proto_pb2.MyMessage())
43 __author__ =
'jieluo@google.com (Jie Luo)'
47 from collections
import OrderedDict
49 from ordereddict
import OrderedDict
56 from operator
import methodcaller
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'
80 _UNPAIRED_SURROGATE_PATTERN = re.compile(six.u(
81 r'[\ud800-\udbff](?![\udc00-\udfff])|(?<![\ud800-\udbff])[\udc00-\udfff]'
84 _VALID_EXTENSION_NAME = re.compile(
r'\[[a-zA-Z0-9\._]*\]$')
88 """Top-level module error for json_format."""
92 """Thrown if serialization to JSON fails."""
96 """Thrown in case of parsing error."""
101 including_default_value_fields=False,
102 preserving_proto_field_name=False,
105 use_integers_for_enums=False,
106 descriptor_pool=None):
107 """Converts protobuf message to JSON format.
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
126 A string containing the JSON formatted protocol buffer message.
129 including_default_value_fields,
130 preserving_proto_field_name,
131 use_integers_for_enums,
133 return printer.ToJsonString(message, indent, sort_keys)
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.
144 When the dictionary is encoded to JSON, it conforms to proto3 JSON spec.
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
160 A dict representation of the protocol buffer message.
163 including_default_value_fields,
164 preserving_proto_field_name,
165 use_integers_for_enums,
168 return printer._MessageToJsonObject(message)
172 return (field.type == descriptor.FieldDescriptor.TYPE_MESSAGE
and
173 field.message_type.has_options
and
174 field.message_type.GetOptions().map_entry)
178 """JSON format printer for protocol message."""
182 including_default_value_fields=False,
183 preserving_proto_field_name=False,
184 use_integers_for_enums=False,
185 descriptor_pool=None):
193 return json.dumps(js, indent=indent, sort_keys=sort_keys)
196 """Converts message to an object according to Proto3 JSON Specification."""
197 message_descriptor = message.DESCRIPTOR
198 full_name = message_descriptor.full_name
201 if full_name
in _WKTJSONMETHODS:
202 return methodcaller(_WKTJSONMETHODS[full_name][0], message)(self)
207 """Converts normal message according to Proto3 JSON Specification."""
208 fields = message.ListFields()
211 for field, value
in fields:
215 name = field.json_name
218 v_field = field.message_type.fields_by_name[
'value']
221 if isinstance(key, bool):
223 recorded_key =
'true'
225 recorded_key =
'false'
231 elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
235 elif field.is_extension:
236 full_qualifier = field.full_name[:-
len(field.name)]
237 name =
'[%s%s]' % (full_qualifier, name)
244 message_descriptor = message.DESCRIPTOR
245 for field
in message_descriptor.fields:
247 if ((field.label != descriptor.FieldDescriptor.LABEL_REPEATED
and
248 field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE)
or
249 field.containing_oneof):
254 name = field.json_name
260 elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
265 except ValueError
as e:
267 'Failed to serialize {0} field: {1}.'.format(field.name, e))
272 """Converts field value according to Proto3 JSON Specification."""
273 if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
275 elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_ENUM:
278 enum_value = field.enum_type.values_by_number.get(value,
None)
279 if enum_value
is not None:
280 return enum_value.name
282 if field.file.syntax ==
'proto3':
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:
289 return base64.b64encode(value).decode(
'utf-8')
292 elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_BOOL:
294 elif field.cpp_type
in _INT64_TYPES:
296 elif field.cpp_type
in _FLOAT_TYPES:
297 if math.isinf(value):
302 if math.isnan(value):
307 """Converts Any message according to Proto3 JSON Specification."""
308 if not message.ListFields():
312 type_url = message.type_url
313 js[
'@type'] = type_url
315 sub_message.ParseFromString(message.value)
316 message_descriptor = sub_message.DESCRIPTOR
317 full_name = message_descriptor.full_name
321 if full_name
in _WKTJSONMETHODS:
322 js[
'value'] = methodcaller(_WKTJSONMETHODS[full_name][0],
328 """Converts message according to Proto3 JSON Specification."""
331 return message.ToJsonString()
334 """Converts Value message according to Proto3 JSON Specification."""
335 which = message.WhichOneof(
'kind')
338 if which
is None or which ==
'null_value':
340 if which ==
'list_value':
342 if which ==
'struct_value':
343 value = message.struct_value
345 value =
getattr(message, which)
346 oneof_descriptor = message.DESCRIPTOR.fields_by_name[which]
350 """Converts ListValue message according to Proto3 JSON Specification."""
352 for value
in message.values]
355 """Converts Struct message according to Proto3 JSON Specification."""
356 fields = message.fields
364 message.DESCRIPTOR.fields_by_name[
'value'], message.value)
368 return message_descriptor.file.name ==
'google/protobuf/wrappers.proto'
373 for name, value
in js:
375 raise ParseError(
'Failed to load JSON: duplicate key {0}.'.format(name))
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]
386 message_descriptor = pool.FindMessageTypeByName(type_name)
389 'Can not find message descriptor by type_url: {0}.'.format(type_url))
390 message_class = db.GetPrototype(message_descriptor)
391 return message_class()
394 def Parse(text, message, ignore_unknown_fields=False, descriptor_pool=None):
395 """Parses a JSON representation of a protocol message into a message.
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
405 The same message passed as argument.
408 ParseError: On JSON parsing problems.
410 if not isinstance(text, six.text_type): text = text.decode(
'utf-8')
412 js = json.loads(text, object_pairs_hook=_DuplicateChecker)
413 except ValueError
as e:
415 return ParseDict(js, message, ignore_unknown_fields, descriptor_pool)
420 ignore_unknown_fields=False,
421 descriptor_pool=None):
422 """Parses a JSON dictionary representation into a message.
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
432 The same message passed as argument.
434 parser =
_Parser(ignore_unknown_fields, descriptor_pool)
435 parser.ConvertMessage(js_dict, message)
439 _INT_OR_FLOAT = six.integer_types + (float,)
443 """JSON format parser for protocol message."""
445 def __init__(self, ignore_unknown_fields, descriptor_pool):
450 """Convert a JSON object into a message.
453 value: A JSON object.
454 message: A WKT or regular protocol message to record the data.
457 ParseError: In case of convert problems.
459 message_descriptor = message.DESCRIPTOR
460 full_name = message_descriptor.full_name
463 elif full_name
in _WKTJSONMETHODS:
464 methodcaller(_WKTJSONMETHODS[full_name][1], value, message)(self)
469 """Convert field value pairs into regular message.
472 js: A JSON object to convert the field value pairs.
473 message: A regular protocol message to record the data.
476 ParseError: In case of problems converting.
479 message_descriptor = message.DESCRIPTOR
480 fields_by_json_name = dict((f.json_name, f)
481 for f
in message_descriptor.fields)
484 field = fields_by_json_name.get(name,
None)
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]
493 field = message.Extensions._FindExtensionByName(identifier)
498 identifier =
'.'.join(identifier.split(
'.')[:-1])
500 field = message.Extensions._FindExtensionByName(identifier)
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]))
511 raise ParseError(
'Message type "{0}" should not have multiple '
512 '"{1}" fields.'.format(
513 message.DESCRIPTOR.full_name, name))
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)
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
531 message.ClearField(field.name)
536 message.ClearField(field.name)
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:
546 sub_message =
getattr(message, field.name).add()
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.')
557 raise ParseError(
'null is not allowed to be used as an element'
558 ' in a repeated field.')
559 getattr(message, field.name).append(
561 elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
562 if field.is_extension:
563 sub_message = message.Extensions[field]
565 sub_message =
getattr(message, field.name)
566 sub_message.SetInParent()
569 if field.is_extension:
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))
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))
584 """Convert a JSON representation into Any message."""
585 if isinstance(value, dict)
and not value:
588 type_url = value[
'@type']
590 raise ParseError(
'@type is missing when parsing any message.')
593 message_descriptor = sub_message.DESCRIPTOR
594 full_name = message_descriptor.full_name
597 elif full_name
in _WKTJSONMETHODS:
599 _WKTJSONMETHODS[full_name][1], value[
'value'], sub_message)(self)
603 value[
'@type'] = type_url
605 message.value = sub_message.SerializeToString()
606 message.type_url = type_url
609 """Convert a JSON representation into message with FromJsonString."""
613 message.FromJsonString(value)
614 except ValueError
as e:
618 """Convert a JSON representation into Value message."""
619 if isinstance(value, dict):
621 elif isinstance(value, list):
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
632 raise ParseError(
'Unexpected type for Value message.')
635 """Convert a JSON representation into ListValue message."""
636 if not isinstance(value, list):
638 'ListValue must be in [] which is {0}.'.format(value))
639 message.ClearField(
'values')
644 """Convert a JSON representation into Struct message."""
645 if not isinstance(value, dict):
647 'Struct must be in a dict which is {0}.'.format(value))
656 """Convert a JSON representation into Wrapper message."""
657 field = message.DESCRIPTOR.fields_by_name[
'value']
661 """Convert map field value for a message map field.
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.
669 ParseError: In case of convert problems.
671 if not isinstance(value, dict):
673 'Map field {0} must be in a dict which is {1}.'.format(
675 key_field = field.message_type.fields_by_name[
'key']
676 value_field = field.message_type.fields_by_name[
'value']
679 if value_field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
681 message, field.name)[key_value])
684 value[key], value_field)
688 """Convert a single scalar field value.
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.
696 The converted scalar field value
699 ParseError: In case of convert problems.
701 if field.cpp_type
in _INT_TYPES:
703 elif field.cpp_type
in _FLOAT_TYPES:
705 elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_BOOL:
707 elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_STRING:
708 if field.type == descriptor.FieldDescriptor.TYPE_BYTES:
709 return base64.b64decode(value)
713 if _UNPAIRED_SURROGATE_PATTERN.search(value):
716 elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_ENUM:
718 enum_value = field.enum_type.values_by_name.get(value,
None)
719 if enum_value
is None:
722 enum_value = field.enum_type.values_by_number.get(number,
None)
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':
730 raise ParseError(
'Invalid enum value {0} for enum type {1}.'.format(
731 value, field.enum_type.full_name))
732 return enum_value.number
736 """Convert an integer.
739 value: A scalar value to convert.
745 ParseError: If an integer couldn't be consumed.
747 if isinstance(value, float)
and not value.is_integer():
748 raise ParseError(
'Couldn\'t parse integer: {0}.'.format(value))
750 if isinstance(value, six.text_type)
and value.find(
' ') != -1:
751 raise ParseError(
'Couldn\'t parse integer: "{0}".'.format(value))
757 """Convert an floating point number."""
759 raise ParseError(
'Couldn\'t parse float "nan", use "NaN" instead.')
765 if value == _NEG_INFINITY:
767 elif value == _INFINITY:
772 raise ParseError(
'Couldn\'t parse float: {0}.'.format(value))
776 """Convert a boolean value.
779 value: A scalar value to convert.
780 require_str: If True, value must be a str.
786 ParseError: If a boolean value couldn't be consumed.
791 elif value ==
'false':
794 raise ParseError(
'Expected "true" or "false", not {0}.'.format(value))
796 if not isinstance(value, bool):
797 raise ParseError(
'Expected true or false without quotes.')
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']