1# Protocol Buffers - Google's data interchange format 
    2# Copyright 2008 Google Inc.  All rights reserved. 
    3# 
    4# Use of this source code is governed by a BSD-style 
    5# license that can be found in the LICENSE file or at 
    6# https://developers.google.com/open-source/licenses/bsd 
    7 
    8"""Contains routines for printing protocol messages in JSON format. 
    9 
    10Simple usage example: 
    11 
    12  # Create a proto object and serialize it to a json format string. 
    13  message = my_proto_pb2.MyMessage(foo='bar') 
    14  json_string = json_format.MessageToJson(message) 
    15 
    16  # Parse a json format string to proto object. 
    17  message = json_format.Parse(json_string, my_proto_pb2.MyMessage()) 
    18""" 
    19 
    20__author__ = 'jieluo@google.com (Jie Luo)' 
    21 
    22 
    23import base64 
    24from collections import OrderedDict 
    25import json 
    26import math 
    27from operator import methodcaller 
    28import re 
    29import warnings 
    30 
    31from google.protobuf import descriptor 
    32from google.protobuf import message_factory 
    33from google.protobuf import symbol_database 
    34from google.protobuf.internal import type_checkers 
    35 
    36 
    37_INT_TYPES = frozenset([ 
    38    descriptor.FieldDescriptor.CPPTYPE_INT32, 
    39    descriptor.FieldDescriptor.CPPTYPE_UINT32, 
    40    descriptor.FieldDescriptor.CPPTYPE_INT64, 
    41    descriptor.FieldDescriptor.CPPTYPE_UINT64, 
    42]) 
    43_INT64_TYPES = frozenset([ 
    44    descriptor.FieldDescriptor.CPPTYPE_INT64, 
    45    descriptor.FieldDescriptor.CPPTYPE_UINT64, 
    46]) 
    47_FLOAT_TYPES = frozenset([ 
    48    descriptor.FieldDescriptor.CPPTYPE_FLOAT, 
    49    descriptor.FieldDescriptor.CPPTYPE_DOUBLE, 
    50]) 
    51_INFINITY = 'Infinity' 
    52_NEG_INFINITY = '-Infinity' 
    53_NAN = 'NaN' 
    54 
    55_UNPAIRED_SURROGATE_PATTERN = re.compile( 
    56    '[\ud800-\udbff](?![\udc00-\udfff])|(?<![\ud800-\udbff])[\udc00-\udfff]' 
    57) 
    58 
    59_VALID_EXTENSION_NAME = re.compile(r'\[[a-zA-Z0-9\._]*\]$') 
    60 
    61 
    62class Error(Exception): 
    63  """Top-level module error for json_format.""" 
    64 
    65 
    66class SerializeToJsonError(Error): 
    67  """Thrown if serialization to JSON fails.""" 
    68 
    69 
    70class ParseError(Error): 
    71  """Thrown in case of parsing error.""" 
    72 
    73 
    74class EnumStringValueParseError(ParseError): 
    75  """Thrown if unknown string enum value is encountered. 
    76 
    77  This exception is suppressed if ignore_unknown_fields is set. 
    78  """ 
    79 
    80 
    81def MessageToJson( 
    82    message, 
    83    preserving_proto_field_name=False, 
    84    indent=2, 
    85    sort_keys=False, 
    86    use_integers_for_enums=False, 
    87    descriptor_pool=None, 
    88    float_precision=None, 
    89    ensure_ascii=True, 
    90    always_print_fields_with_no_presence=False, 
    91): 
    92  """Converts protobuf message to JSON format. 
    93 
    94  Args: 
    95    message: The protocol buffers message instance to serialize. 
    96    always_print_fields_with_no_presence: If True, fields without presence 
    97      (implicit presence scalars, repeated fields, and map fields) will always 
    98      be serialized. Any field that supports presence is not affected by this 
    99      option (including singular message fields and oneof fields). 
    100    preserving_proto_field_name: If True, use the original proto field names as 
    101      defined in the .proto file. If False, convert the field names to 
    102      lowerCamelCase. 
    103    indent: The JSON object will be pretty-printed with this indent level. An 
    104      indent level of 0 or negative will only insert newlines. If the indent 
    105      level is None, no newlines will be inserted. 
    106    sort_keys: If True, then the output will be sorted by field names. 
    107    use_integers_for_enums: If true, print integers instead of enum names. 
    108    descriptor_pool: A Descriptor Pool for resolving types. If None use the 
    109      default. 
    110    float_precision: Deprecated. If set, use this to specify float field valid 
    111      digits. 
    112    ensure_ascii: If True, strings with non-ASCII characters are escaped. If 
    113      False, Unicode strings are returned unchanged. 
    114 
    115  Returns: 
    116    A string containing the JSON formatted protocol buffer message. 
    117  """ 
    118  printer = _Printer( 
    119      preserving_proto_field_name, 
    120      use_integers_for_enums, 
    121      descriptor_pool, 
    122      float_precision, 
    123      always_print_fields_with_no_presence, 
    124  ) 
    125  return printer.ToJsonString(message, indent, sort_keys, ensure_ascii) 
    126 
    127 
    128def MessageToDict( 
    129    message, 
    130    always_print_fields_with_no_presence=False, 
    131    preserving_proto_field_name=False, 
    132    use_integers_for_enums=False, 
    133    descriptor_pool=None, 
    134    float_precision=None, 
    135): 
    136  """Converts protobuf message to a dictionary. 
    137 
    138  When the dictionary is encoded to JSON, it conforms to proto3 JSON spec. 
    139 
    140  Args: 
    141    message: The protocol buffers message instance to serialize. 
    142    always_print_fields_with_no_presence: If True, fields without presence 
    143      (implicit presence scalars, repeated fields, and map fields) will always 
    144      be serialized. Any field that supports presence is not affected by this 
    145      option (including singular message fields and oneof fields). 
    146    preserving_proto_field_name: If True, use the original proto field names as 
    147      defined in the .proto file. If False, convert the field names to 
    148      lowerCamelCase. 
    149    use_integers_for_enums: If true, print integers instead of enum names. 
    150    descriptor_pool: A Descriptor Pool for resolving types. If None use the 
    151      default. 
    152    float_precision: Deprecated. If set, use this to specify float field valid 
    153      digits. 
    154 
    155  Returns: 
    156    A dict representation of the protocol buffer message. 
    157  """ 
    158  printer = _Printer( 
    159      preserving_proto_field_name, 
    160      use_integers_for_enums, 
    161      descriptor_pool, 
    162      float_precision, 
    163      always_print_fields_with_no_presence, 
    164  ) 
    165  # pylint: disable=protected-access 
    166  return printer._MessageToJsonObject(message) 
    167 
    168 
    169def _IsMapEntry(field): 
    170  return ( 
    171      field.type == descriptor.FieldDescriptor.TYPE_MESSAGE 
    172      and field.message_type.has_options 
    173      and field.message_type.GetOptions().map_entry 
    174  ) 
    175 
    176 
    177class _Printer(object): 
    178  """JSON format printer for protocol message.""" 
    179 
    180  def __init__( 
    181      self, 
    182      preserving_proto_field_name=False, 
    183      use_integers_for_enums=False, 
    184      descriptor_pool=None, 
    185      float_precision=None, 
    186      always_print_fields_with_no_presence=False, 
    187  ): 
    188    self.always_print_fields_with_no_presence = ( 
    189        always_print_fields_with_no_presence 
    190    ) 
    191    self.preserving_proto_field_name = preserving_proto_field_name 
    192    self.use_integers_for_enums = use_integers_for_enums 
    193    self.descriptor_pool = descriptor_pool 
    194    if float_precision: 
    195      warnings.warn( 
    196          'float_precision option is deprecated for json_format. ' 
    197          'This will turn into error in 7.34.0, please remove it ' 
    198          'before that.' 
    199      ) 
    200      self.float_format = '.{}g'.format(float_precision) 
    201    else: 
    202      self.float_format = None 
    203 
    204  def ToJsonString(self, message, indent, sort_keys, ensure_ascii): 
    205    js = self._MessageToJsonObject(message) 
    206    return json.dumps( 
    207        js, indent=indent, sort_keys=sort_keys, ensure_ascii=ensure_ascii 
    208    ) 
    209 
    210  def _MessageToJsonObject(self, message): 
    211    """Converts message to an object according to Proto3 JSON Specification.""" 
    212    message_descriptor = message.DESCRIPTOR 
    213    full_name = message_descriptor.full_name 
    214    if _IsWrapperMessage(message_descriptor): 
    215      return self._WrapperMessageToJsonObject(message) 
    216    if full_name in _WKTJSONMETHODS: 
    217      return methodcaller(_WKTJSONMETHODS[full_name][0], message)(self) 
    218    js = {} 
    219    return self._RegularMessageToJsonObject(message, js) 
    220 
    221  def _RegularMessageToJsonObject(self, message, js): 
    222    """Converts normal message according to Proto3 JSON Specification.""" 
    223    fields = message.ListFields() 
    224 
    225    try: 
    226      for field, value in fields: 
    227        if field.is_extension: 
    228          name = '[%s]' % field.full_name 
    229        elif self.preserving_proto_field_name: 
    230          name = field.name 
    231        else: 
    232          name = field.json_name 
    233 
    234        if _IsMapEntry(field): 
    235          # Convert a map field. 
    236          v_field = field.message_type.fields_by_name['value'] 
    237          js_map = {} 
    238          for key in value: 
    239            if isinstance(key, bool): 
    240              if key: 
    241                recorded_key = 'true' 
    242              else: 
    243                recorded_key = 'false' 
    244            else: 
    245              recorded_key = str(key) 
    246            js_map[recorded_key] = self._FieldToJsonObject(v_field, value[key]) 
    247          js[name] = js_map 
    248        elif field.is_repeated: 
    249          # Convert a repeated field. 
    250          js[name] = [self._FieldToJsonObject(field, k) for k in value] 
    251        else: 
    252          js[name] = self._FieldToJsonObject(field, value) 
    253 
    254      # Serialize default value if including_default_value_fields is True. 
    255      if ( 
    256          self.always_print_fields_with_no_presence 
    257      ): 
    258        message_descriptor = message.DESCRIPTOR 
    259        for field in message_descriptor.fields: 
    260 
    261          # always_print_fields_with_no_presence doesn't apply to 
    262          # any field which supports presence. 
    263          if self.always_print_fields_with_no_presence and field.has_presence: 
    264            continue 
    265 
    266          if self.preserving_proto_field_name: 
    267            name = field.name 
    268          else: 
    269            name = field.json_name 
    270          if name in js: 
    271            # Skip the field which has been serialized already. 
    272            continue 
    273          if _IsMapEntry(field): 
    274            js[name] = {} 
    275          elif field.is_repeated: 
    276            js[name] = [] 
    277          else: 
    278            js[name] = self._FieldToJsonObject(field, field.default_value) 
    279 
    280    except ValueError as e: 
    281      raise SerializeToJsonError( 
    282          'Failed to serialize {0} field: {1}.'.format(field.name, e) 
    283      ) from e 
    284 
    285    return js 
    286 
    287  def _FieldToJsonObject(self, field, value): 
    288    """Converts field value according to Proto3 JSON Specification.""" 
    289    if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE: 
    290      return self._MessageToJsonObject(value) 
    291    elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_ENUM: 
    292      if self.use_integers_for_enums: 
    293        return value 
    294      if field.enum_type.full_name == 'google.protobuf.NullValue': 
    295        return None 
    296      enum_value = field.enum_type.values_by_number.get(value, None) 
    297      if enum_value is not None: 
    298        return enum_value.name 
    299      else: 
    300        if field.enum_type.is_closed: 
    301          raise SerializeToJsonError( 
    302              'Enum field contains an integer value ' 
    303              'which can not mapped to an enum value.' 
    304          ) 
    305        else: 
    306          return value 
    307    elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_STRING: 
    308      if field.type == descriptor.FieldDescriptor.TYPE_BYTES: 
    309        # Use base64 Data encoding for bytes 
    310        return base64.b64encode(value).decode('utf-8') 
    311      else: 
    312        return str(value) 
    313    elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_BOOL: 
    314      return bool(value) 
    315    elif field.cpp_type in _INT64_TYPES: 
    316      return str(value) 
    317    elif field.cpp_type in _FLOAT_TYPES: 
    318      if math.isinf(value): 
    319        if value < 0.0: 
    320          return _NEG_INFINITY 
    321        else: 
    322          return _INFINITY 
    323      if math.isnan(value): 
    324        return _NAN 
    325      if self.float_format: 
    326        return float(format(value, self.float_format)) 
    327      elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_FLOAT: 
    328        return type_checkers.ToShortestFloat(value) 
    329 
    330    return value 
    331 
    332  def _AnyMessageToJsonObject(self, message): 
    333    """Converts Any message according to Proto3 JSON Specification.""" 
    334    if not message.ListFields(): 
    335      return {} 
    336    # Must print @type first, use OrderedDict instead of {} 
    337    js = OrderedDict() 
    338    type_url = message.type_url 
    339    js['@type'] = type_url 
    340    sub_message = _CreateMessageFromTypeUrl(type_url, self.descriptor_pool) 
    341    sub_message.ParseFromString(message.value) 
    342    message_descriptor = sub_message.DESCRIPTOR 
    343    full_name = message_descriptor.full_name 
    344    if _IsWrapperMessage(message_descriptor): 
    345      js['value'] = self._WrapperMessageToJsonObject(sub_message) 
    346      return js 
    347    if full_name in _WKTJSONMETHODS: 
    348      js['value'] = methodcaller(_WKTJSONMETHODS[full_name][0], sub_message)( 
    349          self 
    350      ) 
    351      return js 
    352    return self._RegularMessageToJsonObject(sub_message, js) 
    353 
    354  def _GenericMessageToJsonObject(self, message): 
    355    """Converts message according to Proto3 JSON Specification.""" 
    356    # Duration, Timestamp and FieldMask have ToJsonString method to do the 
    357    # convert. Users can also call the method directly. 
    358    return message.ToJsonString() 
    359 
    360  def _ValueMessageToJsonObject(self, message): 
    361    """Converts Value message according to Proto3 JSON Specification.""" 
    362    which = message.WhichOneof('kind') 
    363    # If the Value message is not set treat as null_value when serialize 
    364    # to JSON. The parse back result will be different from original message. 
    365    if which is None or which == 'null_value': 
    366      return None 
    367    if which == 'list_value': 
    368      return self._ListValueMessageToJsonObject(message.list_value) 
    369    if which == 'number_value': 
    370      value = message.number_value 
    371      if math.isinf(value): 
    372        raise ValueError( 
    373            'Fail to serialize Infinity for Value.number_value, ' 
    374            'which would parse as string_value' 
    375        ) 
    376      if math.isnan(value): 
    377        raise ValueError( 
    378            'Fail to serialize NaN for Value.number_value, ' 
    379            'which would parse as string_value' 
    380        ) 
    381    else: 
    382      value = getattr(message, which) 
    383    oneof_descriptor = message.DESCRIPTOR.fields_by_name[which] 
    384    return self._FieldToJsonObject(oneof_descriptor, value) 
    385 
    386  def _ListValueMessageToJsonObject(self, message): 
    387    """Converts ListValue message according to Proto3 JSON Specification.""" 
    388    return [self._ValueMessageToJsonObject(value) for value in message.values] 
    389 
    390  def _StructMessageToJsonObject(self, message): 
    391    """Converts Struct message according to Proto3 JSON Specification.""" 
    392    fields = message.fields 
    393    ret = {} 
    394    for key in fields: 
    395      ret[key] = self._ValueMessageToJsonObject(fields[key]) 
    396    return ret 
    397 
    398  def _WrapperMessageToJsonObject(self, message): 
    399    return self._FieldToJsonObject( 
    400        message.DESCRIPTOR.fields_by_name['value'], message.value 
    401    ) 
    402 
    403 
    404def _IsWrapperMessage(message_descriptor): 
    405  return message_descriptor.file.name == 'google/protobuf/wrappers.proto' 
    406 
    407 
    408def _DuplicateChecker(js): 
    409  result = {} 
    410  for name, value in js: 
    411    if name in result: 
    412      raise ParseError('Failed to load JSON: duplicate key {0}.'.format(name)) 
    413    result[name] = value 
    414  return result 
    415 
    416 
    417def _CreateMessageFromTypeUrl(type_url, descriptor_pool): 
    418  """Creates a message from a type URL.""" 
    419  db = symbol_database.Default() 
    420  pool = db.pool if descriptor_pool is None else descriptor_pool 
    421  type_name = type_url.split('/')[-1] 
    422  try: 
    423    message_descriptor = pool.FindMessageTypeByName(type_name) 
    424  except KeyError as e: 
    425    raise TypeError( 
    426        'Can not find message descriptor by type_url: {0}'.format(type_url) 
    427    ) from e 
    428  message_class = message_factory.GetMessageClass(message_descriptor) 
    429  return message_class() 
    430 
    431 
    432def Parse( 
    433    text, 
    434    message, 
    435    ignore_unknown_fields=False, 
    436    descriptor_pool=None, 
    437    max_recursion_depth=100, 
    438): 
    439  """Parses a JSON representation of a protocol message into a message. 
    440 
    441  Args: 
    442    text: Message JSON representation. 
    443    message: A protocol buffer message to merge into. 
    444    ignore_unknown_fields: If True, do not raise errors for unknown fields. 
    445    descriptor_pool: A Descriptor Pool for resolving types. If None use the 
    446      default. 
    447    max_recursion_depth: max recursion depth of JSON message to be deserialized. 
    448      JSON messages over this depth will fail to be deserialized. Default value 
    449      is 100. 
    450 
    451  Returns: 
    452    The same message passed as argument. 
    453 
    454  Raises:: 
    455    ParseError: On JSON parsing problems. 
    456  """ 
    457  if not isinstance(text, str): 
    458    text = text.decode('utf-8') 
    459 
    460  try: 
    461    js = json.loads(text, object_pairs_hook=_DuplicateChecker) 
    462  except Exception as e: 
    463    raise ParseError('Failed to load JSON: {0}.'.format(str(e))) from e 
    464 
    465  try: 
    466    return ParseDict( 
    467        js, message, ignore_unknown_fields, descriptor_pool, max_recursion_depth 
    468    ) 
    469  except ParseError as e: 
    470    raise e 
    471  except Exception as e: 
    472    raise ParseError( 
    473        'Failed to parse JSON: {0}: {1}.'.format(type(e).__name__, str(e)) 
    474    ) from e 
    475 
    476 
    477def ParseDict( 
    478    js_dict, 
    479    message, 
    480    ignore_unknown_fields=False, 
    481    descriptor_pool=None, 
    482    max_recursion_depth=100, 
    483): 
    484  """Parses a JSON dictionary representation into a message. 
    485 
    486  Args: 
    487    js_dict: Dict representation of a JSON message. 
    488    message: A protocol buffer message to merge into. 
    489    ignore_unknown_fields: If True, do not raise errors for unknown fields. 
    490    descriptor_pool: A Descriptor Pool for resolving types. If None use the 
    491      default. 
    492    max_recursion_depth: max recursion depth of JSON message to be deserialized. 
    493      JSON messages over this depth will fail to be deserialized. Default value 
    494      is 100. 
    495 
    496  Returns: 
    497    The same message passed as argument. 
    498  """ 
    499  parser = _Parser(ignore_unknown_fields, descriptor_pool, max_recursion_depth) 
    500  parser.ConvertMessage(js_dict, message, '') 
    501  return message 
    502 
    503 
    504_INT_OR_FLOAT = (int, float) 
    505_LIST_LIKE = (list, tuple) 
    506 
    507 
    508class _Parser(object): 
    509  """JSON format parser for protocol message.""" 
    510 
    511  def __init__( 
    512      self, ignore_unknown_fields, descriptor_pool, max_recursion_depth 
    513  ): 
    514    self.ignore_unknown_fields = ignore_unknown_fields 
    515    self.descriptor_pool = descriptor_pool 
    516    self.max_recursion_depth = max_recursion_depth 
    517    self.recursion_depth = 0 
    518 
    519  def ConvertMessage(self, value, message, path): 
    520    """Convert a JSON object into a message. 
    521 
    522    Args: 
    523      value: A JSON object. 
    524      message: A WKT or regular protocol message to record the data. 
    525      path: parent path to log parse error info. 
    526 
    527    Raises: 
    528      ParseError: In case of convert problems. 
    529    """ 
    530    self.recursion_depth += 1 
    531    if self.recursion_depth > self.max_recursion_depth: 
    532      raise ParseError( 
    533          'Message too deep. Max recursion depth is {0}'.format( 
    534              self.max_recursion_depth 
    535          ) 
    536      ) 
    537    message_descriptor = message.DESCRIPTOR 
    538    full_name = message_descriptor.full_name 
    539    if not path: 
    540      path = message_descriptor.name 
    541    if _IsWrapperMessage(message_descriptor): 
    542      self._ConvertWrapperMessage(value, message, path) 
    543    elif full_name in _WKTJSONMETHODS: 
    544      methodcaller(_WKTJSONMETHODS[full_name][1], value, message, path)(self) 
    545    else: 
    546      self._ConvertFieldValuePair(value, message, path) 
    547    self.recursion_depth -= 1 
    548 
    549  def _ConvertFieldValuePair(self, js, message, path): 
    550    """Convert field value pairs into regular message. 
    551 
    552    Args: 
    553      js: A JSON object to convert the field value pairs. 
    554      message: A regular protocol message to record the data. 
    555      path: parent path to log parse error info. 
    556 
    557    Raises: 
    558      ParseError: In case of problems converting. 
    559    """ 
    560    names = [] 
    561    message_descriptor = message.DESCRIPTOR 
    562    fields_by_json_name = dict( 
    563        (f.json_name, f) for f in message_descriptor.fields 
    564    ) 
    565 
    566    def _ClearFieldOrExtension(message, field): 
    567      if field.is_extension: 
    568        message.ClearExtension(field) 
    569      else: 
    570        message.ClearField(field.name) 
    571 
    572    def _GetFieldOrExtension(message, field): 
    573      if field.is_extension: 
    574        return message.Extensions[field] 
    575      else: 
    576        return getattr(message, field.name) 
    577 
    578    def _SetFieldOrExtension(message, field, value): 
    579      if field.is_extension: 
    580        message.Extensions[field] = value 
    581      else: 
    582        setattr(message, field.name, value) 
    583 
    584    for name in js: 
    585      try: 
    586        field = fields_by_json_name.get(name, None) 
    587        if not field: 
    588          field = message_descriptor.fields_by_name.get(name, None) 
    589        if not field and _VALID_EXTENSION_NAME.match(name): 
    590          if not message_descriptor.is_extendable: 
    591            raise ParseError( 
    592                'Message type {0} does not have extensions at {1}'.format( 
    593                    message_descriptor.full_name, path 
    594                ) 
    595            ) 
    596          identifier = name[1:-1]  # strip [] brackets 
    597          # pylint: disable=protected-access 
    598          field = message.Extensions._FindExtensionByName(identifier) 
    599          # pylint: enable=protected-access 
    600          if not field: 
    601            # Try looking for extension by the message type name, dropping the 
    602            # field name following the final . separator in full_name. 
    603            identifier = '.'.join(identifier.split('.')[:-1]) 
    604            # pylint: disable=protected-access 
    605            field = message.Extensions._FindExtensionByName(identifier) 
    606            # pylint: enable=protected-access 
    607        if not field: 
    608          if self.ignore_unknown_fields: 
    609            continue 
    610          raise ParseError( 
    611              ( 
    612                  'Message type "{0}" has no field named "{1}" at "{2}".\n' 
    613                  ' Available Fields(except extensions): "{3}"' 
    614              ).format( 
    615                  message_descriptor.full_name, 
    616                  name, 
    617                  path, 
    618                  [f.json_name for f in message_descriptor.fields], 
    619              ) 
    620          ) 
    621        if name in names: 
    622          raise ParseError( 
    623              'Message type "{0}" should not have multiple ' 
    624              '"{1}" fields at "{2}".'.format( 
    625                  message.DESCRIPTOR.full_name, name, path 
    626              ) 
    627          ) 
    628        names.append(name) 
    629        value = js[name] 
    630        # Check no other oneof field is parsed. 
    631        if field.containing_oneof is not None and value is not None: 
    632          oneof_name = field.containing_oneof.name 
    633          if oneof_name in names: 
    634            raise ParseError( 
    635                'Message type "{0}" should not have multiple ' 
    636                '"{1}" oneof fields at "{2}".'.format( 
    637                    message.DESCRIPTOR.full_name, oneof_name, path 
    638                ) 
    639            ) 
    640          names.append(oneof_name) 
    641 
    642        if value is None: 
    643          if ( 
    644              field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE 
    645              and field.message_type.full_name == 'google.protobuf.Value' 
    646          ): 
    647            sub_message = _GetFieldOrExtension(message, field) 
    648            sub_message.null_value = 0 
    649          elif ( 
    650              field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_ENUM 
    651              and field.enum_type.full_name == 'google.protobuf.NullValue' 
    652          ): 
    653            _SetFieldOrExtension(message, field, 0) 
    654          else: 
    655            _ClearFieldOrExtension(message, field) 
    656          continue 
    657 
    658        # Parse field value. 
    659        if _IsMapEntry(field): 
    660          _ClearFieldOrExtension(message, field) 
    661          self._ConvertMapFieldValue( 
    662              value, message, field, '{0}.{1}'.format(path, name) 
    663          ) 
    664        elif field.is_repeated: 
    665          _ClearFieldOrExtension(message, field) 
    666          if not isinstance(value, _LIST_LIKE): 
    667            raise ParseError( 
    668                'repeated field {0} must be in [] which is {1} at {2}'.format( 
    669                    name, value, path 
    670                ) 
    671            ) 
    672          if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE: 
    673            # Repeated message field. 
    674            for index, item in enumerate(value): 
    675              sub_message = _GetFieldOrExtension(message, field).add() 
    676              # None is a null_value in Value. 
    677              if ( 
    678                  item is None 
    679                  and sub_message.DESCRIPTOR.full_name 
    680                  != 'google.protobuf.Value' 
    681              ): 
    682                raise ParseError( 
    683                    'null is not allowed to be used as an element' 
    684                    ' in a repeated field at {0}.{1}[{2}]'.format( 
    685                        path, name, index 
    686                    ) 
    687                ) 
    688              self.ConvertMessage( 
    689                  item, sub_message, '{0}.{1}[{2}]'.format(path, name, index) 
    690              ) 
    691          else: 
    692            # Repeated scalar field. 
    693            for index, item in enumerate(value): 
    694              if item is None: 
    695                raise ParseError( 
    696                    'null is not allowed to be used as an element' 
    697                    ' in a repeated field at {0}.{1}[{2}]'.format( 
    698                        path, name, index 
    699                    ) 
    700                ) 
    701              self._ConvertAndAppendScalar( 
    702                  message, field, item, '{0}.{1}[{2}]'.format(path, name, index) 
    703              ) 
    704        elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE: 
    705          sub_message = _GetFieldOrExtension(message, field) 
    706          sub_message.SetInParent() 
    707          self.ConvertMessage(value, sub_message, '{0}.{1}'.format(path, name)) 
    708        else: 
    709          self._ConvertAndSetScalar( 
    710              message, field, value, '{0}.{1}'.format(path, name) 
    711          ) 
    712      except ParseError as e: 
    713        if field and field.containing_oneof is None: 
    714          raise ParseError( 
    715              'Failed to parse {0} field: {1}.'.format(name, e) 
    716          ) from e 
    717        else: 
    718          raise ParseError(str(e)) from e 
    719      except ValueError as e: 
    720        raise ParseError( 
    721            'Failed to parse {0} field: {1}.'.format(name, e) 
    722        ) from e 
    723      except TypeError as e: 
    724        raise ParseError( 
    725            'Failed to parse {0} field: {1}.'.format(name, e) 
    726        ) from e 
    727 
    728  def _ConvertAnyMessage(self, value, message, path): 
    729    """Convert a JSON representation into Any message.""" 
    730    if isinstance(value, dict) and not value: 
    731      return 
    732    try: 
    733      type_url = value['@type'] 
    734    except KeyError as e: 
    735      raise ParseError( 
    736          '@type is missing when parsing any message at {0}'.format(path) 
    737      ) from e 
    738 
    739    try: 
    740      sub_message = _CreateMessageFromTypeUrl(type_url, self.descriptor_pool) 
    741    except TypeError as e: 
    742      raise ParseError('{0} at {1}'.format(e, path)) from e 
    743    message_descriptor = sub_message.DESCRIPTOR 
    744    full_name = message_descriptor.full_name 
    745    if _IsWrapperMessage(message_descriptor): 
    746      self._ConvertWrapperMessage( 
    747          value['value'], sub_message, '{0}.value'.format(path) 
    748      ) 
    749    elif full_name in _WKTJSONMETHODS: 
    750      methodcaller( 
    751          _WKTJSONMETHODS[full_name][1], 
    752          value['value'], 
    753          sub_message, 
    754          '{0}.value'.format(path), 
    755      )(self) 
    756    else: 
    757      del value['@type'] 
    758      try: 
    759        self._ConvertFieldValuePair(value, sub_message, path) 
    760      finally: 
    761        value['@type'] = type_url 
    762    # Sets Any message 
    763    message.value = sub_message.SerializeToString() 
    764    message.type_url = type_url 
    765 
    766  def _ConvertGenericMessage(self, value, message, path): 
    767    """Convert a JSON representation into message with FromJsonString.""" 
    768    # Duration, Timestamp, FieldMask have a FromJsonString method to do the 
    769    # conversion. Users can also call the method directly. 
    770    try: 
    771      message.FromJsonString(value) 
    772    except ValueError as e: 
    773      raise ParseError('{0} at {1}'.format(e, path)) from e 
    774 
    775  def _ConvertValueMessage(self, value, message, path): 
    776    """Convert a JSON representation into Value message.""" 
    777    if isinstance(value, dict): 
    778      self._ConvertStructMessage(value, message.struct_value, path) 
    779    elif isinstance(value, _LIST_LIKE): 
    780      self._ConvertListOrTupleValueMessage(value, message.list_value, path) 
    781    elif value is None: 
    782      message.null_value = 0 
    783    elif isinstance(value, bool): 
    784      message.bool_value = value 
    785    elif isinstance(value, str): 
    786      message.string_value = value 
    787    elif isinstance(value, _INT_OR_FLOAT): 
    788      message.number_value = value 
    789    else: 
    790      raise ParseError( 
    791          'Value {0} has unexpected type {1} at {2}'.format( 
    792              value, type(value), path 
    793          ) 
    794      ) 
    795 
    796  def _ConvertListOrTupleValueMessage(self, value, message, path): 
    797    """Convert a JSON representation into ListValue message.""" 
    798    if not isinstance(value, _LIST_LIKE): 
    799      raise ParseError( 
    800          'ListValue must be in [] which is {0} at {1}'.format(value, path) 
    801      ) 
    802    message.ClearField('values') 
    803    for index, item in enumerate(value): 
    804      self._ConvertValueMessage( 
    805          item, message.values.add(), '{0}[{1}]'.format(path, index) 
    806      ) 
    807 
    808  def _ConvertStructMessage(self, value, message, path): 
    809    """Convert a JSON representation into Struct message.""" 
    810    if not isinstance(value, dict): 
    811      raise ParseError( 
    812          'Struct must be in a dict which is {0} at {1}'.format(value, path) 
    813      ) 
    814    # Clear will mark the struct as modified so it will be created even if 
    815    # there are no values. 
    816    message.Clear() 
    817    for key in value: 
    818      self._ConvertValueMessage( 
    819          value[key], message.fields[key], '{0}.{1}'.format(path, key) 
    820      ) 
    821    return 
    822 
    823  def _ConvertWrapperMessage(self, value, message, path): 
    824    """Convert a JSON representation into Wrapper message.""" 
    825    field = message.DESCRIPTOR.fields_by_name['value'] 
    826    self._ConvertAndSetScalar( 
    827        message, field, value, path='{0}.value'.format(path) 
    828    ) 
    829 
    830  def _ConvertMapFieldValue(self, value, message, field, path): 
    831    """Convert map field value for a message map field. 
    832 
    833    Args: 
    834      value: A JSON object to convert the map field value. 
    835      message: A protocol message to record the converted data. 
    836      field: The descriptor of the map field to be converted. 
    837      path: parent path to log parse error info. 
    838 
    839    Raises: 
    840      ParseError: In case of convert problems. 
    841    """ 
    842    if not isinstance(value, dict): 
    843      raise ParseError( 
    844          'Map field {0} must be in a dict which is {1} at {2}'.format( 
    845              field.name, value, path 
    846          ) 
    847      ) 
    848    key_field = field.message_type.fields_by_name['key'] 
    849    value_field = field.message_type.fields_by_name['value'] 
    850    for key in value: 
    851      key_value = _ConvertScalarFieldValue( 
    852          key, key_field, '{0}.key'.format(path), True 
    853      ) 
    854      if value_field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE: 
    855        self.ConvertMessage( 
    856            value[key], 
    857            getattr(message, field.name)[key_value], 
    858            '{0}[{1}]'.format(path, key_value), 
    859        ) 
    860      else: 
    861        self._ConvertAndSetScalarToMapKey( 
    862            message, 
    863            field, 
    864            key_value, 
    865            value[key], 
    866            path='{0}[{1}]'.format(path, key_value), 
    867        ) 
    868 
    869  def _ConvertAndSetScalar(self, message, field, js_value, path): 
    870    """Convert scalar from js_value and assign it to message.field.""" 
    871    try: 
    872      value = _ConvertScalarFieldValue(js_value, field, path) 
    873      if field.is_extension: 
    874        message.Extensions[field] = value 
    875      else: 
    876        setattr(message, field.name, value) 
    877    except EnumStringValueParseError: 
    878      if not self.ignore_unknown_fields: 
    879        raise 
    880 
    881  def _ConvertAndAppendScalar(self, message, repeated_field, js_value, path): 
    882    """Convert scalar from js_value and append it to message.repeated_field.""" 
    883    try: 
    884      if repeated_field.is_extension: 
    885        repeated = message.Extensions[repeated_field] 
    886      else: 
    887        repeated = getattr(message, repeated_field.name) 
    888      value = _ConvertScalarFieldValue(js_value, repeated_field, path) 
    889      repeated.append(value) 
    890    except EnumStringValueParseError: 
    891      if not self.ignore_unknown_fields: 
    892        raise 
    893 
    894  def _ConvertAndSetScalarToMapKey( 
    895      self, message, map_field, converted_key, js_value, path 
    896  ): 
    897    """Convert scalar from 'js_value' and add it to message.map_field[converted_key].""" 
    898    try: 
    899      getattr(message, map_field.name)[converted_key] = ( 
    900          _ConvertScalarFieldValue( 
    901              js_value, 
    902              map_field.message_type.fields_by_name['value'], 
    903              path, 
    904          ) 
    905      ) 
    906    except EnumStringValueParseError: 
    907      if not self.ignore_unknown_fields: 
    908        raise 
    909 
    910 
    911def _ConvertScalarFieldValue(value, field, path, require_str=False): 
    912  """Convert a single scalar field value. 
    913 
    914  Args: 
    915    value: A scalar value to convert the scalar field value. 
    916    field: The descriptor of the field to convert. 
    917    path: parent path to log parse error info. 
    918    require_str: If True, the field value must be a str. 
    919 
    920  Returns: 
    921    The converted scalar field value 
    922 
    923  Raises: 
    924    ParseError: In case of convert problems. 
    925    EnumStringValueParseError: In case of unknown enum string value. 
    926  """ 
    927  try: 
    928    if field.cpp_type in _INT_TYPES: 
    929      return _ConvertInteger(value) 
    930    elif field.cpp_type in _FLOAT_TYPES: 
    931      return _ConvertFloat(value, field) 
    932    elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_BOOL: 
    933      return _ConvertBool(value, require_str) 
    934    elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_STRING: 
    935      if field.type == descriptor.FieldDescriptor.TYPE_BYTES: 
    936        if isinstance(value, str): 
    937          encoded = value.encode('utf-8') 
    938        else: 
    939          encoded = value 
    940        # Add extra padding '=' 
    941        padded_value = encoded + b'=' * (4 - len(encoded) % 4) 
    942        return base64.urlsafe_b64decode(padded_value) 
    943      else: 
    944        # Checking for unpaired surrogates appears to be unreliable, 
    945        # depending on the specific Python version, so we check manually. 
    946        if _UNPAIRED_SURROGATE_PATTERN.search(value): 
    947          raise ParseError('Unpaired surrogate') 
    948        return value 
    949    elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_ENUM: 
    950      # Convert an enum value. 
    951      enum_value = field.enum_type.values_by_name.get(value, None) 
    952      if enum_value is None: 
    953        try: 
    954          number = int(value) 
    955          enum_value = field.enum_type.values_by_number.get(number, None) 
    956        except ValueError as e: 
    957          # Since parsing to integer failed and lookup in values_by_name didn't 
    958          # find this name, we have an enum string value which is unknown. 
    959          raise EnumStringValueParseError( 
    960              'Invalid enum value {0} for enum type {1}'.format( 
    961                  value, field.enum_type.full_name 
    962              ) 
    963          ) from e 
    964        if enum_value is None: 
    965          if field.enum_type.is_closed: 
    966            raise ParseError( 
    967                'Invalid enum value {0} for enum type {1}'.format( 
    968                    value, field.enum_type.full_name 
    969                ) 
    970            ) 
    971          else: 
    972            return number 
    973      return enum_value.number 
    974  except EnumStringValueParseError as e: 
    975    raise EnumStringValueParseError('{0} at {1}'.format(e, path)) from e 
    976  except ParseError as e: 
    977    raise ParseError('{0} at {1}'.format(e, path)) from e 
    978 
    979 
    980def _ConvertInteger(value): 
    981  """Convert an integer. 
    982 
    983  Args: 
    984    value: A scalar value to convert. 
    985 
    986  Returns: 
    987    The integer value. 
    988 
    989  Raises: 
    990    ParseError: If an integer couldn't be consumed. 
    991  """ 
    992  if isinstance(value, float) and not value.is_integer(): 
    993    raise ParseError("Couldn't parse integer: {0}".format(value)) 
    994 
    995  if isinstance(value, str) and value.find(' ') != -1: 
    996    raise ParseError('Couldn\'t parse integer: "{0}"'.format(value)) 
    997 
    998  if isinstance(value, bool): 
    999    raise ParseError( 
    1000        'Bool value {0} is not acceptable for integer field'.format(value) 
    1001    ) 
    1002 
    1003  try: 
    1004    return int(value) 
    1005  except ValueError as e: 
    1006    # Attempt to parse as an integer-valued float. 
    1007    try: 
    1008      f = float(value) 
    1009    except ValueError: 
    1010      # Raise the original exception for the int parse. 
    1011      raise e  # pylint: disable=raise-missing-from 
    1012    if not f.is_integer(): 
    1013      raise ParseError( 
    1014          'Couldn\'t parse non-integer string: "{0}"'.format(value) 
    1015      ) from e 
    1016    return int(f) 
    1017 
    1018 
    1019def _ConvertFloat(value, field): 
    1020  """Convert an floating point number.""" 
    1021  if isinstance(value, float): 
    1022    if math.isnan(value): 
    1023      raise ParseError('Couldn\'t parse NaN, use quoted "NaN" instead') 
    1024    if math.isinf(value): 
    1025      if value > 0: 
    1026        raise ParseError( 
    1027            "Couldn't parse Infinity or value too large, " 
    1028            'use quoted "Infinity" instead' 
    1029        ) 
    1030      else: 
    1031        raise ParseError( 
    1032            "Couldn't parse -Infinity or value too small, " 
    1033            'use quoted "-Infinity" instead' 
    1034        ) 
    1035    if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_FLOAT: 
    1036      # pylint: disable=protected-access 
    1037      if value > type_checkers._FLOAT_MAX: 
    1038        raise ParseError('Float value too large') 
    1039      # pylint: disable=protected-access 
    1040      if value < type_checkers._FLOAT_MIN: 
    1041        raise ParseError('Float value too small') 
    1042  if value == 'nan': 
    1043    raise ParseError('Couldn\'t parse float "nan", use "NaN" instead') 
    1044  try: 
    1045    # Assume Python compatible syntax. 
    1046    return float(value) 
    1047  except ValueError as e: 
    1048    # Check alternative spellings. 
    1049    if value == _NEG_INFINITY: 
    1050      return float('-inf') 
    1051    elif value == _INFINITY: 
    1052      return float('inf') 
    1053    elif value == _NAN: 
    1054      return float('nan') 
    1055    else: 
    1056      raise ParseError("Couldn't parse float: {0}".format(value)) from e 
    1057 
    1058 
    1059def _ConvertBool(value, require_str): 
    1060  """Convert a boolean value. 
    1061 
    1062  Args: 
    1063    value: A scalar value to convert. 
    1064    require_str: If True, value must be a str. 
    1065 
    1066  Returns: 
    1067    The bool parsed. 
    1068 
    1069  Raises: 
    1070    ParseError: If a boolean value couldn't be consumed. 
    1071  """ 
    1072  if require_str: 
    1073    if value == 'true': 
    1074      return True 
    1075    elif value == 'false': 
    1076      return False 
    1077    else: 
    1078      raise ParseError('Expected "true" or "false", not {0}'.format(value)) 
    1079 
    1080  if not isinstance(value, bool): 
    1081    raise ParseError('Expected true or false without quotes') 
    1082  return value 
    1083 
    1084 
    1085_WKTJSONMETHODS = { 
    1086    'google.protobuf.Any': ['_AnyMessageToJsonObject', '_ConvertAnyMessage'], 
    1087    'google.protobuf.Duration': [ 
    1088        '_GenericMessageToJsonObject', 
    1089        '_ConvertGenericMessage', 
    1090    ], 
    1091    'google.protobuf.FieldMask': [ 
    1092        '_GenericMessageToJsonObject', 
    1093        '_ConvertGenericMessage', 
    1094    ], 
    1095    'google.protobuf.ListValue': [ 
    1096        '_ListValueMessageToJsonObject', 
    1097        '_ConvertListOrTupleValueMessage', 
    1098    ], 
    1099    'google.protobuf.Struct': [ 
    1100        '_StructMessageToJsonObject', 
    1101        '_ConvertStructMessage', 
    1102    ], 
    1103    'google.protobuf.Timestamp': [ 
    1104        '_GenericMessageToJsonObject', 
    1105        '_ConvertGenericMessage', 
    1106    ], 
    1107    'google.protobuf.Value': [ 
    1108        '_ValueMessageToJsonObject', 
    1109        '_ConvertValueMessage', 
    1110    ], 
    1111}