title: I get an error "CMessage' objects doesn't apply to a 'str' object" when I am trying to parse a dict-structure with repeating elements
body: <p>Can you help me understand why this is crashing: I'm trying to use the protobuf ParseDict function to turn a structure of Python objects into single Protocol Buffer object.</p>
  <p>As an experiment, I tried to make some protobuf instances, turn them into a dictionary structure and then turn them back into protobufs.</p>
  <p>I wrote the following code:</p>
  <pre class="lang-py prettyprint-override"><code>msg0=MsgGrpType.MsgType(subject=&quot;test_subject0&quot;)
  msg1=MsgGrpType.MsgType(subject=&quot;test_subject1&quot;)
  msg2=MsgGrpType.MsgType(subject=&quot;test_subject3&quot;)
  msgGrp = MsgGrpType(flow=&quot;BOALF&quot;, msg=[msg0,msg1,msg2], pub_ts=datetime.datetime.now().isoformat())
  msgDict = google.protobuf.json_format.MessageToDict(msgGrp)
  result = ParseDict(msgDict, MsgGrpType, ignore_unknown_fields=True) # Crashes
  pprint.pprint(result)
  </code></pre>
  <p>When I run the script, msgDict has the following structure:</p>
  <pre class="lang-py prettyprint-override"><code>{'flow': 'BOALF',
   'msg': [{'subject': 'test_subject0'},
           {'subject': 'test_subject1'},
           {'subject': 'test_subject3'}],
   'pubTs': '2021-07-19T13:18:40.263824'}
  </code></pre>
  <p>The script crashes with the following error:</p>
  <pre><code>self = &lt;google.protobuf.json_format._Parser object at 0x0000020177A3F2E0&gt;
  js = {'flow': 'BOALF', 'msg': [{'subject': 'test_subject0'}, {'subject': 'test_subject1'}, {'subject': 'test_subject3'}], 'pubTs': '2021-07-19T13:18:40.263824'}
  message = &lt;class 'com_elexeon_boalf_pb2.MsgGrpType'&gt;
  
      def _ConvertFieldValuePair(self, js, message):
        &quot;&quot;&quot;Convert field value pairs into regular message.
      
        Args:
          js: A JSON object to convert the field value pairs.
          message: A regular protocol message to record the data.
      
        Raises:
          ParseError: In case of problems converting.
        &quot;&quot;&quot;
        names = []
        message_descriptor = message.DESCRIPTOR
        fields_by_json_name = dict((f.json_name, f)
                                   for f in message_descriptor.fields)
        for name in js:
          try:
            field = fields_by_json_name.get(name, None)
            if not field:
              field = message_descriptor.fields_by_name.get(name, None)
            if not field and _VALID_EXTENSION_NAME.match(name):
              if not message_descriptor.is_extendable:
                raise ParseError('Message type {0} does not have extensions'.format(
                    message_descriptor.full_name))
              identifier = name[1:-1]  # strip [] brackets
              # pylint: disable=protected-access
              field = message.Extensions._FindExtensionByName(identifier)
              # pylint: enable=protected-access
              if not field:
                # Try looking for extension by the message type name, dropping the
                # field name following the final . separator in full_name.
                identifier = '.'.join(identifier.split('.')[:-1])
                # pylint: disable=protected-access
                field = message.Extensions._FindExtensionByName(identifier)
                # pylint: enable=protected-access
            if not field:
              if self.ignore_unknown_fields:
                continue
              raise ParseError(
                  ('Message type &quot;{0}&quot; has no field named &quot;{1}&quot;.\n'
                   ' Available Fields(except extensions): {2}').format(
                       message_descriptor.full_name, name,
                       [f.json_name for f in message_descriptor.fields]))
            if name in names:
              raise ParseError('Message type &quot;{0}&quot; should not have multiple '
                               '&quot;{1}&quot; fields.'.format(
                                   message.DESCRIPTOR.full_name, name))
            names.append(name)
            value = js[name]
            # Check no other oneof field is parsed.
            if field.containing_oneof is not None and value is not None:
              oneof_name = field.containing_oneof.name
              if oneof_name in names:
                raise ParseError('Message type &quot;{0}&quot; should not have multiple '
                                 '&quot;{1}&quot; oneof fields.'.format(
                                     message.DESCRIPTOR.full_name, oneof_name))
              names.append(oneof_name)
      
            if value is None:
              if (field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE
                  and field.message_type.full_name == 'google.protobuf.Value'):
                sub_message = getattr(message, field.name)
                sub_message.null_value = 0
              elif (field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_ENUM
                    and field.enum_type.full_name == 'google.protobuf.NullValue'):
                setattr(message, field.name, 0)
              else:
                message.ClearField(field.name)
              continue
      
            # Parse field value.
            if _IsMapEntry(field):
              message.ClearField(field.name)
              self._ConvertMapFieldValue(value, message, field)
            elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
  &gt;           message.ClearField(field.name)
  E           TypeError: descriptor 'ClearField' for 'google.protobuf.pyext._message.CMessage' objects doesn't apply to a 'str' object
  
  C:\installs\anaconda\envs\eunrg_elexeon_protobufs\lib\site-packages\google\protobuf\json_format.py:561: TypeError
  
  During handling of the above exception, another exception occurred:
  
      def test3():
          msg0=MsgGrpType.MsgType(subject=&quot;test_subject0&quot;)
          msg1=MsgGrpType.MsgType(subject=&quot;test_subject1&quot;)
          msg2=MsgGrpType.MsgType(subject=&quot;test_subject3&quot;)
          msgGrp = MsgGrpType(flow=&quot;BOALF&quot;, msg=[msg0,msg1,msg2], pub_ts=datetime.datetime.now().isoformat())
      
          msgDict = google.protobuf.json_format.MessageToDict(msgGrp)
          pprint.pprint(msgDict)
  &gt;       result = ParseDict(msgDict, MsgGrpType, ignore_unknown_fields=True) # Crashes
  
  test_boalf.py:52: 
  _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
  C:\installs\anaconda\envs\eunrg_elexeon_protobufs\lib\site-packages\google\protobuf\json_format.py:454: in ParseDict
      parser.ConvertMessage(js_dict, message)
  C:\installs\anaconda\envs\eunrg_elexeon_protobufs\lib\site-packages\google\protobuf\json_format.py:485: in ConvertMessage
      self._ConvertFieldValuePair(value, message)
  _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
  
  self = &lt;google.protobuf.json_format._Parser object at 0x0000020177A3F2E0&gt;
  js = {'flow': 'BOALF', 'msg': [{'subject': 'test_subject0'}, {'subject': 'test_subject1'}, {'subject': 'test_subject3'}], 'pubTs': '2021-07-19T13:18:40.263824'}
  message = &lt;class 'com_elexeon_boalf_pb2.MsgGrpType'&gt;
  
      def _ConvertFieldValuePair(self, js, message):
        &quot;&quot;&quot;Convert field value pairs into regular message.
      
        Args:
          js: A JSON object to convert the field value pairs.
          message: A regular protocol message to record the data.
      
        Raises:
          ParseError: In case of problems converting.
        &quot;&quot;&quot;
        names = []
        message_descriptor = message.DESCRIPTOR
        fields_by_json_name = dict((f.json_name, f)
                                   for f in message_descriptor.fields)
        for name in js:
          try:
            field = fields_by_json_name.get(name, None)
            if not field:
              field = message_descriptor.fields_by_name.get(name, None)
            if not field and _VALID_EXTENSION_NAME.match(name):
              if not message_descriptor.is_extendable:
                raise ParseError('Message type {0} does not have extensions'.format(
                    message_descriptor.full_name))
              identifier = name[1:-1]  # strip [] brackets
              # pylint: disable=protected-access
              field = message.Extensions._FindExtensionByName(identifier)
              # pylint: enable=protected-access
              if not field:
                # Try looking for extension by the message type name, dropping the
                # field name following the final . separator in full_name.
                identifier = '.'.join(identifier.split('.')[:-1])
                # pylint: disable=protected-access
                field = message.Extensions._FindExtensionByName(identifier)
                # pylint: enable=protected-access
            if not field:
              if self.ignore_unknown_fields:
                continue
              raise ParseError(
                  ('Message type &quot;{0}&quot; has no field named &quot;{1}&quot;.\n'
                   ' Available Fields(except extensions): {2}').format(
                       message_descriptor.full_name, name,
                       [f.json_name for f in message_descriptor.fields]))
            if name in names:
              raise ParseError('Message type &quot;{0}&quot; should not have multiple '
                               '&quot;{1}&quot; fields.'.format(
                                   message.DESCRIPTOR.full_name, name))
            names.append(name)
            value = js[name]
            # Check no other oneof field is parsed.
            if field.containing_oneof is not None and value is not None:
              oneof_name = field.containing_oneof.name
              if oneof_name in names:
                raise ParseError('Message type &quot;{0}&quot; should not have multiple '
                                 '&quot;{1}&quot; oneof fields.'.format(
                                     message.DESCRIPTOR.full_name, oneof_name))
              names.append(oneof_name)
      
            if value is None:
              if (field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE
                  and field.message_type.full_name == 'google.protobuf.Value'):
                sub_message = getattr(message, field.name)
                sub_message.null_value = 0
              elif (field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_ENUM
                    and field.enum_type.full_name == 'google.protobuf.NullValue'):
                setattr(message, field.name, 0)
              else:
                message.ClearField(field.name)
              continue
      
            # Parse field value.
            if _IsMapEntry(field):
              message.ClearField(field.name)
              self._ConvertMapFieldValue(value, message, field)
            elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
              message.ClearField(field.name)
              if not isinstance(value, list):
                raise ParseError('repeated field {0} must be in [] which is '
                                 '{1}.'.format(name, value))
              if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
                # Repeated message field.
                for item in value:
                  sub_message = getattr(message, field.name).add()
                  # None is a null_value in Value.
                  if (item is None and
                      sub_message.DESCRIPTOR.full_name != 'google.protobuf.Value'):
                    raise ParseError('null is not allowed to be used as an element'
                                     ' in a repeated field.')
                  self.ConvertMessage(item, sub_message)
              else:
                # Repeated scalar field.
                for item in value:
                  if item is None:
                    raise ParseError('null is not allowed to be used as an element'
                                     ' in a repeated field.')
                  getattr(message, field.name).append(
                      _ConvertScalarFieldValue(item, field))
            elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
              if field.is_extension:
                sub_message = message.Extensions[field]
              else:
                sub_message = getattr(message, field.name)
              sub_message.SetInParent()
              self.ConvertMessage(value, sub_message)
            else:
              if field.is_extension:
                message.Extensions[field] = _ConvertScalarFieldValue(value, field)
              else:
                setattr(message, field.name, _ConvertScalarFieldValue(value, field))
          except ParseError as e:
            if field and field.containing_oneof is None:
              raise ParseError('Failed to parse {0} field: {1}.'.format(name, e))
            else:
              raise ParseError(str(e))
          except ValueError as e:
            raise ParseError('Failed to parse {0} field: {1}.'.format(name, e))
          except TypeError as e:
  &gt;         raise ParseError('Failed to parse {0} field: {1}.'.format(name, e))
  E         google.protobuf.json_format.ParseError: Failed to parse msg field: descriptor 'ClearField' for 'google.protobuf.pyext._message.CMessage' objects doesn't apply to a 'str' object.
  </code></pre>
  <p>Here's my .proto file:</p>
  <pre class="lang-proto prettyprint-override"><code>// com_elexeon_boalf.proto at 0:0
  syntax = &quot;proto3&quot;;
  package com.elexeon.boalf;
  
  message MsgGrpType {
    string pub_ts = 1;
    string flow = 2;
    repeated MsgType msg = 3;
  
    message MsgType {
      string subject = 1;
      int32 n_k = 2;
      string s_o = 3;
      string p_f = 4;
      string t_a = 5;
      string a_d = 6;
      int32 n_p = 7;
      repeated RowType row = 8;
  
      message RowType {
        string t_s = 1;
        double v_a = 2;
      }
    }
  }
  </code></pre>