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

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
Links to the raise (1)
https://github.com/protocolbuffers/protobuf/blob/96ccf402fe8e62649f2be48a05944d552701aa5f/python/google/protobuf/internal/python_message.py#L1314Ways to fix
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"
}