fix Python bug with required fields
https://github.com/protocolbuffers/upb/issues/1220
There were two bugs here: Python was incorrectly mandating that a required
field be set during assignment, and it was also incorrectly assuming a non-NULL
return from an internal function call.
PiperOrigin-RevId: 518561818
diff --git a/python/message.c b/python/message.c
index 6bd3941..753cc74 100644
--- a/python/message.c
+++ b/python/message.c
@@ -447,6 +447,8 @@
return ok;
}
+static PyObject* PyUpb_Message_MergePartialFrom(PyObject*, PyObject*);
+
static bool PyUpb_Message_InitMessageAttribute(PyObject* _self, PyObject* name,
PyObject* value) {
PyObject* submsg = PyUpb_Message_GetAttr(_self, name);
@@ -454,9 +456,9 @@
assert(!PyErr_Occurred());
bool ok;
if (PyUpb_Message_TryCheck(value)) {
- PyObject* tmp = PyUpb_Message_MergeFrom(submsg, value);
+ PyObject* tmp = PyUpb_Message_MergePartialFrom(submsg, value);
ok = tmp != NULL;
- Py_DECREF(tmp);
+ Py_XDECREF(tmp);
} else if (PyDict_Check(value)) {
assert(!PyErr_Occurred());
ok = PyUpb_Message_InitAttributes(submsg, NULL, value) >= 0;
@@ -1184,7 +1186,8 @@
return NULL;
}
-PyObject* PyUpb_Message_MergeFrom(PyObject* self, PyObject* arg) {
+static PyObject* PyUpb_Message_MergeInternal(PyObject* self, PyObject* arg,
+ bool check_required) {
if (self->ob_type != arg->ob_type) {
PyErr_Format(PyExc_TypeError,
"Parameter to MergeFrom() must be instance of same class: "
@@ -1194,7 +1197,10 @@
}
// OPT: exit if src is empty.
PyObject* subargs = PyTuple_New(0);
- PyObject* serialized = PyUpb_Message_SerializeToString(arg, subargs, NULL);
+ PyObject* serialized =
+ check_required
+ ? PyUpb_Message_SerializeToString(arg, subargs, NULL)
+ : PyUpb_Message_SerializePartialToString(arg, subargs, NULL);
Py_DECREF(subargs);
if (!serialized) return NULL;
PyObject* ret = PyUpb_Message_MergeFromString(self, serialized);
@@ -1203,6 +1209,14 @@
Py_RETURN_NONE;
}
+PyObject* PyUpb_Message_MergeFrom(PyObject* self, PyObject* arg) {
+ return PyUpb_Message_MergeInternal(self, arg, true);
+}
+
+static PyObject* PyUpb_Message_MergePartialFrom(PyObject* self, PyObject* arg) {
+ return PyUpb_Message_MergeInternal(self, arg, false);
+}
+
static PyObject* PyUpb_Message_SetInParent(PyObject* _self, PyObject* arg) {
PyUpb_Message* self = (void*)_self;
PyUpb_Message_EnsureReified(self);
diff --git a/python/message.h b/python/message.h
index f10f15f..2bb075b 100644
--- a/python/message.h
+++ b/python/message.h
@@ -64,6 +64,8 @@
PyObject* PyUpb_Message_MergeFromString(PyObject* self, PyObject* arg);
PyObject* PyUpb_Message_SerializeToString(PyObject* self, PyObject* args,
PyObject* kwargs);
+PyObject* PyUpb_Message_SerializePartialToString(PyObject* self, PyObject* args,
+ PyObject* kwargs);
// Sets fields of the message according to the attribuges in `kwargs`.
int PyUpb_Message_InitAttributes(PyObject* _self, PyObject* args,