votes up 5

Parameter to MergeFrom() must be instance of same class: expected %s got %s.

Package:
Exception Class:
TypeError

Raise code

AddMergeFromMethod(cls):
  LABEL_REPEATED = _FieldDescriptor.LABEL_REPEATED
  CPPTYPE_MESSAGE = _FieldDescriptor.CPPTYPE_MESSAGE

  def MergeFrom(self, msg):
    if not isinstance(msg, cls):
      raise TypeError(
          'Parameter to MergeFrom() must be instance of same class: '
          'expected %s got %s.' % (cls.__name__, msg.__class__.__name__))

    assert msg is not self
    self._Modified()

    fields = self._fields

    f
😲  Walkingbet is Android app that pays you real bitcoins for a walking. Withdrawable real money bonus is available now, hurry up! 🚶

Ways to fix

votes up 3 votes down

Jul 21, 2021 kellemnegasi answer
kellemnegasi 31.6k
votes up 3 votes down

This error is raised when trying to merge a given protobuf (Protocol Buffer) message instance into another instance.

To understand the nature and the source of this error, let's see what protobufs are.

What are Protocol Buffers:

Protocol Buffers are a way to encode data before transportation, which efficiently shrinks data blocks and therefore increases speed when sending it. It abstracts data into a language- and platform-neutral format.

To use Protocol Buffers in python

  • Definine Message Type
  • Save the message type to a file with .proto extension
  • compile the .proto file using the command

protoc -I=$SRC_DIR --python_out=$DST_DIR $SRC_DIR/addressbook.proto

"""
-I: defines the directory where we search for any dependencies (we use . which is the current directory)
--python_out: defines the location we want to generate a Python integration class in (again we use . which is the current directory)
The last unnamed parameter defines the .proto file that will be compiled (we use the todolist.proto file in the current directory)
"""

The above protoc command generates a new Python file named <name_of_proto_file>_pb2.py.

Finally we can work with the defined message class by importing this generated python file to our code.

Reproducing the error:

apt install -y protobuf-compiler

mkdir prot-test

pipenv shell

  • Write a sample protobuf messange

Here we are going to write a protobuf message and save it as .proto file. In our case we gonna name this file sample_file.proto .

Let's write the following content inside the sample_file.proto.

syntax = "proto3";
package protosample;
enum TaskState {
    TASK_OPEN = 0;
    TASK_IN_PROGRESS = 1;
    TASK_POST_PONED = 2;
    TASK_CLOSED = 3;
    TASK_DONE = 4;
}

message TodoList {
    int32 owner_id = 1;
    string owner_name = 2;

    message ListItems {
        TaskState state = 1;
        string task = 2;
        string due_date = 3;
    }

    repeated ListItems todos = 3;
}


message Person {
  string name = 1;
  int32 id = 2;
  string email = 3;

  enum PhoneType {
    MOBILE = 0;
    HOME = 1;
    WORK = 2;
  }

  message PhoneNumber {
    string number = 1;
    PhoneType type = 2;
  }

  repeated PhoneNumber phones = 4;
}

message AddressBook {
  repeated Person people = 1;
}

In the above we have three message types, Person , AddressBook and TodoList with some of them having other nested messages inside them as properties. e.g. The message Person has the message PhoneNumber.

  • Compile the .proto file:

Now let's compile the proto file with the following command.

protoc -I=. --python_out=. ./sample_file.proto

The above command is run from the same directory as the proto file. there for the dot (".") is used to indicate the current directory. This command genrates a python file with name sample_file_pb2.py . This is the file that we have to import into our sample code to test and reproduce the error.

  • Write the code that produces the error

# import the compiled protobuf
import sample_file_pb2 as sample_proto 


person = sample_proto.Person() # instansiate the Person class
my_todos = sample_proto.TodoList() # instantiate the TodoList class


# populate the Person object with properties
my_todos.owner_id = 1234
my_todos.owner_name = "owners_name"
first_item = my_todos.todos.add()
first_item.state = sample_proto.TaskState.Value("TASK_IN_PROGRESS")
first_item.task = "reproduce the protobuf MergeFrom error"
first_item.due_date = "21.07.2021"




# populate the Person object with the defined properties
person.id = 1234
person.name = "John Doe"
person.email = "[email protected]"
phone = person.phones.add()
phone.number = "555-4321"
phone.type = sample_proto.Person.HOME


# now let's try to merge the person object to my_todos object
my_todos.MergeFrom(person)
print(my_todos)

let's save this code in test proto_code.py and finally let's run the code using the command.

python test_proto_code.py

The output error:

Traceback (most recent call last):
 File "test_proto_code.py", line 34, in <module>
   my_todos.MergeFrom(person)
TypeError: Parameter to MergeFrom() must be instance of same class: expected protosample.TodoList got protosample.Person.

How to Fix it

The cause of the error is we tried to merge an instance of Person class to the instance of TodoList.

Only instances of the same object can be merged.

# import the compiled protobuf
import sample_file_pb2 as sample_proto 

person = sample_proto.Person() # instansiate the Person class
my_todos = sample_proto.TodoList() # instantiate the TodoList class


# populate the Person object with properties
my_todos.owner_id = 1234
my_todos.owner_name = "owners_name"
first_item = my_todos.todos.add()
first_item.state = sample_proto.TaskState.Value("TASK_IN_PROGRESS")
first_item.task = "reproduce the protobuf MergeFrom error"
first_item.due_date = "21.07.2021"


# let's instantiate antoher object of TodoList and populate it
another_todos = sample_proto.TodoList()
my_todos.owner_id = 1235
my_todos.owner_name = "owners_name"
second_item = my_todos.todos.add()
second_item.state = sample_proto.TaskState.Value("TASK_DONE")
second_item.task = "read on python documentation of protobuf"



# now let's try to merge the second object to the first TodoList object 
my_todos.MergeFrom(another_todos)
print(my_todos)

Output:

A merge of the two objects containing all properties together.

owner_id: 1235
owner_name: "owners_name"
todos {
  state: TASK_IN_PROGRESS
  task: "reproduce the protobuf MergeFrom error"
  due_date: "21.07.2021"
}
todos {
  state: TASK_DONE
  task: "read on python documentation of protobuf"
}
Jul 21, 2021 kellemnegasi answer
kellemnegasi 31.6k

Add a possible fix

Please authorize to post fix