Addressed PR comments.
diff --git a/python/message.c b/python/message.c
index 87c699d..3d5c9ba 100644
--- a/python/message.c
+++ b/python/message.c
@@ -67,6 +67,13 @@
PyUpb_CPythonBits cpython_bits;
static bool PyUpb_CPythonBits_Init(PyUpb_CPythonBits* bits) {
+ PyObject* bases = NULL;
+ PyTypeObject* type = NULL;
+ PyObject* size = NULL;
+ PyObject* sys = NULL;
+ PyObject* hex_version = NULL;
+ bool ret = false;
+
// PyType_GetSlot() only works on heap types, so we cannot use it on
// &PyType_Type directly. Instead we create our own (temporary) type derived
// from PyType_Type: this will inherit all of the slots from PyType_Type, but
@@ -81,21 +88,19 @@
dummy_slots,
};
- PyObject* bases = Py_BuildValue("(O)", &PyType_Type);
- if (!bases) return false;
- PyObject* type = PyType_FromSpecWithBases(&dummy_spec, bases);
- if (!type) return false;
- Py_DECREF(bases);
+ bases = Py_BuildValue("(O)", &PyType_Type);
+ if (!bases) goto err;
+ type = (PyTypeObject*)PyType_FromSpecWithBases(&dummy_spec, bases);
+ if (!type) goto err;
- bits->type_new = PyType_GetSlot((PyTypeObject*)type, Py_tp_new);
- bits->type_getattro = PyType_GetSlot((PyTypeObject*)type, Py_tp_getattro);
- bits->type_setattro = PyType_GetSlot((PyTypeObject*)type, Py_tp_setattro);
- Py_DECREF(type);
+ bits->type_new = PyType_GetSlot(type, Py_tp_new);
+ bits->type_getattro = PyType_GetSlot(type, Py_tp_getattro);
+ bits->type_setattro = PyType_GetSlot(type, Py_tp_setattro);
- PyObject* size =
- PyObject_GetAttrString((PyObject*)&PyType_Type, "__basicsize__");
+ size = PyObject_GetAttrString((PyObject*)&PyType_Type, "__basicsize__");
+ if (!size) goto err;
bits->type_basicsize = PyLong_AsLong(size);
- Py_DECREF(size);
+ if (bits->type_basicsize == -1) goto err;
assert(bits->type_new && bits->type_getattro && bits->type_setattro);
@@ -106,12 +111,17 @@
assert(bits->type_basicsize == sizeof(PyHeapTypeObject));
#endif
- PyObject* sys = PyImport_ImportModule("sys");
- PyObject* hex_version = PyObject_GetAttrString(sys, "hexversion");
+ sys = PyImport_ImportModule("sys");
+ hex_version = PyObject_GetAttrString(sys, "hexversion");
bits->python_version_hex = PyLong_AsLong(hex_version);
- Py_DECREF(hex_version);
- Py_DECREF(sys);
+ ret = true;
+err:
+ Py_XDECREF(bases);
+ Py_XDECREF(type);
+ Py_XDECREF(size);
+ Py_XDECREF(sys);
+ Py_XDECREF(hex_version);
return true;
}
@@ -193,7 +203,7 @@
}
upb_msg* PyUpb_CMessage_GetIfWritable(PyObject* _self) {
- PyUpb_CMessage* self = (PyUpb_CMessage*)_self;
+ PyUpb_CMessage* self = (void*)_self;
return PyUpb_CMessage_IsUnset(self) ? NULL : self->msg;
}
@@ -217,8 +227,8 @@
* PyUpb_CMessage_LookupName()
*
* Tries to find a field or oneof named `py_name` in the message object `self`.
- * The user can pass `f` and/or `o` to indicate whether a field or a oneof name
- * is expected. If the name is found and is has an expected type, the function
+ * The user must pass `f` and/or `o` to indicate whether a field or a oneof name
+ * is expected. If the name is found and it has an expected type, the function
* sets `*f` or `*o` respectively and returns true. Otherwise returns false
* and sets an exception of type `exc_type` if provided.
*/
@@ -226,6 +236,7 @@
const upb_fielddef** f,
const upb_oneofdef** o,
PyObject* exc_type) {
+ assert(f || o);
Py_ssize_t size;
const char* name = PyUnicode_AsUTF8AndSize(py_name, &size);
if (!name) return NULL;
@@ -238,13 +249,17 @@
upb_msgdef_fullname(msgdef), name);
}
return false;
- } else if (!o && !*f) {
+ }
+
+ if (!o && !*f) {
if (exc_type) {
PyErr_Format(exc_type, "Expected a field name, but got oneof name %s.",
name);
}
return false;
- } else if (!f && !*o) {
+ }
+
+ if (!f && !*o) {
if (exc_type) {
PyErr_Format(exc_type, "Expected a oneof name, but got field name %s.",
name);
@@ -258,8 +273,8 @@
static bool PyUpb_CMessage_InitMessageMapEntry(PyObject* dst, PyObject* src) {
if (!src || !dst) return false;
- // Currently we are doing Clear()+MergeFrom(). Replace with CopyFrom() once that
- // is implemented.
+ // TODO(haberman): Currently we are doing Clear()+MergeFrom(). Replace with
+ // CopyFrom() once that is implemented.
PyObject* ok = PyObject_CallMethod(dst, "Clear", NULL);
if (!ok) return false;
Py_DECREF(ok);
@@ -274,12 +289,15 @@
const upb_fielddef* f) {
const upb_msgdef* entry_m = upb_fielddef_msgsubdef(f);
const upb_fielddef* val_f = upb_msgdef_field(entry_m, 1);
+ PyObject* iter = NULL;
+ PyObject* tmp = NULL;
+ int ret = -1;
if (upb_fielddef_issubmsg(val_f)) {
PyObject* iter = PyObject_GetIter(value);
if (iter == NULL) {
PyErr_Format(PyExc_TypeError, "Argument for field %s is not iterable",
upb_fielddef_fullname(f));
- return -1;
+ goto err;
}
PyObject* item;
while ((item = PyIter_Next(iter)) != NULL) {
@@ -289,22 +307,76 @@
bool ok = PyUpb_CMessage_InitMessageMapEntry(dst, src);
Py_XDECREF(src);
Py_XDECREF(dst);
- if (!ok) {
- Py_DECREF(iter);
- return -1;
- }
+ if (!ok) goto err;
}
Py_DECREF(iter);
} else {
PyObject* tmp = PyObject_CallMethod(map, "update", "O", value);
- if (!tmp) return -1;
- Py_DECREF(tmp);
+ if (!tmp) goto err;
}
- return 0;
+ ret = 0;
+
+err:
+ Py_XDECREF(iter);
+ Py_XDECREF(tmp);
+ return ret;
}
void PyUpb_CMessage_AssureWritable(PyUpb_CMessage* self);
+static bool PyUpb_CMessage_InitMapAttribute(PyObject* _self, PyObject* name,
+ const upb_fielddef* f,
+ PyObject* value) {
+ PyObject* map = PyUpb_CMessage_GetAttr(_self, name);
+ int ok = PyUpb_CMessage_InitMapAttributes(map, value, f);
+ Py_DECREF(map);
+ return ok >= 0;
+}
+
+static bool PyUpb_CMessage_InitRepeatedAttribute() {
+ // TODO(haberman): disabled until repeated container is in.
+ // PyObject* repeated = PyUpb_CMessage_GetAttr(_self, name);
+ // PyObject* tmp = PyUpb_RepeatedContainer_Extend(repeated, value);
+ // if (!tmp) return -1;
+ // Py_DECREF(tmp);
+ PyErr_SetString(PyExc_NotImplementedError, "repeated init");
+ return false;
+}
+
+static bool PyUpb_CMessage_InitMessageAttribute(PyObject* _self, PyObject* name,
+ PyObject* value) {
+ PyObject* submsg = PyUpb_CMessage_GetAttr(_self, name);
+ if (!submsg) return -1;
+ assert(!PyErr_Occurred());
+ bool ok;
+ if (PyUpb_CMessage_TryCheck(value)) {
+ PyObject* tmp = PyUpb_CMessage_MergeFrom(submsg, value);
+ ok = tmp != NULL;
+ Py_DECREF(tmp);
+ } else {
+ assert(!PyErr_Occurred());
+ ok = PyUpb_CMessage_InitAttributes(submsg, NULL, value) >= 0;
+ }
+ Py_DECREF(submsg);
+ return ok;
+}
+
+static bool PyUpb_CMessage_InitScalarAttribute(upb_msg* msg,
+ const upb_fielddef* f,
+ PyObject* value,
+ upb_arena* arena) {
+ upb_msgval msgval;
+ assert(!PyErr_Occurred());
+ if (!PyUpb_PyToUpb(value, f, &msgval, arena)) {
+ PyErr_Clear();
+ PyErr_Format(PyExc_ValueError, "Error initializing field %s",
+ upb_fielddef_fullname(f));
+ return false;
+ }
+ upb_msg_set(msg, f, msgval, arena);
+ return true;
+}
+
int PyUpb_CMessage_InitAttributes(PyObject* _self, PyObject* args,
PyObject* kwargs) {
assert(!PyErr_Occurred());
@@ -316,7 +388,7 @@
if (kwargs == NULL) return 0;
- PyUpb_CMessage* self = (PyUpb_CMessage*)_self;
+ PyUpb_CMessage* self = (void*)_self;
Py_ssize_t pos = 0;
PyObject* name;
PyObject* value;
@@ -337,43 +409,13 @@
assert(!PyErr_Occurred());
if (upb_fielddef_ismap(f)) {
- PyObject* map = PyUpb_CMessage_GetAttr(_self, name);
- int ok = PyUpb_CMessage_InitMapAttributes(map, value, f);
- Py_DECREF(map);
- if (ok < 0) return -1;
+ if (!PyUpb_CMessage_InitMapAttribute(_self, name, f, value)) return -1;
} else if (upb_fielddef_isseq(f)) {
- // TODO(haberman): disabled until repeated container is in.
- // PyObject* repeated = PyUpb_CMessage_GetAttr(_self, name);
- // PyObject* tmp = PyUpb_RepeatedContainer_Extend(repeated, value);
- // if (!tmp) return -1;
- // Py_DECREF(tmp);
- PyErr_SetString(PyExc_NotImplementedError, "repeated init");
- return -1;
+ if (!PyUpb_CMessage_InitRepeatedAttribute()) return -1;
} else if (upb_fielddef_issubmsg(f)) {
- PyObject* submsg = PyUpb_CMessage_GetAttr(_self, name);
- if (!submsg) return -1;
- assert(!PyErr_Occurred());
- bool ok;
- if (PyUpb_CMessage_TryCheck(value)) {
- PyObject* tmp = PyUpb_CMessage_MergeFrom(submsg, value);
- ok = tmp != NULL;
- Py_DECREF(tmp);
- } else {
- assert(!PyErr_Occurred());
- ok = PyUpb_CMessage_InitAttributes(submsg, NULL, value) >= 0;
- }
- Py_DECREF(submsg);
- if (!ok) return -1;
+ if (!PyUpb_CMessage_InitMessageAttribute(_self, name, value)) return -1;
} else {
- upb_msgval msgval;
- assert(!PyErr_Occurred());
- if (!PyUpb_PyToUpb(value, f, &msgval, arena)) {
- PyErr_Clear();
- PyErr_Format(PyExc_ValueError, "Error initializing field %s",
- upb_fielddef_fullname(f));
- return -1;
- }
- upb_msg_set(msg, f, msgval, arena);
+ if (!PyUpb_CMessage_InitScalarAttribute(msg, f, value, arena)) return -1;
}
if (PyErr_Occurred()) return -1;
}
@@ -414,17 +456,18 @@
}
static bool PyUpb_CMessage_IsEqual(PyUpb_CMessage* m1, PyObject* _m2) {
- PyUpb_CMessage* m2 = (PyUpb_CMessage*)_m2;
+ PyUpb_CMessage* m2 = (void*)_m2;
if (m1 == m2) return true;
if (!PyObject_TypeCheck(_m2, m1->ob_base.ob_type)) {
return false;
}
const upb_msgdef* m1_msgdef = _PyUpb_CMessage_GetMsgdef(m1);
+#ifndef NDEBUG
const upb_msgdef* m2_msgdef = _PyUpb_CMessage_GetMsgdef(m2);
+ assert(m1_msgdef == m2_msgdef);
+#endif
const upb_msg* m1_msg = PyUpb_CMessage_GetIfWritable((PyObject*)m1);
const upb_msg* m2_msg = PyUpb_CMessage_GetIfWritable(_m2);
- (void)m2_msgdef;
- assert(m1_msgdef == m2_msgdef);
return PyUpb_Message_IsEqual(m1_msg, m2_msg, m1_msgdef);
}
@@ -484,6 +527,25 @@
self->version++;
}
+static void PyUpb_CMessage_SyncSubobjs(PyUpb_CMessage* self);
+
+/*
+ * PyUpb_CMessage_SwitchToSet()
+ *
+ * The message equivalent of PyUpb_*Container_SwitchToSet(), this transitions
+ * the wrapper from the unset state (owning a reference on self->parent) to the
+ * set state (having a non-owning pointer to self->msg).
+ */
+static void PyUpb_CMessage_SwitchToSet(PyUpb_CMessage* self,
+ const upb_fielddef* f, upb_msg* msg) {
+ assert(f == PyUpb_CMessage_GetFieldDef(self));
+ PyUpb_ObjCache_Add(msg, &self->ob_base);
+ Py_DECREF(&self->parent->ob_base);
+ self->msg = msg; // Overwrites self->parent
+ self->def = (uintptr_t)upb_fielddef_msgsubdef(f);
+ PyUpb_CMessage_SyncSubobjs(self);
+}
+
/*
* PyUpb_CMessage_SyncSubobjs()
*
@@ -498,17 +560,24 @@
* # SyncSubobjs() is required to connect our existing 'sub' wrapper to the
* # newly created foo.submsg data in C.
* foo.MergeFrom(FooMessage(submsg={}))
+ *
+ * This requires that all of the new sub-objects that have appeared are owned
+ * by `self`'s arena.
*/
static void PyUpb_CMessage_SyncSubobjs(PyUpb_CMessage* self) {
PyUpb_WeakMap* subobj_map = self->unset_subobj_map;
+ if (!subobj_map) return;
+
upb_msg* msg = PyUpb_CMessage_GetMsg(self);
intptr_t iter = PYUPB_WEAKMAP_BEGIN;
const void* key;
PyObject* obj;
- if (!subobj_map) return;
-
// The last ref to this message could disappear during iteration.
+ // When we call PyUpb_*Container_SwitchToSet() below, the container will drop
+ // its ref on `self`. If that was the last ref on self, the object will be
+ // deleted, and `subobj_map` along with it. We need it to live until we are
+ // done iterating.
Py_INCREF(&self->ob_base);
while (PyUpb_WeakMap_Next(subobj_map, &key, &obj, &iter)) {
@@ -525,14 +594,9 @@
// TODO(haberman): re-enable when repeated fields are checked in.
// PyUpb_RepeatedContainer_SwitchToSet(obj, (upb_array*)msgval.array_val);
} else {
- PyUpb_CMessage* sub = (PyUpb_CMessage*)obj;
- PyUpb_ObjCache_Add(msgval.msg_val, obj);
+ PyUpb_CMessage* sub = (void*)obj;
assert(self == sub->parent);
- assert(f == PyUpb_CMessage_GetFieldDef(sub));
- Py_DECREF((PyObject*)self);
- sub->msg = (upb_msg*)msgval.msg_val;
- sub->def = (uintptr_t)upb_fielddef_msgsubdef(f);
- PyUpb_CMessage_SyncSubobjs(sub);
+ PyUpb_CMessage_SwitchToSet(sub, f, (upb_msg*)msgval.msg_val);
}
}
@@ -567,30 +631,31 @@
static PyObject* PyUpb_CMessage_RichCompare(PyObject* _self, PyObject* other,
int opid) {
- PyUpb_CMessage* self = (PyUpb_CMessage*)_self;
+ PyUpb_CMessage* self = (void*)_self;
if (opid != Py_EQ && opid != Py_NE) {
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
- bool ret = (opid == Py_EQ) == PyUpb_CMessage_IsEqual(self, other);
+ bool ret = PyUpb_CMessage_IsEqual(self, other);
+ if (opid == Py_NE) ret = !ret;
return PyBool_FromLong(ret);
}
void PyUpb_CMessage_CacheDelete(PyObject* _self, const upb_fielddef* f) {
- PyUpb_CMessage* self = (PyUpb_CMessage*)_self;
+ PyUpb_CMessage* self = (void*)_self;
PyUpb_WeakMap_Delete(self->unset_subobj_map, f);
}
void PyUpb_CMessage_SetConcreteSubobj(PyObject* _self, const upb_fielddef* f,
upb_msgval subobj) {
- PyUpb_CMessage* self = (PyUpb_CMessage*)_self;
+ PyUpb_CMessage* self = (void*)_self;
PyUpb_CMessage_AssureWritable(self);
PyUpb_CMessage_CacheDelete(_self, f);
upb_msg_set(self->msg, f, subobj, PyUpb_Arena_Get(self->arena));
}
static void PyUpb_CMessage_Dealloc(PyObject* _self) {
- PyUpb_CMessage* self = (PyUpb_CMessage*)_self;
+ PyUpb_CMessage* self = (void*)_self;
if (PyUpb_CMessage_IsUnset(self)) {
PyUpb_CMessage_CacheDelete((PyObject*)self->parent,
@@ -622,25 +687,87 @@
PyObject* PyUpb_CMessage_Get(upb_msg* u_msg, const upb_msgdef* m,
PyObject* arena) {
PyObject* ret = PyUpb_ObjCache_Get(u_msg);
+ if (ret) return ret;
- if (!ret) {
- PyObject* cls = PyUpb_Descriptor_GetClass(m);
- // It is not safe to use PyObject_{,GC}_New() due to:
- // https://bugs.python.org/issue35810
- PyUpb_CMessage* py_msg = (void*)PyType_GenericAlloc((PyTypeObject*)cls, 0);
- py_msg->arena = arena;
- py_msg->def = (uintptr_t)m;
- py_msg->msg = u_msg;
- py_msg->unset_subobj_map = NULL;
- py_msg->ext_dict = NULL;
- py_msg->version = 0;
- ret = &py_msg->ob_base;
- Py_DECREF(cls);
- Py_INCREF(arena);
- PyUpb_ObjCache_Add(u_msg, ret);
+ PyObject* cls = PyUpb_Descriptor_GetClass(m);
+ // It is not safe to use PyObject_{,GC}_New() due to:
+ // https://bugs.python.org/issue35810
+ PyUpb_CMessage* py_msg = (void*)PyType_GenericAlloc((PyTypeObject*)cls, 0);
+ py_msg->arena = arena;
+ py_msg->def = (uintptr_t)m;
+ py_msg->msg = u_msg;
+ py_msg->unset_subobj_map = NULL;
+ py_msg->ext_dict = NULL;
+ py_msg->version = 0;
+ ret = &py_msg->ob_base;
+ Py_DECREF(cls);
+ Py_INCREF(arena);
+ PyUpb_ObjCache_Add(u_msg, ret);
+ return ret;
+}
+
+PyObject* PyUpb_CMessage_GetUnsetWrapper(PyUpb_CMessage* self,
+ const upb_fielddef* field) {
+ // Non-present messages return magical "empty" messages that point to their
+ // parent, but will materialize into real messages if any fields are
+ // assigned.
+ if (!self->unset_subobj_map) {
+ self->unset_subobj_map = PyUpb_WeakMap_New();
+ }
+ PyObject* subobj = PyUpb_WeakMap_Get(self->unset_subobj_map, field);
+
+ if (!subobj) {
+ if (upb_fielddef_ismap(field)) {
+ // TODO(haberman): re-enable when maps are checked in.
+ // subobj = PyUpb_MapContainer_NewUnset(_self, field, self->arena);
+ PyErr_SetString(PyExc_NotImplementedError, "unset map");
+ return NULL;
+ } else if (upb_fielddef_isseq(field)) {
+ // TODO(haberman): re-enable when repeated fields are checked in.
+ // subobj = PyUpb_RepeatedContainer_NewUnset(_self, field, self->arena);
+ PyErr_SetString(PyExc_NotImplementedError, "unset repeated");
+ return NULL;
+ } else {
+ subobj = PyUpb_CMessage_NewUnset(&self->ob_base, field, self->arena);
+ }
+ PyUpb_WeakMap_Add(self->unset_subobj_map, field, subobj);
}
- return ret;
+ assert(!PyErr_Occurred());
+ return subobj;
+}
+
+PyObject* PyUpb_CMessage_GetPresentWrapper(PyUpb_CMessage* self,
+ const upb_fielddef* field) {
+ assert(!PyUpb_CMessage_IsUnset(self));
+ upb_mutmsgval mutval =
+ upb_msg_mutable(self->msg, field, PyUpb_Arena_Get(self->arena));
+ if (upb_fielddef_ismap(field)) {
+ // TODO(haberman): re-enable when maps are checked in.
+ // return PyUpb_MapContainer_GetOrCreateWrapper(mutval.map, field,
+ // self->arena);
+ (void)mutval;
+ PyErr_SetString(PyExc_NotImplementedError, "access map");
+ return NULL;
+ } else {
+ // TODO(haberman): re-enable when repeated fields are checked in.
+ // return PyUpb_RepeatedContainer_GetOrCreateWrapper(mutval.array, _self,
+ // field, self->arena);
+ PyErr_SetString(PyExc_NotImplementedError, "access repeated");
+ return NULL;
+ }
+}
+
+PyObject* PyUpb_CMessage_GetScalarValue(PyUpb_CMessage* self,
+ const upb_fielddef* field) {
+ upb_msgval val;
+ if (PyUpb_CMessage_IsUnset(self)) {
+ // Unset message always returns default values.
+ val = upb_fielddef_default(field);
+ } else {
+ val = upb_msg_get(self->msg, field);
+ }
+ return PyUpb_UpbToPy(val, field, self->arena);
}
/*
@@ -656,75 +783,24 @@
*/
PyObject* PyUpb_CMessage_GetFieldValue(PyObject* _self,
const upb_fielddef* field) {
- PyUpb_CMessage* self = (PyUpb_CMessage*)_self;
+ PyUpb_CMessage* self = (void*)_self;
assert(upb_fielddef_containingtype(field) == PyUpb_CMessage_GetMsgdef(_self));
bool submsg = upb_fielddef_issubmsg(field);
bool seq = upb_fielddef_isseq(field);
if ((PyUpb_CMessage_IsUnset(self) && (submsg || seq)) ||
(submsg && !upb_msg_has(self->msg, field))) {
- // Non-present messages return magical "empty" messages that point to their
- // parent, but will materialize into real messages if any fields are
- // assigned.
- if (!self->unset_subobj_map) {
- self->unset_subobj_map = PyUpb_WeakMap_New();
- }
- PyObject* subobj = PyUpb_WeakMap_Get(self->unset_subobj_map, field);
-
- if (!subobj) {
- if (upb_fielddef_ismap(field)) {
- // TODO(haberman): re-enable when maps are checked in.
- // subobj = PyUpb_MapContainer_NewUnset(_self, field, self->arena);
- PyErr_SetString(PyExc_NotImplementedError, "unset map");
- return NULL;
- } else if (seq) {
- // TODO(haberman): re-enable when repeated fields are checked in.
- // subobj = PyUpb_RepeatedContainer_NewUnset(_self, field, self->arena);
- PyErr_SetString(PyExc_NotImplementedError, "unset repeated");
- return NULL;
- } else {
- subobj = PyUpb_CMessage_NewUnset(_self, field, self->arena);
- }
- PyUpb_WeakMap_Add(self->unset_subobj_map, field, subobj);
- }
-
- assert(!PyErr_Occurred());
- return subobj;
- }
-
- if (seq) {
- assert(!PyUpb_CMessage_IsUnset(self));
- upb_mutmsgval mutval =
- upb_msg_mutable(self->msg, field, PyUpb_Arena_Get(self->arena));
- if (upb_fielddef_ismap(field)) {
- // TODO(haberman): re-enable when maps are checked in.
- // return PyUpb_MapContainer_GetOrCreateWrapper(mutval.map, field,
- // self->arena);
- (void)mutval;
- PyErr_SetString(PyExc_NotImplementedError, "access map");
- return NULL;
- } else {
- // TODO(haberman): re-enable when repeated fields are checked in.
- // return PyUpb_RepeatedContainer_GetOrCreateWrapper(mutval.array, _self,
- // field, self->arena);
- PyErr_SetString(PyExc_NotImplementedError, "access repeated");
- return NULL;
- }
+ return PyUpb_CMessage_GetUnsetWrapper(self, field);
+ } else if (seq) {
+ return PyUpb_CMessage_GetPresentWrapper(self, field);
} else {
- upb_msgval val;
- if (PyUpb_CMessage_IsUnset(self)) {
- // Unset message always returns default values.
- val = upb_fielddef_default(field);
- } else {
- val = upb_msg_get(self->msg, field);
- }
- return PyUpb_UpbToPy(val, field, self->arena);
+ return PyUpb_CMessage_GetScalarValue(self, field);
}
}
int PyUpb_CMessage_SetFieldValue(PyObject* _self, const upb_fielddef* field,
PyObject* value) {
- PyUpb_CMessage* self = (PyUpb_CMessage*)_self;
+ PyUpb_CMessage* self = (void*)_self;
if (upb_fielddef_issubmsg(field) || upb_fielddef_isseq(field)) {
PyErr_Format(PyExc_AttributeError,
"Assignment not allowed to message, map, or repeated "
@@ -746,7 +822,7 @@
}
int PyUpb_CMessage_GetVersion(PyObject* _self) {
- PyUpb_CMessage* self = (PyUpb_CMessage*)_self;
+ PyUpb_CMessage* self = (void*)_self;
return self->version;
}
@@ -761,7 +837,7 @@
*/
__attribute__((flatten)) static PyObject* PyUpb_CMessage_GetAttr(
PyObject* _self, PyObject* attr) {
- PyUpb_CMessage* self = (PyUpb_CMessage*)_self;
+ PyUpb_CMessage* self = (void*)_self;
// Lookup field by name.
const upb_fielddef* field;
@@ -772,17 +848,16 @@
// Check base class attributes.
assert(!PyErr_Occurred());
PyObject* ret = PyObject_GenericGetAttr(_self, attr);
+ if (ret) return ret;
- // Return value if found, swallow AttributeError if raised.
- if (ret) {
- return ret;
+ // If the attribute wasn't found, look for attributes on the class. But if a
+ // different kind of error (other than AttributeError) was found, return that.
+ if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+ PyErr_Clear();
+ return PyUpb_MessageMeta_GetAttr((PyObject*)Py_TYPE(_self), attr);
}
- if (!PyErr_ExceptionMatches(PyExc_AttributeError)) {
- return NULL;
- }
- PyErr_Clear();
- return PyUpb_MessageMeta_GetAttr((PyObject*)Py_TYPE(_self), attr);
+ return NULL;
}
/*
@@ -793,7 +868,7 @@
*/
static int PyUpb_CMessage_SetAttr(PyObject* _self, PyObject* attr,
PyObject* value) {
- PyUpb_CMessage* self = (PyUpb_CMessage*)_self;
+ PyUpb_CMessage* self = (void*)_self;
const upb_fielddef* field;
if (!PyUpb_CMessage_LookupName(self, attr, &field, NULL,
PyExc_AttributeError)) {
@@ -804,7 +879,7 @@
}
static PyObject* PyUpb_CMessage_HasField(PyObject* _self, PyObject* arg) {
- PyUpb_CMessage* self = (PyUpb_CMessage*)_self;
+ PyUpb_CMessage* self = (void*)_self;
const upb_fielddef* field;
const upb_oneofdef* oneof;
@@ -866,7 +941,7 @@
}
static PyObject* PyUpb_CMessage_SetInParent(PyObject* _self, PyObject* arg) {
- PyUpb_CMessage* self = (PyUpb_CMessage*)_self;
+ PyUpb_CMessage* self = (void*)_self;
PyUpb_CMessage_AssureWritable(self);
Py_RETURN_NONE;
}
@@ -879,7 +954,7 @@
}
PyObject* PyUpb_CMessage_MergeFromString(PyObject* _self, PyObject* arg) {
- PyUpb_CMessage* self = (PyUpb_CMessage*)_self;
+ PyUpb_CMessage* self = (void*)_self;
char* buf;
Py_ssize_t size;
PyObject* bytes = NULL;
@@ -1006,7 +1081,7 @@
static PyObject* PyUpb_CMessage_FindInitializationErrors(PyObject* _self,
PyObject* arg) {
- PyUpb_CMessage* self = (PyUpb_CMessage*)_self;
+ PyUpb_CMessage* self = (void*)_self;
upb_msg* msg = PyUpb_CMessage_GetIfWritable(_self);
if (!msg) return PyList_New(0);
const upb_msgdef* msgdef = _PyUpb_CMessage_GetMsgdef(self);
@@ -1022,7 +1097,7 @@
size_t need = upb_FieldPath_ToText(&fields, buf, size);
if (need >= size) {
fields = field;
- size = 16;
+ size = size ? size * 2 : 16;
while (size <= need) size *= 2;
buf = realloc(buf, size);
need = upb_FieldPath_ToText(&fields, buf, size);
@@ -1037,17 +1112,22 @@
static PyObject* PyUpb_CMessage_FromString(PyObject* cls,
PyObject* serialized) {
- PyObject* ret = PyObject_CallObject(cls, NULL);
- if (ret == NULL) return NULL;
+ PyObject* ret = NULL;
+ PyObject* length = NULL;
- PyObject* length = PyUpb_CMessage_MergeFromString(ret, serialized);
- if (length == NULL) {
- Py_DECREF(ret);
- return NULL;
- }
+ ret = PyObject_CallObject(cls, NULL);
+ if (ret == NULL) goto err;
+ length = PyUpb_CMessage_MergeFromString(ret, serialized);
+ if (length == NULL) goto err;
- Py_DECREF(length);
+done:
+ Py_XDECREF(length);
return ret;
+
+err:
+ Py_XDECREF(ret);
+ ret = NULL;
+ goto done;
}
static PyObject* PyUpb_CMessage_HasExtension(PyObject* _self,
@@ -1062,7 +1142,7 @@
PyObject* PyUpb_CMessage_SerializeInternal(PyObject* _self, PyObject* args,
PyObject* kwargs,
bool check_required) {
- PyUpb_CMessage* self = (PyUpb_CMessage*)_self;
+ PyUpb_CMessage* self = (void*)_self;
if (!PyUpb_CMessage_Check((PyObject*)self)) return NULL;
static const char* kwlist[] = {"deterministic", NULL};
int deterministic = 0;
@@ -1110,7 +1190,7 @@
}
static PyObject* PyUpb_CMessage_WhichOneof(PyObject* _self, PyObject* name) {
- PyUpb_CMessage* self = (PyUpb_CMessage*)_self;
+ PyUpb_CMessage* self = (void*)_self;
const upb_oneofdef* o;
if (!PyUpb_CMessage_LookupName(self, name, NULL, &o, PyExc_ValueError)) {
return NULL;
@@ -1123,14 +1203,14 @@
}
void PyUpb_CMessage_ClearExtensionDict(PyObject* _self) {
- PyUpb_CMessage* self = (PyUpb_CMessage*)_self;
+ PyUpb_CMessage* self = (void*)_self;
assert(self->ext_dict);
self->ext_dict = NULL;
}
static PyObject* PyUpb_CMessage_GetExtensionDict(PyObject* _self,
void* closure) {
- PyUpb_CMessage* self = (PyUpb_CMessage*)_self;
+ PyUpb_CMessage* self = (void*)_self;
if (self->ext_dict) {
return self->ext_dict;
}
@@ -1277,27 +1357,6 @@
return PyUpb_Descriptor_GetDef(self->py_message_descriptor);
}
-PyObject* PyUpb_MessageMeta_ModuleQualifiedName(const upb_msgdef* m) {
- const upb_filedef* file = upb_msgdef_file(m);
- const char* filename = upb_filedef_name(file);
- const char* msgname = upb_msgdef_name(m);
- const char* final_dot = strrchr(filename, '.');
- size_t len = final_dot ? final_dot - filename : strlen(filename);
- char* modname = malloc(len + 1);
- if (!modname) return NULL;
- for (size_t i = 0; i < len; i++) {
- if (filename[i] == '/') {
- modname[i] = '.';
- } else {
- modname[i] = filename[i];
- }
- }
- modname[len] = '\0';
- PyObject* ret = PyUnicode_FromFormat("%s_pb2.%s", modname, msgname);
- free(modname);
- return ret;
-}
-
PyObject* PyUpb_MessageMeta_DoCreateClass(PyObject* py_descriptor,
const char* name, PyObject* dict) {
PyUpb_ModuleState* state = PyUpb_ModuleState_Get();