|  | // Protocol Buffers - Google's data interchange format | 
|  | // Copyright 2023 Google LLC.  All rights reserved. | 
|  | // | 
|  | // Use of this source code is governed by a BSD-style | 
|  | // license that can be found in the LICENSE file or at | 
|  | // https://developers.google.com/open-source/licenses/bsd | 
|  |  | 
|  | #include "python/message.h" | 
|  |  | 
|  | #include "python/convert.h" | 
|  | #include "python/descriptor.h" | 
|  | #include "python/extension_dict.h" | 
|  | #include "python/map.h" | 
|  | #include "python/repeated.h" | 
|  | #include "upb/message/compare.h" | 
|  | #include "upb/message/copy.h" | 
|  | #include "upb/reflection/def.h" | 
|  | #include "upb/reflection/message.h" | 
|  | #include "upb/text/encode.h" | 
|  | #include "upb/util/required_fields.h" | 
|  |  | 
|  | static const upb_MessageDef* PyUpb_MessageMeta_GetMsgdef(PyObject* cls); | 
|  | static PyObject* PyUpb_MessageMeta_GetAttr(PyObject* self, PyObject* name); | 
|  |  | 
|  | // ----------------------------------------------------------------------------- | 
|  | // CPythonBits | 
|  | // ----------------------------------------------------------------------------- | 
|  |  | 
|  | // This struct contains a few things that are not exposed directly through the | 
|  | // limited API, but that we can get at in somewhat more roundabout ways. The | 
|  | // roundabout ways are slower, so we cache the values here. | 
|  | // | 
|  | // These values are valid to cache in a global, even across sub-interpreters, | 
|  | // because they are not pointers to interpreter state.  They are process | 
|  | // globals that will be the same for any interpreter in this process. | 
|  | typedef struct { | 
|  | // For each member, we note the equivalent expression that we could use in the | 
|  | // full (non-limited) API. | 
|  | newfunc type_new;            // PyTypeObject.tp_new | 
|  | destructor type_dealloc;     // PyTypeObject.tp_dealloc | 
|  | getattrofunc type_getattro;  // PyTypeObject.tp_getattro | 
|  | setattrofunc type_setattro;  // PyTypeObject.tp_setattro | 
|  | size_t type_basicsize;       // sizeof(PyHeapTypeObject) | 
|  | traverseproc type_traverse;  // PyTypeObject.tp_traverse | 
|  | inquiry type_clear;          // PyTypeObject.tp_clear | 
|  |  | 
|  | // While we can refer to PY_VERSION_HEX in the limited API, this will give us | 
|  | // the version of Python we were compiled against, which may be different | 
|  | // than the version we are dynamically linked against.  Here we want the | 
|  | // version that is actually running in this process. | 
|  | long python_version_hex;  // PY_VERSION_HEX | 
|  | } PyUpb_CPythonBits; | 
|  |  | 
|  | // A global containing the values for this process. | 
|  | PyUpb_CPythonBits cpython_bits; | 
|  |  | 
|  | destructor upb_Pre310_PyType_GetDeallocSlot(PyTypeObject* type_subclass) { | 
|  | // This is a bit desperate.  We need type_dealloc(), but PyType_GetSlot(type, | 
|  | // Py_tp_dealloc) will return subtype_dealloc().  There appears to be no way | 
|  | // whatsoever to fetch type_dealloc() through the limited API until Python | 
|  | // 3.10. | 
|  | // | 
|  | // To work around this so we attempt to find it by looking for the offset of | 
|  | // tp_dealloc in PyTypeObject, then memcpy() it directly.  This should always | 
|  | // work in practice. | 
|  | // | 
|  | // Starting with Python 3.10 on you can call PyType_GetSlot() on non-heap | 
|  | // types.  We will be able to replace all this hack with just: | 
|  | // | 
|  | //   PyType_GetSlot(&PyType_Type, Py_tp_dealloc) | 
|  | // | 
|  | destructor subtype_dealloc = PyType_GetSlot(type_subclass, Py_tp_dealloc); | 
|  | for (size_t i = 0; i < 2000; i += sizeof(uintptr_t)) { | 
|  | destructor maybe_subtype_dealloc; | 
|  | memcpy(&maybe_subtype_dealloc, (char*)type_subclass + i, | 
|  | sizeof(destructor)); | 
|  | if (maybe_subtype_dealloc == subtype_dealloc) { | 
|  | destructor type_dealloc; | 
|  | memcpy(&type_dealloc, (char*)&PyType_Type + i, sizeof(destructor)); | 
|  | return type_dealloc; | 
|  | } | 
|  | } | 
|  | assert(false); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | 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 | 
|  | // as a heap type it can be queried with PyType_GetSlot(). | 
|  | static PyType_Slot dummy_slots[] = {{0, NULL}}; | 
|  |  | 
|  | static PyType_Spec dummy_spec = { | 
|  | "module.DummyClass",  // tp_name | 
|  | 0,  // To be filled in by size of base     // tp_basicsize | 
|  | 0,  // tp_itemsize | 
|  | Py_TPFLAGS_DEFAULT,  // tp_flags | 
|  | dummy_slots, | 
|  | }; | 
|  |  | 
|  | 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(type, Py_tp_new); | 
|  | bits->type_dealloc = upb_Pre310_PyType_GetDeallocSlot(type); | 
|  | bits->type_getattro = PyType_GetSlot(type, Py_tp_getattro); | 
|  | bits->type_setattro = PyType_GetSlot(type, Py_tp_setattro); | 
|  | bits->type_traverse = PyType_GetSlot(type, Py_tp_traverse); | 
|  | bits->type_clear = PyType_GetSlot(type, Py_tp_clear); | 
|  |  | 
|  | size = PyObject_GetAttrString((PyObject*)&PyType_Type, "__basicsize__"); | 
|  | if (!size) goto err; | 
|  | bits->type_basicsize = PyLong_AsLong(size); | 
|  | if (bits->type_basicsize == -1) goto err; | 
|  |  | 
|  | assert(bits->type_new); | 
|  | assert(bits->type_dealloc); | 
|  | assert(bits->type_getattro); | 
|  | assert(bits->type_setattro); | 
|  | assert(bits->type_traverse); | 
|  | assert(bits->type_clear); | 
|  |  | 
|  | #ifndef Py_LIMITED_API | 
|  | assert(bits->type_new == PyType_Type.tp_new); | 
|  | assert(bits->type_dealloc == PyType_Type.tp_dealloc); | 
|  | assert(bits->type_getattro == PyType_Type.tp_getattro); | 
|  | assert(bits->type_setattro == PyType_Type.tp_setattro); | 
|  | assert(bits->type_basicsize == sizeof(PyHeapTypeObject)); | 
|  | assert(bits->type_traverse == PyType_Type.tp_traverse); | 
|  | assert(bits->type_clear == PyType_Type.tp_clear); | 
|  | #endif | 
|  |  | 
|  | sys = PyImport_ImportModule("sys"); | 
|  | hex_version = PyObject_GetAttrString(sys, "hexversion"); | 
|  | bits->python_version_hex = PyLong_AsLong(hex_version); | 
|  | ret = true; | 
|  |  | 
|  | err: | 
|  | Py_XDECREF(bases); | 
|  | Py_XDECREF(type); | 
|  | Py_XDECREF(size); | 
|  | Py_XDECREF(sys); | 
|  | Py_XDECREF(hex_version); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | // ----------------------------------------------------------------------------- | 
|  | // Message | 
|  | // ----------------------------------------------------------------------------- | 
|  |  | 
|  | // The main message object.  The type of the object (PyUpb_Message.ob_type) | 
|  | // will be an instance of the PyUpb_MessageMeta type (defined below).  So the | 
|  | // chain is: | 
|  | //   FooMessage = MessageMeta(...) | 
|  | //   foo = FooMessage() | 
|  | // | 
|  | // Which becomes: | 
|  | //   Object             C Struct Type        Python type (ob_type) | 
|  | //   -----------------  -----------------    --------------------- | 
|  | //   foo                PyUpb_Message        FooMessage | 
|  | //   FooMessage         PyUpb_MessageMeta    message_meta_type | 
|  | //   message_meta_type  PyTypeObject         'type' in Python | 
|  | // | 
|  | // A message object can be in one of two states: present or non-present.  When | 
|  | // a message is non-present, it stores a reference to its parent, and a write | 
|  | // to any attribute will trigger the message to become present in its parent. | 
|  | // The parent may also be non-present, in which case a mutation will trigger a | 
|  | // chain reaction. | 
|  | typedef struct PyUpb_Message { | 
|  | PyObject_HEAD; | 
|  | PyObject* arena; | 
|  | uintptr_t def;  // Tagged, low bit 1 == upb_FieldDef*, else upb_MessageDef* | 
|  | union { | 
|  | // when def is msgdef, the data for this msg. | 
|  | upb_Message* msg; | 
|  | // when def is fielddef, owning pointer to parent | 
|  | struct PyUpb_Message* parent; | 
|  | } ptr; | 
|  | PyObject* ext_dict;  // Weak pointer to extension dict, if any. | 
|  | // name->obj dict for non-present msg/map/repeated, NULL if none. | 
|  | PyUpb_WeakMap* unset_subobj_map; | 
|  | int version; | 
|  | } PyUpb_Message; | 
|  |  | 
|  | static PyObject* PyUpb_Message_GetAttr(PyObject* _self, PyObject* attr); | 
|  |  | 
|  | bool PyUpb_Message_IsStub(PyUpb_Message* msg) { return msg->def & 1; } | 
|  |  | 
|  | const upb_FieldDef* PyUpb_Message_GetFieldDef(PyUpb_Message* msg) { | 
|  | assert(PyUpb_Message_IsStub(msg)); | 
|  | return (void*)(msg->def & ~(uintptr_t)1); | 
|  | } | 
|  |  | 
|  | static const upb_MessageDef* _PyUpb_Message_GetMsgdef(PyUpb_Message* msg) { | 
|  | return PyUpb_Message_IsStub(msg) | 
|  | ? upb_FieldDef_MessageSubDef(PyUpb_Message_GetFieldDef(msg)) | 
|  | : (void*)msg->def; | 
|  | } | 
|  |  | 
|  | const upb_MessageDef* PyUpb_Message_GetMsgdef(PyObject* self) { | 
|  | return _PyUpb_Message_GetMsgdef((PyUpb_Message*)self); | 
|  | } | 
|  |  | 
|  | static upb_Message* PyUpb_Message_GetMsg(PyUpb_Message* self) { | 
|  | assert(!PyUpb_Message_IsStub(self)); | 
|  | return self->ptr.msg; | 
|  | } | 
|  |  | 
|  | bool PyUpb_Message_TryCheck(PyObject* self) { | 
|  | PyUpb_ModuleState* state = PyUpb_ModuleState_Get(); | 
|  | PyObject* type = (PyObject*)Py_TYPE(self); | 
|  | return Py_TYPE(type) == state->message_meta_type; | 
|  | } | 
|  |  | 
|  | bool PyUpb_Message_Verify(PyObject* self) { | 
|  | if (!PyUpb_Message_TryCheck(self)) { | 
|  | PyErr_Format(PyExc_TypeError, "Expected a message object, but got %R.", | 
|  | self); | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // If the message is reified, returns it.  Otherwise, returns NULL. | 
|  | // If NULL is returned, the object is empty and has no underlying data. | 
|  | upb_Message* PyUpb_Message_GetIfReified(PyObject* _self) { | 
|  | PyUpb_Message* self = (void*)_self; | 
|  | return PyUpb_Message_IsStub(self) ? NULL : self->ptr.msg; | 
|  | } | 
|  |  | 
|  | static PyObject* PyUpb_Message_New(PyObject* cls, PyObject* unused_args, | 
|  | PyObject* unused_kwargs) { | 
|  | const upb_MessageDef* msgdef = PyUpb_MessageMeta_GetMsgdef(cls); | 
|  | const upb_MiniTable* layout = upb_MessageDef_MiniTable(msgdef); | 
|  | PyUpb_Message* msg = (void*)PyType_GenericAlloc((PyTypeObject*)cls, 0); | 
|  | msg->def = (uintptr_t)msgdef; | 
|  | msg->arena = PyUpb_Arena_New(); | 
|  | msg->ptr.msg = upb_Message_New(layout, PyUpb_Arena_Get(msg->arena)); | 
|  | msg->unset_subobj_map = NULL; | 
|  | msg->ext_dict = NULL; | 
|  | msg->version = 0; | 
|  |  | 
|  | PyObject* ret = &msg->ob_base; | 
|  | PyUpb_ObjCache_Add(msg->ptr.msg, ret); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * PyUpb_Message_LookupName() | 
|  | * | 
|  | * Tries to find a field or oneof named `py_name` in the message object `self`. | 
|  | * 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. | 
|  | */ | 
|  | static bool PyUpb_Message_LookupName(PyUpb_Message* self, PyObject* py_name, | 
|  | const upb_FieldDef** f, | 
|  | const upb_OneofDef** o, | 
|  | PyObject* exc_type) { | 
|  | assert(f || o); | 
|  | Py_ssize_t size; | 
|  | const char* name = NULL; | 
|  | if (PyUnicode_Check(py_name)) { | 
|  | name = PyUnicode_AsUTF8AndSize(py_name, &size); | 
|  | } else if (PyBytes_Check(py_name)) { | 
|  | PyBytes_AsStringAndSize(py_name, (char**)&name, &size); | 
|  | } | 
|  | if (!name) { | 
|  | PyErr_Format(exc_type, | 
|  | "Expected a field name, but got non-string argument %S.", | 
|  | py_name); | 
|  | return false; | 
|  | } | 
|  | const upb_MessageDef* msgdef = _PyUpb_Message_GetMsgdef(self); | 
|  |  | 
|  | if (!upb_MessageDef_FindByNameWithSize(msgdef, name, size, f, o)) { | 
|  | if (exc_type) { | 
|  | PyErr_Format(exc_type, "Protocol message %s has no \"%s\" field.", | 
|  | upb_MessageDef_Name(msgdef), name); | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | if (!o && !*f) { | 
|  | if (exc_type) { | 
|  | PyErr_Format(exc_type, "Expected a field name, but got oneof name %s.", | 
|  | name); | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | if (!f && !*o) { | 
|  | if (exc_type) { | 
|  | PyErr_Format(exc_type, "Expected a oneof name, but got field name %s.", | 
|  | name); | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | static bool PyUpb_Message_InitMessageMapEntry(PyObject* dst, PyObject* src) { | 
|  | if (!src || !dst) return false; | 
|  |  | 
|  | PyObject* ok = PyObject_CallMethod(dst, "CopyFrom", "O", src); | 
|  | if (!ok) return false; | 
|  | Py_DECREF(ok); | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | int PyUpb_Message_InitMapAttributes(PyObject* map, PyObject* value, | 
|  | const upb_FieldDef* f) { | 
|  | const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(f); | 
|  | const upb_FieldDef* val_f = upb_MessageDef_Field(entry_m, 1); | 
|  | PyObject* it = NULL; | 
|  | PyObject* tmp = NULL; | 
|  | int ret = -1; | 
|  | if (upb_FieldDef_IsSubMessage(val_f)) { | 
|  | it = PyObject_GetIter(value); | 
|  | if (it == NULL) { | 
|  | PyErr_Format(PyExc_TypeError, "Argument for field %s is not iterable", | 
|  | upb_FieldDef_FullName(f)); | 
|  | goto err; | 
|  | } | 
|  | PyObject* e; | 
|  | while ((e = PyIter_Next(it)) != NULL) { | 
|  | PyObject* src = PyObject_GetItem(value, e); | 
|  | PyObject* dst = PyObject_GetItem(map, e); | 
|  | Py_DECREF(e); | 
|  | bool ok = PyUpb_Message_InitMessageMapEntry(dst, src); | 
|  | Py_XDECREF(src); | 
|  | Py_XDECREF(dst); | 
|  | if (!ok) goto err; | 
|  | } | 
|  | } else { | 
|  | tmp = PyObject_CallMethod(map, "update", "O", value); | 
|  | if (!tmp) goto err; | 
|  | } | 
|  | ret = 0; | 
|  |  | 
|  | err: | 
|  | Py_XDECREF(it); | 
|  | Py_XDECREF(tmp); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | void PyUpb_Message_EnsureReified(PyUpb_Message* self); | 
|  |  | 
|  | static bool PyUpb_Message_InitMapAttribute(PyObject* _self, PyObject* name, | 
|  | const upb_FieldDef* f, | 
|  | PyObject* value) { | 
|  | PyObject* map = PyUpb_Message_GetAttr(_self, name); | 
|  | int ok = PyUpb_Message_InitMapAttributes(map, value, f); | 
|  | Py_DECREF(map); | 
|  | return ok >= 0; | 
|  | } | 
|  |  | 
|  | static bool PyUpb_Message_InitRepeatedMessageAttribute(PyObject* _self, | 
|  | PyObject* repeated, | 
|  | PyObject* value, | 
|  | const upb_FieldDef* f) { | 
|  | PyObject* it = PyObject_GetIter(value); | 
|  | if (!it) { | 
|  | PyErr_Format(PyExc_TypeError, "Argument for field %s is not iterable", | 
|  | upb_FieldDef_FullName(f)); | 
|  | return false; | 
|  | } | 
|  | PyObject* e = NULL; | 
|  | PyObject* m = NULL; | 
|  | while ((e = PyIter_Next(it)) != NULL) { | 
|  | if (PyDict_Check(e)) { | 
|  | m = PyUpb_RepeatedCompositeContainer_Add(repeated, NULL, e); | 
|  | if (!m) goto err; | 
|  | } else { | 
|  | m = PyUpb_RepeatedCompositeContainer_Add(repeated, NULL, NULL); | 
|  | if (!m) goto err; | 
|  | PyObject* merged = PyUpb_Message_MergeFrom(m, e); | 
|  | if (!merged) goto err; | 
|  | Py_DECREF(merged); | 
|  | } | 
|  | Py_DECREF(e); | 
|  | Py_DECREF(m); | 
|  | m = NULL; | 
|  | } | 
|  |  | 
|  | err: | 
|  | Py_XDECREF(it); | 
|  | Py_XDECREF(e); | 
|  | Py_XDECREF(m); | 
|  | return !PyErr_Occurred();  // Check PyIter_Next() exit. | 
|  | } | 
|  |  | 
|  | static bool PyUpb_Message_InitRepeatedAttribute(PyObject* _self, PyObject* name, | 
|  | PyObject* value) { | 
|  | PyUpb_Message* self = (void*)_self; | 
|  | const upb_FieldDef* field; | 
|  | if (!PyUpb_Message_LookupName(self, name, &field, NULL, | 
|  | PyExc_AttributeError)) { | 
|  | return false; | 
|  | } | 
|  | bool ok = false; | 
|  | PyObject* repeated = PyUpb_Message_GetFieldValue(_self, field); | 
|  | PyObject* tmp = NULL; | 
|  | if (!repeated) goto err; | 
|  | if (upb_FieldDef_IsSubMessage(field)) { | 
|  | if (!PyUpb_Message_InitRepeatedMessageAttribute(_self, repeated, value, | 
|  | field)) { | 
|  | goto err; | 
|  | } | 
|  | } else { | 
|  | tmp = PyUpb_RepeatedContainer_Extend(repeated, value); | 
|  | if (!tmp) goto err; | 
|  | } | 
|  | ok = true; | 
|  |  | 
|  | err: | 
|  | Py_XDECREF(repeated); | 
|  | Py_XDECREF(tmp); | 
|  | return ok; | 
|  | } | 
|  |  | 
|  | static bool PyUpb_Message_InitMessageAttribute(PyObject* _self, PyObject* name, | 
|  | PyObject* value) { | 
|  | PyObject* submsg = PyUpb_Message_GetAttr(_self, name); | 
|  | if (!submsg) return -1; | 
|  | assert(!PyErr_Occurred()); | 
|  | bool ok; | 
|  | if (PyUpb_Message_TryCheck(value)) { | 
|  | PyObject* tmp = PyUpb_Message_MergeFrom(submsg, value); | 
|  | ok = tmp != NULL; | 
|  | Py_XDECREF(tmp); | 
|  | } else if (PyDict_Check(value)) { | 
|  | assert(!PyErr_Occurred()); | 
|  | ok = PyUpb_Message_InitAttributes(submsg, NULL, value) >= 0; | 
|  | } else { | 
|  | const upb_MessageDef* m = PyUpb_Message_GetMsgdef(_self); | 
|  | PyErr_Format(PyExc_TypeError, "Message must be initialized with a dict: %s", | 
|  | upb_MessageDef_FullName(m)); | 
|  | ok = false; | 
|  | } | 
|  | Py_DECREF(submsg); | 
|  | return ok; | 
|  | } | 
|  |  | 
|  | static bool PyUpb_Message_InitScalarAttribute(upb_Message* msg, | 
|  | const upb_FieldDef* f, | 
|  | PyObject* value, | 
|  | upb_Arena* arena) { | 
|  | upb_MessageValue msgval; | 
|  | assert(!PyErr_Occurred()); | 
|  | if (!PyUpb_PyToUpb(value, f, &msgval, arena)) return false; | 
|  | upb_Message_SetFieldByDef(msg, f, msgval, arena); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | int PyUpb_Message_InitAttributes(PyObject* _self, PyObject* args, | 
|  | PyObject* kwargs) { | 
|  | assert(!PyErr_Occurred()); | 
|  |  | 
|  | if (args != NULL && PyTuple_Size(args) != 0) { | 
|  | PyErr_SetString(PyExc_TypeError, "No positional arguments allowed"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | if (kwargs == NULL) return 0; | 
|  |  | 
|  | PyUpb_Message* self = (void*)_self; | 
|  | Py_ssize_t pos = 0; | 
|  | PyObject* name; | 
|  | PyObject* value; | 
|  | PyUpb_Message_EnsureReified(self); | 
|  | upb_Message* msg = PyUpb_Message_GetMsg(self); | 
|  | upb_Arena* arena = PyUpb_Arena_Get(self->arena); | 
|  |  | 
|  | while (PyDict_Next(kwargs, &pos, &name, &value)) { | 
|  | assert(!PyErr_Occurred()); | 
|  | const upb_FieldDef* f; | 
|  | assert(!PyErr_Occurred()); | 
|  | if (!PyUpb_Message_LookupName(self, name, &f, NULL, PyExc_ValueError)) { | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | if (value == Py_None) continue;  // Ignored. | 
|  |  | 
|  | assert(!PyErr_Occurred()); | 
|  |  | 
|  | if (upb_FieldDef_IsMap(f)) { | 
|  | if (!PyUpb_Message_InitMapAttribute(_self, name, f, value)) return -1; | 
|  | } else if (upb_FieldDef_IsRepeated(f)) { | 
|  | if (!PyUpb_Message_InitRepeatedAttribute(_self, name, value)) return -1; | 
|  | } else if (upb_FieldDef_IsSubMessage(f)) { | 
|  | if (!PyUpb_Message_InitMessageAttribute(_self, name, value)) return -1; | 
|  | } else { | 
|  | if (!PyUpb_Message_InitScalarAttribute(msg, f, value, arena)) return -1; | 
|  | } | 
|  | if (PyErr_Occurred()) return -1; | 
|  | } | 
|  |  | 
|  | if (PyErr_Occurred()) return -1; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int PyUpb_Message_Init(PyObject* _self, PyObject* args, | 
|  | PyObject* kwargs) { | 
|  | if (args != NULL && PyTuple_Size(args) != 0) { | 
|  | PyErr_SetString(PyExc_TypeError, "No positional arguments allowed"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | return PyUpb_Message_InitAttributes(_self, args, kwargs); | 
|  | } | 
|  |  | 
|  | static PyObject* PyUpb_Message_NewStub(PyObject* parent, const upb_FieldDef* f, | 
|  | PyObject* arena) { | 
|  | const upb_MessageDef* sub_m = upb_FieldDef_MessageSubDef(f); | 
|  | PyObject* cls = PyUpb_Descriptor_GetClass(sub_m); | 
|  |  | 
|  | PyUpb_Message* msg = (void*)PyType_GenericAlloc((PyTypeObject*)cls, 0); | 
|  | msg->def = (uintptr_t)f | 1; | 
|  | msg->arena = arena; | 
|  | msg->ptr.parent = (PyUpb_Message*)parent; | 
|  | msg->unset_subobj_map = NULL; | 
|  | msg->ext_dict = NULL; | 
|  | msg->version = 0; | 
|  |  | 
|  | Py_DECREF(cls); | 
|  | Py_INCREF(parent); | 
|  | Py_INCREF(arena); | 
|  | return &msg->ob_base; | 
|  | } | 
|  |  | 
|  | static bool PyUpb_Message_IsEmpty(const upb_Message* msg, | 
|  | const upb_MessageDef* m, | 
|  | const upb_DefPool* ext_pool) { | 
|  | if (!msg) return true; | 
|  |  | 
|  | size_t iter = kUpb_Message_Begin; | 
|  | const upb_FieldDef* f; | 
|  | upb_MessageValue val; | 
|  | if (upb_Message_Next(msg, m, ext_pool, &f, &val, &iter)) return false; | 
|  |  | 
|  | size_t len; | 
|  | (void)upb_Message_GetUnknown(msg, &len); | 
|  | return len == 0; | 
|  | } | 
|  |  | 
|  | static bool PyUpb_Message_IsEqual(PyUpb_Message* m1, PyObject* _m2) { | 
|  | PyUpb_Message* m2 = (void*)_m2; | 
|  | if (m1 == m2) return true; | 
|  | if (!PyObject_TypeCheck(_m2, m1->ob_base.ob_type)) { | 
|  | return false; | 
|  | } | 
|  | const upb_MessageDef* m1_msgdef = _PyUpb_Message_GetMsgdef(m1); | 
|  | #ifndef NDEBUG | 
|  | const upb_MessageDef* m2_msgdef = _PyUpb_Message_GetMsgdef(m2); | 
|  | assert(m1_msgdef == m2_msgdef); | 
|  | #endif | 
|  | const upb_Message* m1_msg = PyUpb_Message_GetIfReified((PyObject*)m1); | 
|  | const upb_Message* m2_msg = PyUpb_Message_GetIfReified(_m2); | 
|  | const upb_DefPool* symtab = upb_FileDef_Pool(upb_MessageDef_File(m1_msgdef)); | 
|  |  | 
|  | const bool e1 = PyUpb_Message_IsEmpty(m1_msg, m1_msgdef, symtab); | 
|  | const bool e2 = PyUpb_Message_IsEmpty(m2_msg, m1_msgdef, symtab); | 
|  | if (e1 || e2) return e1 && e2; | 
|  |  | 
|  | const int options = kUpb_CompareOption_IncludeUnknownFields; | 
|  | return upb_Message_IsEqualByDef(m1_msg, m2_msg, m1_msgdef, options); | 
|  | } | 
|  |  | 
|  | static const upb_FieldDef* PyUpb_Message_InitAsMsg(PyUpb_Message* m, | 
|  | upb_Arena* arena) { | 
|  | const upb_FieldDef* f = PyUpb_Message_GetFieldDef(m); | 
|  | const upb_MessageDef* m2 = upb_FieldDef_MessageSubDef(f); | 
|  | m->ptr.msg = upb_Message_New(upb_MessageDef_MiniTable(m2), arena); | 
|  | m->def = (uintptr_t)m2; | 
|  | PyUpb_ObjCache_Add(m->ptr.msg, &m->ob_base); | 
|  | return f; | 
|  | } | 
|  |  | 
|  | static void PyUpb_Message_SetField(PyUpb_Message* parent, const upb_FieldDef* f, | 
|  | PyUpb_Message* child, upb_Arena* arena) { | 
|  | upb_MessageValue msgval = {.msg_val = PyUpb_Message_GetMsg(child)}; | 
|  | upb_Message_SetFieldByDef(PyUpb_Message_GetMsg(parent), f, msgval, arena); | 
|  | PyUpb_WeakMap_Delete(parent->unset_subobj_map, f); | 
|  | // Releases a ref previously owned by child->ptr.parent of our child. | 
|  | Py_DECREF(child); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * PyUpb_Message_EnsureReified() | 
|  | * | 
|  | * This implements the "expando" behavior of Python protos: | 
|  | *   foo = FooProto() | 
|  | * | 
|  | *   # The intermediate messages don't really exist, and won't be serialized. | 
|  | *   x = foo.bar.bar.bar.bar.bar.baz | 
|  | * | 
|  | *   # Now all the intermediate objects are created. | 
|  | *   foo.bar.bar.bar.bar.bar.baz = 5 | 
|  | * | 
|  | * This function should be called before performing any mutation of a protobuf | 
|  | * object. | 
|  | * | 
|  | * Post-condition: | 
|  | *   PyUpb_Message_IsStub(self) is false | 
|  | */ | 
|  | void PyUpb_Message_EnsureReified(PyUpb_Message* self) { | 
|  | if (!PyUpb_Message_IsStub(self)) return; | 
|  | upb_Arena* arena = PyUpb_Arena_Get(self->arena); | 
|  |  | 
|  | // This is a non-present message. We need to create a real upb_Message for | 
|  | // this object and every parent until we reach a present message. | 
|  | PyUpb_Message* child = self; | 
|  | PyUpb_Message* parent = self->ptr.parent; | 
|  | const upb_FieldDef* child_f = PyUpb_Message_InitAsMsg(child, arena); | 
|  | Py_INCREF(child);  // To avoid a special-case in PyUpb_Message_SetField(). | 
|  |  | 
|  | do { | 
|  | PyUpb_Message* next_parent = parent->ptr.parent; | 
|  | const upb_FieldDef* parent_f = NULL; | 
|  | if (PyUpb_Message_IsStub(parent)) { | 
|  | parent_f = PyUpb_Message_InitAsMsg(parent, arena); | 
|  | } | 
|  | PyUpb_Message_SetField(parent, child_f, child, arena); | 
|  | child = parent; | 
|  | child_f = parent_f; | 
|  | parent = next_parent; | 
|  | } while (child_f); | 
|  |  | 
|  | // Releases ref previously owned by child->ptr.parent of our child. | 
|  | Py_DECREF(child); | 
|  | self->version++; | 
|  | } | 
|  |  | 
|  | static void PyUpb_Message_SyncSubobjs(PyUpb_Message* self); | 
|  |  | 
|  | /* | 
|  | * PyUpb_Message_Reify() | 
|  | * | 
|  | * The message equivalent of PyUpb_*Container_Reify(), this transitions | 
|  | * the wrapper from the unset state (owning a reference on self->ptr.parent) to | 
|  | * the set state (having a non-owning pointer to self->ptr.msg). | 
|  | */ | 
|  | static void PyUpb_Message_Reify(PyUpb_Message* self, const upb_FieldDef* f, | 
|  | upb_Message* msg) { | 
|  | assert(f == PyUpb_Message_GetFieldDef(self)); | 
|  | if (!msg) { | 
|  | const upb_MessageDef* msgdef = PyUpb_Message_GetMsgdef((PyObject*)self); | 
|  | const upb_MiniTable* layout = upb_MessageDef_MiniTable(msgdef); | 
|  | msg = upb_Message_New(layout, PyUpb_Arena_Get(self->arena)); | 
|  | } | 
|  | PyUpb_ObjCache_Add(msg, &self->ob_base); | 
|  | Py_DECREF(&self->ptr.parent->ob_base); | 
|  | self->ptr.msg = msg;  // Overwrites self->ptr.parent | 
|  | self->def = (uintptr_t)upb_FieldDef_MessageSubDef(f); | 
|  | PyUpb_Message_SyncSubobjs(self); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * PyUpb_Message_SyncSubobjs() | 
|  | * | 
|  | * This operation must be invoked whenever the underlying upb_Message has been | 
|  | * mutated directly in C.  This will attach any newly-present field data | 
|  | * to previously returned stub wrapper objects. | 
|  | * | 
|  | * For example: | 
|  | *   foo = FooMessage() | 
|  | *   sub = foo.submsg  # Empty, unset sub-message | 
|  | * | 
|  | *   # 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_Message_SyncSubobjs(PyUpb_Message* self) { | 
|  | PyUpb_WeakMap* subobj_map = self->unset_subobj_map; | 
|  | if (!subobj_map) return; | 
|  |  | 
|  | upb_Message* msg = PyUpb_Message_GetMsg(self); | 
|  | intptr_t iter = PYUPB_WEAKMAP_BEGIN; | 
|  | const void* key; | 
|  | PyObject* obj; | 
|  |  | 
|  | // The last ref to this message could disappear during iteration. | 
|  | // When we call PyUpb_*Container_Reify() 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)) { | 
|  | const upb_FieldDef* f = key; | 
|  | if (upb_FieldDef_HasPresence(f) && !upb_Message_HasFieldByDef(msg, f)) | 
|  | continue; | 
|  | upb_MessageValue msgval = upb_Message_GetFieldByDef(msg, f); | 
|  | PyUpb_WeakMap_DeleteIter(subobj_map, &iter); | 
|  | if (upb_FieldDef_IsMap(f)) { | 
|  | if (!msgval.map_val) continue; | 
|  | PyUpb_MapContainer_Reify(obj, (upb_Map*)msgval.map_val); | 
|  | } else if (upb_FieldDef_IsRepeated(f)) { | 
|  | if (!msgval.array_val) continue; | 
|  | PyUpb_RepeatedContainer_Reify(obj, (upb_Array*)msgval.array_val); | 
|  | } else { | 
|  | PyUpb_Message* sub = (void*)obj; | 
|  | assert(self == sub->ptr.parent); | 
|  | PyUpb_Message_Reify(sub, f, (upb_Message*)msgval.msg_val); | 
|  | } | 
|  | } | 
|  |  | 
|  | Py_DECREF(&self->ob_base); | 
|  |  | 
|  | // TODO: present fields need to be iterated too if they can reach | 
|  | // a WeakMap. | 
|  | } | 
|  |  | 
|  | static PyObject* PyUpb_Message_ToString(PyUpb_Message* self) { | 
|  | if (PyUpb_Message_IsStub(self)) { | 
|  | return PyUnicode_FromStringAndSize(NULL, 0); | 
|  | } | 
|  | upb_Message* msg = PyUpb_Message_GetMsg(self); | 
|  | const upb_MessageDef* msgdef = _PyUpb_Message_GetMsgdef(self); | 
|  | const upb_DefPool* symtab = upb_FileDef_Pool(upb_MessageDef_File(msgdef)); | 
|  | char buf[1024]; | 
|  | int options = UPB_TXTENC_SKIPUNKNOWN; | 
|  | size_t size = upb_TextEncode(msg, msgdef, symtab, options, buf, sizeof(buf)); | 
|  | if (size < sizeof(buf)) { | 
|  | return PyUnicode_FromStringAndSize(buf, size); | 
|  | } else { | 
|  | char* buf2 = malloc(size + 1); | 
|  | size_t size2 = upb_TextEncode(msg, msgdef, symtab, options, buf2, size + 1); | 
|  | assert(size == size2); | 
|  | PyObject* ret = PyUnicode_FromStringAndSize(buf2, size2); | 
|  | free(buf2); | 
|  | return ret; | 
|  | } | 
|  | } | 
|  |  | 
|  | static PyObject* PyUpb_Message_RichCompare(PyObject* _self, PyObject* other, | 
|  | int opid) { | 
|  | PyUpb_Message* self = (void*)_self; | 
|  | if (opid != Py_EQ && opid != Py_NE) { | 
|  | Py_INCREF(Py_NotImplemented); | 
|  | return Py_NotImplemented; | 
|  | } | 
|  | if (!PyObject_TypeCheck(other, Py_TYPE(self))) { | 
|  | Py_INCREF(Py_NotImplemented); | 
|  | return Py_NotImplemented; | 
|  | } | 
|  | bool ret = PyUpb_Message_IsEqual(self, other); | 
|  | if (opid == Py_NE) ret = !ret; | 
|  | return PyBool_FromLong(ret); | 
|  | } | 
|  |  | 
|  | void PyUpb_Message_CacheDelete(PyObject* _self, const upb_FieldDef* f) { | 
|  | PyUpb_Message* self = (void*)_self; | 
|  | PyUpb_WeakMap_Delete(self->unset_subobj_map, f); | 
|  | } | 
|  |  | 
|  | void PyUpb_Message_SetConcreteSubobj(PyObject* _self, const upb_FieldDef* f, | 
|  | upb_MessageValue subobj) { | 
|  | PyUpb_Message* self = (void*)_self; | 
|  | PyUpb_Message_EnsureReified(self); | 
|  | PyUpb_Message_CacheDelete(_self, f); | 
|  | upb_Message_SetFieldByDef(self->ptr.msg, f, subobj, | 
|  | PyUpb_Arena_Get(self->arena)); | 
|  | } | 
|  |  | 
|  | static void PyUpb_Message_Dealloc(PyObject* _self) { | 
|  | PyUpb_Message* self = (void*)_self; | 
|  |  | 
|  | if (PyUpb_Message_IsStub(self)) { | 
|  | PyUpb_Message_CacheDelete((PyObject*)self->ptr.parent, | 
|  | PyUpb_Message_GetFieldDef(self)); | 
|  | Py_DECREF(self->ptr.parent); | 
|  | } else { | 
|  | PyUpb_ObjCache_Delete(self->ptr.msg); | 
|  | } | 
|  |  | 
|  | if (self->unset_subobj_map) { | 
|  | PyUpb_WeakMap_Free(self->unset_subobj_map); | 
|  | } | 
|  |  | 
|  | Py_DECREF(self->arena); | 
|  |  | 
|  | // We do not use PyUpb_Dealloc() here because Message is a base type and for | 
|  | // base types there is a bug we have to work around in this case (see below). | 
|  | PyTypeObject* tp = Py_TYPE(self); | 
|  | freefunc tp_free = PyType_GetSlot(tp, Py_tp_free); | 
|  | tp_free(self); | 
|  |  | 
|  | if (cpython_bits.python_version_hex >= 0x03080000) { | 
|  | // Prior to Python 3.8 there is a bug where deallocating the type here would | 
|  | // lead to a double-decref: https://bugs.python.org/issue37879 | 
|  | Py_DECREF(tp); | 
|  | } | 
|  | } | 
|  |  | 
|  | PyObject* PyUpb_Message_Get(upb_Message* u_msg, const upb_MessageDef* m, | 
|  | PyObject* arena) { | 
|  | PyObject* ret = PyUpb_ObjCache_Get(u_msg); | 
|  | if (ret) return ret; | 
|  |  | 
|  | PyObject* cls = PyUpb_Descriptor_GetClass(m); | 
|  | // It is not safe to use PyObject_{,GC}_New() due to: | 
|  | //    https://bugs.python.org/issue35810 | 
|  | PyUpb_Message* py_msg = (void*)PyType_GenericAlloc((PyTypeObject*)cls, 0); | 
|  | py_msg->arena = arena; | 
|  | py_msg->def = (uintptr_t)m; | 
|  | py_msg->ptr.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; | 
|  | } | 
|  |  | 
|  | /* PyUpb_Message_GetStub() | 
|  | * | 
|  | * Non-present messages return "stub" objects that point to their parent, but | 
|  | * will materialize into real upb objects if they are mutated. | 
|  | * | 
|  | * Note: we do *not* create stubs for repeated/map fields unless the parent | 
|  | * is a stub: | 
|  | * | 
|  | *    msg = TestMessage() | 
|  | *    msg.submessage                # (A) Creates a stub | 
|  | *    msg.repeated_foo              # (B) Does *not* create a stub | 
|  | *    msg.submessage.repeated_bar   # (C) Creates a stub | 
|  | * | 
|  | * In case (B) we have some freedom: we could either create a stub, or create | 
|  | * a reified object with underlying data.  It appears that either could work | 
|  | * equally well, with no observable change to users.  There isn't a clear | 
|  | * advantage to either choice.  We choose to follow the behavior of the | 
|  | * pre-existing C++ behavior for consistency, but if it becomes apparent that | 
|  | * there would be some benefit to reversing this decision, it should be totally | 
|  | * within the realm of possibility. | 
|  | */ | 
|  | PyObject* PyUpb_Message_GetStub(PyUpb_Message* self, | 
|  | const upb_FieldDef* field) { | 
|  | PyObject* _self = (void*)self; | 
|  | if (!self->unset_subobj_map) { | 
|  | self->unset_subobj_map = PyUpb_WeakMap_New(); | 
|  | } | 
|  | PyObject* subobj = PyUpb_WeakMap_Get(self->unset_subobj_map, field); | 
|  |  | 
|  | if (subobj) return subobj; | 
|  |  | 
|  | if (upb_FieldDef_IsMap(field)) { | 
|  | subobj = PyUpb_MapContainer_NewStub(_self, field, self->arena); | 
|  | } else if (upb_FieldDef_IsRepeated(field)) { | 
|  | subobj = PyUpb_RepeatedContainer_NewStub(_self, field, self->arena); | 
|  | } else { | 
|  | subobj = PyUpb_Message_NewStub(&self->ob_base, field, self->arena); | 
|  | } | 
|  | PyUpb_WeakMap_Add(self->unset_subobj_map, field, subobj); | 
|  |  | 
|  | assert(!PyErr_Occurred()); | 
|  | return subobj; | 
|  | } | 
|  |  | 
|  | PyObject* PyUpb_Message_GetPresentWrapper(PyUpb_Message* self, | 
|  | const upb_FieldDef* field) { | 
|  | assert(!PyUpb_Message_IsStub(self)); | 
|  | upb_MutableMessageValue mutval = | 
|  | upb_Message_Mutable(self->ptr.msg, field, PyUpb_Arena_Get(self->arena)); | 
|  | if (upb_FieldDef_IsMap(field)) { | 
|  | return PyUpb_MapContainer_GetOrCreateWrapper(mutval.map, field, | 
|  | self->arena); | 
|  | } else { | 
|  | return PyUpb_RepeatedContainer_GetOrCreateWrapper(mutval.array, field, | 
|  | self->arena); | 
|  | } | 
|  | } | 
|  |  | 
|  | PyObject* PyUpb_Message_GetScalarValue(PyUpb_Message* self, | 
|  | const upb_FieldDef* field) { | 
|  | upb_MessageValue val; | 
|  | if (PyUpb_Message_IsStub(self)) { | 
|  | // Unset message always returns default values. | 
|  | val = upb_FieldDef_Default(field); | 
|  | } else { | 
|  | val = upb_Message_GetFieldByDef(self->ptr.msg, field); | 
|  | } | 
|  | return PyUpb_UpbToPy(val, field, self->arena); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * PyUpb_Message_GetFieldValue() | 
|  | * | 
|  | * Implements the equivalent of getattr(msg, field), once `field` has | 
|  | * already been resolved to a `upb_FieldDef*`. | 
|  | * | 
|  | * This may involve constructing a wrapper object for the given field, or | 
|  | * returning one that was previously constructed.  If the field is not actually | 
|  | * set, the wrapper object will be an "unset" object that is not actually | 
|  | * connected to any C data. | 
|  | */ | 
|  | PyObject* PyUpb_Message_GetFieldValue(PyObject* _self, | 
|  | const upb_FieldDef* field) { | 
|  | PyUpb_Message* self = (void*)_self; | 
|  | assert(upb_FieldDef_ContainingType(field) == PyUpb_Message_GetMsgdef(_self)); | 
|  | bool submsg = upb_FieldDef_IsSubMessage(field); | 
|  | bool seq = upb_FieldDef_IsRepeated(field); | 
|  |  | 
|  | if ((PyUpb_Message_IsStub(self) && (submsg || seq)) || | 
|  | (submsg && !seq && !upb_Message_HasFieldByDef(self->ptr.msg, field))) { | 
|  | return PyUpb_Message_GetStub(self, field); | 
|  | } else if (seq) { | 
|  | return PyUpb_Message_GetPresentWrapper(self, field); | 
|  | } else { | 
|  | return PyUpb_Message_GetScalarValue(self, field); | 
|  | } | 
|  | } | 
|  |  | 
|  | int PyUpb_Message_SetFieldValue(PyObject* _self, const upb_FieldDef* field, | 
|  | PyObject* value, PyObject* exc) { | 
|  | PyUpb_Message* self = (void*)_self; | 
|  | assert(value); | 
|  |  | 
|  | if (upb_FieldDef_IsSubMessage(field) || upb_FieldDef_IsRepeated(field)) { | 
|  | PyErr_Format(exc, | 
|  | "Assignment not allowed to message, map, or repeated " | 
|  | "field \"%s\" in protocol message object.", | 
|  | upb_FieldDef_Name(field)); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | PyUpb_Message_EnsureReified(self); | 
|  |  | 
|  | upb_MessageValue val; | 
|  | upb_Arena* arena = PyUpb_Arena_Get(self->arena); | 
|  | if (!PyUpb_PyToUpb(value, field, &val, arena)) { | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | upb_Message_SetFieldByDef(self->ptr.msg, field, val, arena); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int PyUpb_Message_GetVersion(PyObject* _self) { | 
|  | PyUpb_Message* self = (void*)_self; | 
|  | return self->version; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * PyUpb_Message_GetAttr() | 
|  | * | 
|  | * Implements: | 
|  | *   foo = msg.foo | 
|  | * | 
|  | * Attribute lookup must find both message fields and base class methods like | 
|  | * msg.SerializeToString(). | 
|  | */ | 
|  | __attribute__((flatten)) static PyObject* PyUpb_Message_GetAttr( | 
|  | PyObject* _self, PyObject* attr) { | 
|  | PyUpb_Message* self = (void*)_self; | 
|  |  | 
|  | // Lookup field by name. | 
|  | const upb_FieldDef* field; | 
|  | if (PyUpb_Message_LookupName(self, attr, &field, NULL, NULL)) { | 
|  | return PyUpb_Message_GetFieldValue(_self, field); | 
|  | } | 
|  |  | 
|  | // Check base class attributes. | 
|  | assert(!PyErr_Occurred()); | 
|  | PyObject* ret = PyObject_GenericGetAttr(_self, attr); | 
|  | if (ret) return ret; | 
|  |  | 
|  | // Swallow AttributeError if it occurred and try again on the metaclass | 
|  | // to pick up class attributes.  But we have to special-case "Extensions" | 
|  | // which affirmatively returns AttributeError when a message is not | 
|  | // extendable. | 
|  | const char* name; | 
|  | if (PyErr_ExceptionMatches(PyExc_AttributeError) && | 
|  | (name = PyUpb_GetStrData(attr)) && strcmp(name, "Extensions") != 0) { | 
|  | PyErr_Clear(); | 
|  | return PyUpb_MessageMeta_GetAttr((PyObject*)Py_TYPE(_self), attr); | 
|  | } | 
|  |  | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * PyUpb_Message_SetAttr() | 
|  | * | 
|  | * Implements: | 
|  | *   msg.foo = foo | 
|  | */ | 
|  | static int PyUpb_Message_SetAttr(PyObject* _self, PyObject* attr, | 
|  | PyObject* value) { | 
|  | PyUpb_Message* self = (void*)_self; | 
|  |  | 
|  | if (value == NULL) { | 
|  | PyErr_SetString(PyExc_AttributeError, "Cannot delete field attribute"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | const upb_FieldDef* field; | 
|  | if (!PyUpb_Message_LookupName(self, attr, &field, NULL, | 
|  | PyExc_AttributeError)) { | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | return PyUpb_Message_SetFieldValue(_self, field, value, PyExc_AttributeError); | 
|  | } | 
|  |  | 
|  | static PyObject* PyUpb_Message_HasField(PyObject* _self, PyObject* arg) { | 
|  | PyUpb_Message* self = (void*)_self; | 
|  | const upb_FieldDef* field; | 
|  | const upb_OneofDef* oneof; | 
|  |  | 
|  | if (!PyUpb_Message_LookupName(self, arg, &field, &oneof, PyExc_ValueError)) { | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | if (field && !upb_FieldDef_HasPresence(field)) { | 
|  | PyErr_Format(PyExc_ValueError, "Field %s does not have presence.", | 
|  | upb_FieldDef_FullName(field)); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | if (PyUpb_Message_IsStub(self)) Py_RETURN_FALSE; | 
|  |  | 
|  | return PyBool_FromLong(field ? upb_Message_HasFieldByDef(self->ptr.msg, field) | 
|  | : upb_Message_WhichOneof(self->ptr.msg, oneof) != | 
|  | NULL); | 
|  | } | 
|  |  | 
|  | static PyObject* PyUpb_Message_FindInitializationErrors(PyObject* _self, | 
|  | PyObject* arg); | 
|  |  | 
|  | static PyObject* PyUpb_Message_IsInitializedAppendErrors(PyObject* _self, | 
|  | PyObject* errors) { | 
|  | PyObject* list = PyUpb_Message_FindInitializationErrors(_self, NULL); | 
|  | if (!list) return NULL; | 
|  | bool ok = PyList_Size(list) == 0; | 
|  | PyObject* ret = NULL; | 
|  | PyObject* extend_result = NULL; | 
|  | if (!ok) { | 
|  | extend_result = PyObject_CallMethod(errors, "extend", "O", list); | 
|  | if (!extend_result) goto done; | 
|  | } | 
|  | ret = PyBool_FromLong(ok); | 
|  |  | 
|  | done: | 
|  | Py_XDECREF(list); | 
|  | Py_XDECREF(extend_result); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static PyObject* PyUpb_Message_IsInitialized(PyObject* _self, PyObject* args) { | 
|  | PyObject* errors = NULL; | 
|  | if (!PyArg_ParseTuple(args, "|O", &errors)) { | 
|  | return NULL; | 
|  | } | 
|  | if (errors) { | 
|  | // We need to collect a list of unset required fields and append it to | 
|  | // `errors`. | 
|  | return PyUpb_Message_IsInitializedAppendErrors(_self, errors); | 
|  | } else { | 
|  | // We just need to return a boolean "true" or "false" for whether all | 
|  | // required fields are set. | 
|  | upb_Message* msg = PyUpb_Message_GetIfReified(_self); | 
|  | const upb_MessageDef* m = PyUpb_Message_GetMsgdef(_self); | 
|  | const upb_DefPool* symtab = upb_FileDef_Pool(upb_MessageDef_File(m)); | 
|  | bool initialized = !upb_util_HasUnsetRequired(msg, m, symtab, NULL); | 
|  | return PyBool_FromLong(initialized); | 
|  | } | 
|  | } | 
|  |  | 
|  | static PyObject* PyUpb_Message_ListFieldsItemKey(PyObject* self, | 
|  | PyObject* val) { | 
|  | assert(PyTuple_Check(val)); | 
|  | PyObject* field = PyTuple_GetItem(val, 0); | 
|  | const upb_FieldDef* f = PyUpb_FieldDescriptor_GetDef(field); | 
|  | return PyLong_FromLong(upb_FieldDef_Number(f)); | 
|  | } | 
|  |  | 
|  | static PyObject* PyUpb_Message_CheckCalledFromGeneratedFile( | 
|  | PyObject* unused, PyObject* unused_arg) { | 
|  | PyErr_SetString( | 
|  | PyExc_TypeError, | 
|  | "Descriptors cannot be created directly.\n" | 
|  | "If this call came from a _pb2.py file, your generated code is out of " | 
|  | "date and must be regenerated with protoc >= 3.19.0.\n" | 
|  | "If you cannot immediately regenerate your protos, some other possible " | 
|  | "workarounds are:\n" | 
|  | " 1. Downgrade the protobuf package to 3.20.x or lower.\n" | 
|  | " 2. Set PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python (but this will " | 
|  | "use pure-Python parsing and will be much slower).\n" | 
|  | "\n" | 
|  | "More information: " | 
|  | "https://developers.google.com/protocol-buffers/docs/news/" | 
|  | "2022-05-06#python-updates"); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | static bool PyUpb_Message_SortFieldList(PyObject* list) { | 
|  | PyUpb_ModuleState* state = PyUpb_ModuleState_Get(); | 
|  | bool ok = false; | 
|  | PyObject* args = PyTuple_New(0); | 
|  | PyObject* kwargs = PyDict_New(); | 
|  | PyObject* method = PyObject_GetAttrString(list, "sort"); | 
|  | PyObject* call_result = NULL; | 
|  | if (!args || !kwargs || !method) goto err; | 
|  | if (PyDict_SetItemString(kwargs, "key", state->listfields_item_key) < 0) { | 
|  | goto err; | 
|  | } | 
|  | call_result = PyObject_Call(method, args, kwargs); | 
|  | if (!call_result) goto err; | 
|  | ok = true; | 
|  |  | 
|  | err: | 
|  | Py_XDECREF(method); | 
|  | Py_XDECREF(args); | 
|  | Py_XDECREF(kwargs); | 
|  | Py_XDECREF(call_result); | 
|  | return ok; | 
|  | } | 
|  |  | 
|  | static PyObject* PyUpb_Message_ListFields(PyObject* _self, PyObject* arg) { | 
|  | PyObject* list = PyList_New(0); | 
|  | upb_Message* msg = PyUpb_Message_GetIfReified(_self); | 
|  | if (!msg) return list; | 
|  |  | 
|  | size_t iter1 = kUpb_Message_Begin; | 
|  | const upb_MessageDef* m = PyUpb_Message_GetMsgdef(_self); | 
|  | const upb_DefPool* symtab = upb_FileDef_Pool(upb_MessageDef_File(m)); | 
|  | const upb_FieldDef* f; | 
|  | PyObject* field_desc = NULL; | 
|  | PyObject* py_val = NULL; | 
|  | PyObject* tuple = NULL; | 
|  | upb_MessageValue val; | 
|  | uint32_t last_field = 0; | 
|  | bool in_order = true; | 
|  | while (upb_Message_Next(msg, m, symtab, &f, &val, &iter1)) { | 
|  | const uint32_t field_number = upb_FieldDef_Number(f); | 
|  | if (field_number < last_field) in_order = false; | 
|  | last_field = field_number; | 
|  | PyObject* field_desc = PyUpb_FieldDescriptor_Get(f); | 
|  | PyObject* py_val = PyUpb_Message_GetFieldValue(_self, f); | 
|  | if (!field_desc || !py_val) goto err; | 
|  | PyObject* tuple = Py_BuildValue("(NN)", field_desc, py_val); | 
|  | field_desc = NULL; | 
|  | py_val = NULL; | 
|  | if (!tuple) goto err; | 
|  | if (PyList_Append(list, tuple)) goto err; | 
|  | Py_DECREF(tuple); | 
|  | tuple = NULL; | 
|  | } | 
|  |  | 
|  | // Users rely on fields being returned in field number order. | 
|  | if (!in_order && !PyUpb_Message_SortFieldList(list)) goto err; | 
|  |  | 
|  | return list; | 
|  |  | 
|  | err: | 
|  | Py_XDECREF(field_desc); | 
|  | Py_XDECREF(py_val); | 
|  | Py_XDECREF(tuple); | 
|  | Py_DECREF(list); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | PyObject* PyUpb_Message_MergeFrom(PyObject* self, PyObject* arg) { | 
|  | if (self->ob_type != arg->ob_type) { | 
|  | PyErr_Format(PyExc_TypeError, | 
|  | "Parameter to MergeFrom() must be instance of same class: " | 
|  | "expected %S got %S.", | 
|  | Py_TYPE(self), Py_TYPE(arg)); | 
|  | return NULL; | 
|  | } | 
|  | // OPT: exit if src is empty. | 
|  | PyObject* subargs = PyTuple_New(0); | 
|  | PyObject* serialized = | 
|  | PyUpb_Message_SerializePartialToString(arg, subargs, NULL); | 
|  | Py_DECREF(subargs); | 
|  | if (!serialized) return NULL; | 
|  | PyObject* ret = PyUpb_Message_MergeFromString(self, serialized); | 
|  | Py_DECREF(serialized); | 
|  | Py_XDECREF(ret); | 
|  | Py_RETURN_NONE; | 
|  | } | 
|  |  | 
|  | static PyObject* PyUpb_Message_Clear(PyUpb_Message* self); | 
|  |  | 
|  | static PyObject* PyUpb_Message_CopyFrom(PyObject* _self, PyObject* arg) { | 
|  | if (_self->ob_type != arg->ob_type) { | 
|  | PyErr_Format(PyExc_TypeError, | 
|  | "Parameter to CopyFrom() must be instance of same class: " | 
|  | "expected %S got %S.", | 
|  | Py_TYPE(_self), Py_TYPE(arg)); | 
|  | return NULL; | 
|  | } | 
|  | if (_self == arg) { | 
|  | Py_RETURN_NONE; | 
|  | } | 
|  | PyUpb_Message* self = (void*)_self; | 
|  | PyUpb_Message* other = (void*)arg; | 
|  | PyUpb_Message_EnsureReified(self); | 
|  |  | 
|  | const upb_Message* other_msg = PyUpb_Message_GetIfReified((PyObject*)other); | 
|  | if (other_msg) { | 
|  | upb_Message_DeepCopy( | 
|  | self->ptr.msg, other_msg, | 
|  | upb_MessageDef_MiniTable((const upb_MessageDef*)other->def), | 
|  | PyUpb_Arena_Get(self->arena)); | 
|  | } else { | 
|  | PyObject* tmp = PyUpb_Message_Clear(self); | 
|  | Py_DECREF(tmp); | 
|  | } | 
|  | PyUpb_Message_SyncSubobjs(self); | 
|  |  | 
|  | Py_RETURN_NONE; | 
|  | } | 
|  |  | 
|  | static PyObject* PyUpb_Message_SetInParent(PyObject* _self, PyObject* arg) { | 
|  | PyUpb_Message* self = (void*)_self; | 
|  | PyUpb_Message_EnsureReified(self); | 
|  | Py_RETURN_NONE; | 
|  | } | 
|  |  | 
|  | static PyObject* PyUpb_Message_UnknownFields(PyObject* _self, PyObject* arg) { | 
|  | // TODO: re-enable when unknown fields are added. | 
|  | // return PyUpb_UnknownFields_New(_self); | 
|  | PyErr_SetString(PyExc_NotImplementedError, "unknown field accessor"); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | PyObject* PyUpb_Message_MergeFromString(PyObject* _self, PyObject* arg) { | 
|  | PyUpb_Message* self = (void*)_self; | 
|  | char* buf; | 
|  | Py_ssize_t size; | 
|  | PyObject* bytes = NULL; | 
|  |  | 
|  | if (PyMemoryView_Check(arg)) { | 
|  | bytes = PyBytes_FromObject(arg); | 
|  | // Cannot fail when passed something of the correct type. | 
|  | int err = PyBytes_AsStringAndSize(bytes, &buf, &size); | 
|  | (void)err; | 
|  | assert(err >= 0); | 
|  | } else if (PyBytes_AsStringAndSize(arg, &buf, &size) < 0) { | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | PyUpb_Message_EnsureReified(self); | 
|  | const upb_MessageDef* msgdef = _PyUpb_Message_GetMsgdef(self); | 
|  | const upb_FileDef* file = upb_MessageDef_File(msgdef); | 
|  | const upb_ExtensionRegistry* extreg = | 
|  | upb_DefPool_ExtensionRegistry(upb_FileDef_Pool(file)); | 
|  | const upb_MiniTable* layout = upb_MessageDef_MiniTable(msgdef); | 
|  | upb_Arena* arena = PyUpb_Arena_Get(self->arena); | 
|  | PyUpb_ModuleState* state = PyUpb_ModuleState_Get(); | 
|  | int options = | 
|  | upb_DecodeOptions_MaxDepth(state->allow_oversize_protos ? UINT16_MAX : 0); | 
|  | upb_DecodeStatus status = | 
|  | upb_Decode(buf, size, self->ptr.msg, layout, extreg, options, arena); | 
|  | Py_XDECREF(bytes); | 
|  | if (status != kUpb_DecodeStatus_Ok) { | 
|  | PyErr_Format(state->decode_error_class, "Error parsing message"); | 
|  | return NULL; | 
|  | } | 
|  | PyUpb_Message_SyncSubobjs(self); | 
|  | return PyLong_FromSsize_t(size); | 
|  | } | 
|  |  | 
|  | static PyObject* PyUpb_Message_ParseFromString(PyObject* self, PyObject* arg) { | 
|  | PyObject* tmp = PyUpb_Message_Clear((PyUpb_Message*)self); | 
|  | Py_DECREF(tmp); | 
|  | return PyUpb_Message_MergeFromString(self, arg); | 
|  | } | 
|  |  | 
|  | static PyObject* PyUpb_Message_ByteSize(PyObject* self, PyObject* args) { | 
|  | // TODO: At the | 
|  | // moment upb does not have a "byte size" function, so we just serialize to | 
|  | // string and get the size of the string. | 
|  | PyObject* subargs = PyTuple_New(0); | 
|  | PyObject* serialized = PyUpb_Message_SerializeToString(self, subargs, NULL); | 
|  | Py_DECREF(subargs); | 
|  | if (!serialized) return NULL; | 
|  | size_t size = PyBytes_Size(serialized); | 
|  | Py_DECREF(serialized); | 
|  | return PyLong_FromSize_t(size); | 
|  | } | 
|  |  | 
|  | static PyObject* PyUpb_Message_Clear(PyUpb_Message* self) { | 
|  | PyUpb_Message_EnsureReified(self); | 
|  | const upb_MessageDef* msgdef = _PyUpb_Message_GetMsgdef(self); | 
|  | PyUpb_WeakMap* subobj_map = self->unset_subobj_map; | 
|  |  | 
|  | if (subobj_map) { | 
|  | upb_Message* msg = PyUpb_Message_GetMsg(self); | 
|  | (void)msg;  // Suppress unused warning when asserts are disabled. | 
|  | intptr_t iter = PYUPB_WEAKMAP_BEGIN; | 
|  | const void* key; | 
|  | PyObject* obj; | 
|  |  | 
|  | while (PyUpb_WeakMap_Next(subobj_map, &key, &obj, &iter)) { | 
|  | const upb_FieldDef* f = key; | 
|  | PyUpb_WeakMap_DeleteIter(subobj_map, &iter); | 
|  | if (upb_FieldDef_IsMap(f)) { | 
|  | assert(upb_Message_GetFieldByDef(msg, f).map_val == NULL); | 
|  | PyUpb_MapContainer_Reify(obj, NULL); | 
|  | } else if (upb_FieldDef_IsRepeated(f)) { | 
|  | assert(upb_Message_GetFieldByDef(msg, f).array_val == NULL); | 
|  | PyUpb_RepeatedContainer_Reify(obj, NULL); | 
|  | } else { | 
|  | assert(!upb_Message_HasFieldByDef(msg, f)); | 
|  | PyUpb_Message* sub = (void*)obj; | 
|  | assert(self == sub->ptr.parent); | 
|  | PyUpb_Message_Reify(sub, f, NULL); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | upb_Message_ClearByDef(self->ptr.msg, msgdef); | 
|  | Py_RETURN_NONE; | 
|  | } | 
|  |  | 
|  | void PyUpb_Message_DoClearField(PyObject* _self, const upb_FieldDef* f) { | 
|  | PyUpb_Message* self = (void*)_self; | 
|  | PyUpb_Message_EnsureReified((PyUpb_Message*)self); | 
|  |  | 
|  | // We must ensure that any stub object is reified so its parent no longer | 
|  | // points to us. | 
|  | PyObject* sub = self->unset_subobj_map | 
|  | ? PyUpb_WeakMap_Get(self->unset_subobj_map, f) | 
|  | : NULL; | 
|  |  | 
|  | if (upb_FieldDef_IsMap(f)) { | 
|  | // For maps we additionally have to invalidate any iterators.  So we need | 
|  | // to get an object even if it's reified. | 
|  | if (!sub) { | 
|  | sub = PyUpb_Message_GetFieldValue(_self, f); | 
|  | } | 
|  | PyUpb_MapContainer_EnsureReified(sub); | 
|  | PyUpb_MapContainer_Invalidate(sub); | 
|  | } else if (upb_FieldDef_IsRepeated(f)) { | 
|  | if (sub) { | 
|  | PyUpb_RepeatedContainer_EnsureReified(sub); | 
|  | } | 
|  | } else if (upb_FieldDef_IsSubMessage(f)) { | 
|  | if (sub) { | 
|  | PyUpb_Message_EnsureReified((PyUpb_Message*)sub); | 
|  | } | 
|  | } | 
|  |  | 
|  | Py_XDECREF(sub); | 
|  | upb_Message_ClearFieldByDef(self->ptr.msg, f); | 
|  | } | 
|  |  | 
|  | static PyObject* PyUpb_Message_ClearExtension(PyObject* _self, PyObject* arg) { | 
|  | PyUpb_Message* self = (void*)_self; | 
|  | PyUpb_Message_EnsureReified(self); | 
|  | const upb_FieldDef* f = PyUpb_Message_GetExtensionDef(_self, arg); | 
|  | if (!f) return NULL; | 
|  | PyUpb_Message_DoClearField(_self, f); | 
|  | Py_RETURN_NONE; | 
|  | } | 
|  |  | 
|  | static PyObject* PyUpb_Message_ClearField(PyObject* _self, PyObject* arg) { | 
|  | PyUpb_Message* self = (void*)_self; | 
|  |  | 
|  | // We always need EnsureReified() here (even for an unset message) to | 
|  | // preserve behavior like: | 
|  | //   msg = FooMessage() | 
|  | //   msg.foo.Clear() | 
|  | //   assert msg.HasField("foo") | 
|  | PyUpb_Message_EnsureReified(self); | 
|  |  | 
|  | const upb_FieldDef* f; | 
|  | const upb_OneofDef* o; | 
|  | if (!PyUpb_Message_LookupName(self, arg, &f, &o, PyExc_ValueError)) { | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | if (o) f = upb_Message_WhichOneof(self->ptr.msg, o); | 
|  | if (f) PyUpb_Message_DoClearField(_self, f); | 
|  | Py_RETURN_NONE; | 
|  | } | 
|  |  | 
|  | static PyObject* PyUpb_Message_DiscardUnknownFields(PyUpb_Message* self, | 
|  | PyObject* arg) { | 
|  | PyUpb_Message_EnsureReified(self); | 
|  | const upb_MessageDef* msgdef = _PyUpb_Message_GetMsgdef(self); | 
|  | upb_Message_DiscardUnknown(self->ptr.msg, msgdef, 64); | 
|  | Py_RETURN_NONE; | 
|  | } | 
|  |  | 
|  | static PyObject* PyUpb_Message_FindInitializationErrors(PyObject* _self, | 
|  | PyObject* arg) { | 
|  | PyUpb_Message* self = (void*)_self; | 
|  | upb_Message* msg = PyUpb_Message_GetIfReified(_self); | 
|  | const upb_MessageDef* msgdef = _PyUpb_Message_GetMsgdef(self); | 
|  | const upb_DefPool* ext_pool = upb_FileDef_Pool(upb_MessageDef_File(msgdef)); | 
|  | upb_FieldPathEntry* fields_base; | 
|  | PyObject* ret = PyList_New(0); | 
|  | if (upb_util_HasUnsetRequired(msg, msgdef, ext_pool, &fields_base)) { | 
|  | upb_FieldPathEntry* fields = fields_base; | 
|  | char* buf = NULL; | 
|  | size_t size = 0; | 
|  | assert(fields->field); | 
|  | while (fields->field) { | 
|  | upb_FieldPathEntry* field = fields; | 
|  | size_t need = upb_FieldPath_ToText(&fields, buf, size); | 
|  | if (need >= size) { | 
|  | fields = field; | 
|  | size = size ? size * 2 : 16; | 
|  | while (size <= need) size *= 2; | 
|  | buf = realloc(buf, size); | 
|  | need = upb_FieldPath_ToText(&fields, buf, size); | 
|  | assert(size > need); | 
|  | } | 
|  | PyObject* str = PyUnicode_FromString(buf); | 
|  | PyList_Append(ret, str); | 
|  | Py_DECREF(str); | 
|  | } | 
|  | free(buf); | 
|  | free(fields_base); | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static PyObject* PyUpb_Message_FromString(PyObject* cls, PyObject* serialized) { | 
|  | PyObject* ret = NULL; | 
|  | PyObject* length = NULL; | 
|  |  | 
|  | ret = PyObject_CallObject(cls, NULL); | 
|  | if (ret == NULL) goto err; | 
|  | length = PyUpb_Message_MergeFromString(ret, serialized); | 
|  | if (length == NULL) goto err; | 
|  |  | 
|  | done: | 
|  | Py_XDECREF(length); | 
|  | return ret; | 
|  |  | 
|  | err: | 
|  | Py_XDECREF(ret); | 
|  | ret = NULL; | 
|  | goto done; | 
|  | } | 
|  |  | 
|  | const upb_FieldDef* PyUpb_Message_GetExtensionDef(PyObject* _self, | 
|  | PyObject* key) { | 
|  | const upb_FieldDef* f = PyUpb_FieldDescriptor_GetDef(key); | 
|  | if (!f) { | 
|  | PyErr_Clear(); | 
|  | PyErr_Format(PyExc_KeyError, "Object %R is not a field descriptor\n", key); | 
|  | return NULL; | 
|  | } | 
|  | if (!upb_FieldDef_IsExtension(f)) { | 
|  | PyErr_Format(PyExc_KeyError, "Field %s is not an extension\n", | 
|  | upb_FieldDef_FullName(f)); | 
|  | return NULL; | 
|  | } | 
|  | const upb_MessageDef* msgdef = PyUpb_Message_GetMsgdef(_self); | 
|  | if (upb_FieldDef_ContainingType(f) != msgdef) { | 
|  | PyErr_Format(PyExc_KeyError, "Extension doesn't match (%s vs %s)", | 
|  | upb_MessageDef_FullName(msgdef), upb_FieldDef_FullName(f)); | 
|  | return NULL; | 
|  | } | 
|  | return f; | 
|  | } | 
|  |  | 
|  | static PyObject* PyUpb_Message_HasExtension(PyObject* _self, | 
|  | PyObject* ext_desc) { | 
|  | upb_Message* msg = PyUpb_Message_GetIfReified(_self); | 
|  | const upb_FieldDef* f = PyUpb_Message_GetExtensionDef(_self, ext_desc); | 
|  | if (!f) return NULL; | 
|  | if (upb_FieldDef_IsRepeated(f)) { | 
|  | PyErr_SetString(PyExc_KeyError, | 
|  | "Field is repeated. A singular method is required."); | 
|  | return NULL; | 
|  | } | 
|  | if (!msg) Py_RETURN_FALSE; | 
|  | return PyBool_FromLong(upb_Message_HasFieldByDef(msg, f)); | 
|  | } | 
|  |  | 
|  | void PyUpb_Message_ReportInitializationErrors(const upb_MessageDef* msgdef, | 
|  | PyObject* errors, PyObject* exc) { | 
|  | PyObject* comma = PyUnicode_FromString(","); | 
|  | PyObject* missing_fields = NULL; | 
|  | if (!comma) goto done; | 
|  | missing_fields = PyUnicode_Join(comma, errors); | 
|  | if (!missing_fields) goto done; | 
|  | PyErr_Format(exc, "Message %s is missing required fields: %U", | 
|  | upb_MessageDef_FullName(msgdef), missing_fields); | 
|  | done: | 
|  | Py_XDECREF(comma); | 
|  | Py_XDECREF(missing_fields); | 
|  | Py_DECREF(errors); | 
|  | } | 
|  |  | 
|  | PyObject* PyUpb_Message_SerializeInternal(PyObject* _self, PyObject* args, | 
|  | PyObject* kwargs, | 
|  | bool check_required) { | 
|  | PyUpb_Message* self = (void*)_self; | 
|  | if (!PyUpb_Message_Verify((PyObject*)self)) return NULL; | 
|  | static const char* kwlist[] = {"deterministic", NULL}; | 
|  | int deterministic = 0; | 
|  | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|p", (char**)(kwlist), | 
|  | &deterministic)) { | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | const upb_MessageDef* msgdef = _PyUpb_Message_GetMsgdef(self); | 
|  | if (PyUpb_Message_IsStub(self)) { | 
|  | // Nothing to serialize, but we do have to check whether the message is | 
|  | // initialized. | 
|  | PyUpb_ModuleState* state = PyUpb_ModuleState_Get(); | 
|  | PyObject* errors = PyUpb_Message_FindInitializationErrors(_self, NULL); | 
|  | if (!errors) return NULL; | 
|  | if (PyList_Size(errors) == 0) { | 
|  | Py_DECREF(errors); | 
|  | return PyBytes_FromStringAndSize(NULL, 0); | 
|  | } | 
|  | PyUpb_Message_ReportInitializationErrors(msgdef, errors, | 
|  | state->encode_error_class); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | upb_Arena* arena = upb_Arena_New(); | 
|  | const upb_MiniTable* layout = upb_MessageDef_MiniTable(msgdef); | 
|  | size_t size = 0; | 
|  | // Python does not currently have any effective limit on serialization depth. | 
|  | int options = upb_EncodeOptions_MaxDepth(UINT16_MAX); | 
|  | if (check_required) options |= kUpb_EncodeOption_CheckRequired; | 
|  | if (deterministic) options |= kUpb_EncodeOption_Deterministic; | 
|  | char* pb; | 
|  | upb_EncodeStatus status = | 
|  | upb_Encode(self->ptr.msg, layout, options, arena, &pb, &size); | 
|  | PyObject* ret = NULL; | 
|  |  | 
|  | if (status != kUpb_EncodeStatus_Ok) { | 
|  | PyUpb_ModuleState* state = PyUpb_ModuleState_Get(); | 
|  | PyObject* errors = PyUpb_Message_FindInitializationErrors(_self, NULL); | 
|  | if (PyList_Size(errors) != 0) { | 
|  | PyUpb_Message_ReportInitializationErrors(msgdef, errors, | 
|  | state->encode_error_class); | 
|  | } else { | 
|  | PyErr_Format(state->encode_error_class, "Failed to serialize proto"); | 
|  | } | 
|  | goto done; | 
|  | } | 
|  |  | 
|  | ret = PyBytes_FromStringAndSize(pb, size); | 
|  |  | 
|  | done: | 
|  | upb_Arena_Free(arena); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | PyObject* PyUpb_Message_SerializeToString(PyObject* _self, PyObject* args, | 
|  | PyObject* kwargs) { | 
|  | return PyUpb_Message_SerializeInternal(_self, args, kwargs, true); | 
|  | } | 
|  |  | 
|  | PyObject* PyUpb_Message_SerializePartialToString(PyObject* _self, | 
|  | PyObject* args, | 
|  | PyObject* kwargs) { | 
|  | return PyUpb_Message_SerializeInternal(_self, args, kwargs, false); | 
|  | } | 
|  |  | 
|  | static PyObject* PyUpb_Message_WhichOneof(PyObject* _self, PyObject* name) { | 
|  | PyUpb_Message* self = (void*)_self; | 
|  | const upb_OneofDef* o; | 
|  | if (!PyUpb_Message_LookupName(self, name, NULL, &o, PyExc_ValueError)) { | 
|  | return NULL; | 
|  | } | 
|  | upb_Message* msg = PyUpb_Message_GetIfReified(_self); | 
|  | if (!msg) Py_RETURN_NONE; | 
|  | const upb_FieldDef* f = upb_Message_WhichOneof(msg, o); | 
|  | if (!f) Py_RETURN_NONE; | 
|  | return PyUnicode_FromString(upb_FieldDef_Name(f)); | 
|  | } | 
|  |  | 
|  | PyObject* DeepCopy(PyObject* _self, PyObject* arg) { | 
|  | const upb_MessageDef* def = PyUpb_Message_GetMsgdef(_self); | 
|  | const upb_MiniTable* mini_table = upb_MessageDef_MiniTable(def); | 
|  | upb_Message* msg = PyUpb_Message_GetIfReified(_self); | 
|  | PyObject* arena = PyUpb_Arena_New(); | 
|  | upb_Arena* upb_arena = PyUpb_Arena_Get(arena); | 
|  |  | 
|  | upb_Message* clone = msg ? upb_Message_DeepClone(msg, mini_table, upb_arena) | 
|  | : upb_Message_New(mini_table, upb_arena); | 
|  | PyObject* ret = PyUpb_Message_Get(clone, def, arena); | 
|  | Py_DECREF(arena); | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | void PyUpb_Message_ClearExtensionDict(PyObject* _self) { | 
|  | PyUpb_Message* self = (void*)_self; | 
|  | assert(self->ext_dict); | 
|  | self->ext_dict = NULL; | 
|  | } | 
|  |  | 
|  | static PyObject* PyUpb_Message_GetExtensionDict(PyObject* _self, | 
|  | void* closure) { | 
|  | PyUpb_Message* self = (void*)_self; | 
|  | if (self->ext_dict) { | 
|  | Py_INCREF(self->ext_dict); | 
|  | return self->ext_dict; | 
|  | } | 
|  |  | 
|  | const upb_MessageDef* m = _PyUpb_Message_GetMsgdef(self); | 
|  | if (upb_MessageDef_ExtensionRangeCount(m) == 0) { | 
|  | PyErr_SetNone(PyExc_AttributeError); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | self->ext_dict = PyUpb_ExtensionDict_New(_self); | 
|  | return self->ext_dict; | 
|  | } | 
|  |  | 
|  | static PyGetSetDef PyUpb_Message_Getters[] = { | 
|  | {"Extensions", PyUpb_Message_GetExtensionDict, NULL, "Extension dict"}, | 
|  | {NULL}}; | 
|  |  | 
|  | static PyMethodDef PyUpb_Message_Methods[] = { | 
|  | {"__deepcopy__", (PyCFunction)DeepCopy, METH_VARARGS, | 
|  | "Makes a deep copy of the class."}, | 
|  | // TODO | 
|  | //{ "__unicode__", (PyCFunction)ToUnicode, METH_NOARGS, | 
|  | //  "Outputs a unicode representation of the message." }, | 
|  | {"ByteSize", (PyCFunction)PyUpb_Message_ByteSize, METH_NOARGS, | 
|  | "Returns the size of the message in bytes."}, | 
|  | {"Clear", (PyCFunction)PyUpb_Message_Clear, METH_NOARGS, | 
|  | "Clears the message."}, | 
|  | {"ClearExtension", PyUpb_Message_ClearExtension, METH_O, | 
|  | "Clears a message field."}, | 
|  | {"ClearField", PyUpb_Message_ClearField, METH_O, "Clears a message field."}, | 
|  | {"CopyFrom", PyUpb_Message_CopyFrom, METH_O, | 
|  | "Copies a protocol message into the current message."}, | 
|  | {"DiscardUnknownFields", (PyCFunction)PyUpb_Message_DiscardUnknownFields, | 
|  | METH_NOARGS, "Discards the unknown fields."}, | 
|  | {"FindInitializationErrors", PyUpb_Message_FindInitializationErrors, | 
|  | METH_NOARGS, "Finds unset required fields."}, | 
|  | {"FromString", PyUpb_Message_FromString, METH_O | METH_CLASS, | 
|  | "Creates new method instance from given serialized data."}, | 
|  | {"HasExtension", PyUpb_Message_HasExtension, METH_O, | 
|  | "Checks if a message field is set."}, | 
|  | {"HasField", PyUpb_Message_HasField, METH_O, | 
|  | "Checks if a message field is set."}, | 
|  | {"IsInitialized", PyUpb_Message_IsInitialized, METH_VARARGS, | 
|  | "Checks if all required fields of a protocol message are set."}, | 
|  | {"ListFields", PyUpb_Message_ListFields, METH_NOARGS, | 
|  | "Lists all set fields of a message."}, | 
|  | {"MergeFrom", PyUpb_Message_MergeFrom, METH_O, | 
|  | "Merges a protocol message into the current message."}, | 
|  | {"MergeFromString", PyUpb_Message_MergeFromString, METH_O, | 
|  | "Merges a serialized message into the current message."}, | 
|  | {"ParseFromString", PyUpb_Message_ParseFromString, METH_O, | 
|  | "Parses a serialized message into the current message."}, | 
|  | {"SerializePartialToString", | 
|  | (PyCFunction)PyUpb_Message_SerializePartialToString, | 
|  | METH_VARARGS | METH_KEYWORDS, | 
|  | "Serializes the message to a string, even if it isn't initialized."}, | 
|  | {"SerializeToString", (PyCFunction)PyUpb_Message_SerializeToString, | 
|  | METH_VARARGS | METH_KEYWORDS, | 
|  | "Serializes the message to a string, only for initialized messages."}, | 
|  | {"SetInParent", (PyCFunction)PyUpb_Message_SetInParent, METH_NOARGS, | 
|  | "Sets the has bit of the given field in its parent message."}, | 
|  | {"UnknownFields", (PyCFunction)PyUpb_Message_UnknownFields, METH_NOARGS, | 
|  | "Parse unknown field set"}, | 
|  | {"WhichOneof", PyUpb_Message_WhichOneof, METH_O, | 
|  | "Returns the name of the field set inside a oneof, " | 
|  | "or None if no field is set."}, | 
|  | {"_ListFieldsItemKey", PyUpb_Message_ListFieldsItemKey, | 
|  | METH_O | METH_STATIC, | 
|  | "Compares ListFields() list entries by field number"}, | 
|  | {"_CheckCalledFromGeneratedFile", | 
|  | PyUpb_Message_CheckCalledFromGeneratedFile, METH_NOARGS | METH_STATIC, | 
|  | "Raises TypeError if the caller is not in a _pb2.py file."}, | 
|  | {NULL, NULL}}; | 
|  |  | 
|  | static PyType_Slot PyUpb_Message_Slots[] = { | 
|  | {Py_tp_dealloc, PyUpb_Message_Dealloc}, | 
|  | {Py_tp_doc, "A ProtocolMessage"}, | 
|  | {Py_tp_getattro, PyUpb_Message_GetAttr}, | 
|  | {Py_tp_getset, PyUpb_Message_Getters}, | 
|  | {Py_tp_hash, PyObject_HashNotImplemented}, | 
|  | {Py_tp_methods, PyUpb_Message_Methods}, | 
|  | {Py_tp_new, PyUpb_Message_New}, | 
|  | {Py_tp_str, PyUpb_Message_ToString}, | 
|  | {Py_tp_repr, PyUpb_Message_ToString}, | 
|  | {Py_tp_richcompare, PyUpb_Message_RichCompare}, | 
|  | {Py_tp_setattro, PyUpb_Message_SetAttr}, | 
|  | {Py_tp_init, PyUpb_Message_Init}, | 
|  | {0, NULL}}; | 
|  |  | 
|  | PyType_Spec PyUpb_Message_Spec = { | 
|  | PYUPB_MODULE_NAME ".Message",              // tp_name | 
|  | sizeof(PyUpb_Message),                     // tp_basicsize | 
|  | 0,                                         // tp_itemsize | 
|  | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  // tp_flags | 
|  | PyUpb_Message_Slots, | 
|  | }; | 
|  |  | 
|  | // ----------------------------------------------------------------------------- | 
|  | // MessageMeta | 
|  | // ----------------------------------------------------------------------------- | 
|  |  | 
|  | // MessageMeta is the metaclass for message objects.  The generated code uses it | 
|  | // to construct message classes, ie. | 
|  | // | 
|  | // FooMessage = _message.MessageMeta('FooMessage', (_message.Message), {...}) | 
|  | // | 
|  | // (This is not quite true: at the moment the Python library subclasses | 
|  | // MessageMeta, and uses that subclass as the metaclass.  There is a TODO below | 
|  | // to simplify this, so that the illustration above is indeed accurate). | 
|  |  | 
|  | typedef struct { | 
|  | const upb_MiniTable* layout; | 
|  | PyObject* py_message_descriptor; | 
|  | } PyUpb_MessageMeta; | 
|  |  | 
|  | // The PyUpb_MessageMeta struct is trailing data tacked onto the end of | 
|  | // MessageMeta instances.  This means that we get our instances of this struct | 
|  | // by adding the appropriate number of bytes. | 
|  | static PyUpb_MessageMeta* PyUpb_GetMessageMeta(PyObject* cls) { | 
|  | #ifndef NDEBUG | 
|  | PyUpb_ModuleState* state = PyUpb_ModuleState_MaybeGet(); | 
|  | assert(!state || cls->ob_type == state->message_meta_type); | 
|  | #endif | 
|  | return (PyUpb_MessageMeta*)((char*)cls + cpython_bits.type_basicsize); | 
|  | } | 
|  |  | 
|  | static const upb_MessageDef* PyUpb_MessageMeta_GetMsgdef(PyObject* cls) { | 
|  | PyUpb_MessageMeta* self = PyUpb_GetMessageMeta(cls); | 
|  | return PyUpb_Descriptor_GetDef(self->py_message_descriptor); | 
|  | } | 
|  |  | 
|  | PyObject* PyUpb_MessageMeta_DoCreateClass(PyObject* py_descriptor, | 
|  | const char* name, PyObject* dict) { | 
|  | PyUpb_ModuleState* state = PyUpb_ModuleState_Get(); | 
|  | PyTypeObject* descriptor_type = state->descriptor_types[kPyUpb_Descriptor]; | 
|  | if (!PyObject_TypeCheck(py_descriptor, descriptor_type)) { | 
|  | return PyErr_Format(PyExc_TypeError, "Expected a message Descriptor"); | 
|  | } | 
|  |  | 
|  | const upb_MessageDef* msgdef = PyUpb_Descriptor_GetDef(py_descriptor); | 
|  | assert(msgdef); | 
|  | assert(!PyUpb_ObjCache_Get(upb_MessageDef_MiniTable(msgdef))); | 
|  |  | 
|  | PyObject* slots = PyTuple_New(0); | 
|  | if (!slots) return NULL; | 
|  | int status = PyDict_SetItemString(dict, "__slots__", slots); | 
|  | Py_DECREF(slots); | 
|  | if (status < 0) return NULL; | 
|  |  | 
|  | // Bases are either: | 
|  | //    (Message, Message)            # for regular messages | 
|  | //    (Message, Message, WktBase)   # For well-known types | 
|  | PyObject* wkt_bases = PyUpb_GetWktBases(state); | 
|  | PyObject* wkt_base = | 
|  | PyDict_GetItemString(wkt_bases, upb_MessageDef_FullName(msgdef)); | 
|  | PyObject* args; | 
|  | if (wkt_base == NULL) { | 
|  | args = Py_BuildValue("s(OO)O", name, state->cmessage_type, | 
|  | state->message_class, dict); | 
|  | } else { | 
|  | args = Py_BuildValue("s(OOO)O", name, state->cmessage_type, | 
|  | state->message_class, wkt_base, dict); | 
|  | } | 
|  |  | 
|  | PyObject* ret = cpython_bits.type_new(state->message_meta_type, args, NULL); | 
|  | Py_DECREF(args); | 
|  | if (!ret) return NULL; | 
|  |  | 
|  | PyUpb_MessageMeta* meta = PyUpb_GetMessageMeta(ret); | 
|  | meta->py_message_descriptor = py_descriptor; | 
|  | meta->layout = upb_MessageDef_MiniTable(msgdef); | 
|  | Py_INCREF(meta->py_message_descriptor); | 
|  | PyUpb_Descriptor_SetClass(py_descriptor, ret); | 
|  |  | 
|  | PyUpb_ObjCache_Add(meta->layout, ret); | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static PyObject* PyUpb_MessageMeta_New(PyTypeObject* type, PyObject* args, | 
|  | PyObject* kwargs) { | 
|  | PyUpb_ModuleState* state = PyUpb_ModuleState_Get(); | 
|  | static const char* kwlist[] = {"name", "bases", "dict", 0}; | 
|  | PyObject *bases, *dict; | 
|  | const char* name; | 
|  |  | 
|  | // Check arguments: (name, bases, dict) | 
|  | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO!O!:type", (char**)kwlist, | 
|  | &name, &PyTuple_Type, &bases, &PyDict_Type, | 
|  | &dict)) { | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | // Check bases: only (), or (message.Message,) are allowed | 
|  | Py_ssize_t size = PyTuple_Size(bases); | 
|  | if (!(size == 0 || | 
|  | (size == 1 && PyTuple_GetItem(bases, 0) == state->message_class))) { | 
|  | PyErr_Format(PyExc_TypeError, | 
|  | "A Message class can only inherit from Message, not %S", | 
|  | bases); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | // Check dict['DESCRIPTOR'] | 
|  | PyObject* py_descriptor = PyDict_GetItemString(dict, "DESCRIPTOR"); | 
|  | if (py_descriptor == NULL) { | 
|  | PyErr_SetString(PyExc_TypeError, "Message class has no DESCRIPTOR"); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | const upb_MessageDef* m = PyUpb_Descriptor_GetDef(py_descriptor); | 
|  | PyObject* ret = PyUpb_ObjCache_Get(upb_MessageDef_MiniTable(m)); | 
|  | if (ret) return ret; | 
|  | return PyUpb_MessageMeta_DoCreateClass(py_descriptor, name, dict); | 
|  | } | 
|  |  | 
|  | static void PyUpb_MessageMeta_Dealloc(PyObject* self) { | 
|  | PyUpb_MessageMeta* meta = PyUpb_GetMessageMeta(self); | 
|  | PyUpb_ObjCache_Delete(meta->layout); | 
|  | // The MessageMeta type is a GC type, which means we should untrack the | 
|  | // object before invalidating internal state (so that code executed by the | 
|  | // GC doesn't see the invalid state). Unfortunately since we're calling | 
|  | // cpython_bits.type_dealloc, which also untracks the object, we can't. | 
|  | // Instead just make sure the internal state remains reasonable by using | 
|  | // Py_CLEAR(), which sets the struct member to NULL. The tp_traverse and | 
|  | // tp_clear methods, which are called by Python's GC, already allow for it | 
|  | // to be NULL. | 
|  | Py_CLEAR(meta->py_message_descriptor); | 
|  | PyTypeObject* tp = Py_TYPE(self); | 
|  | cpython_bits.type_dealloc(self); | 
|  | Py_DECREF(tp); | 
|  | } | 
|  |  | 
|  | void PyUpb_MessageMeta_AddFieldNumber(PyObject* self, const upb_FieldDef* f) { | 
|  | PyObject* name = | 
|  | PyUnicode_FromFormat("%s_FIELD_NUMBER", upb_FieldDef_Name(f)); | 
|  | PyObject* upper = PyObject_CallMethod(name, "upper", ""); | 
|  | PyObject_SetAttr(self, upper, PyLong_FromLong(upb_FieldDef_Number(f))); | 
|  | Py_DECREF(name); | 
|  | Py_DECREF(upper); | 
|  | } | 
|  |  | 
|  | static PyObject* PyUpb_MessageMeta_GetDynamicAttr(PyObject* self, | 
|  | PyObject* name) { | 
|  | const char* name_buf = PyUpb_GetStrData(name); | 
|  | if (!name_buf) return NULL; | 
|  | const upb_MessageDef* msgdef = PyUpb_MessageMeta_GetMsgdef(self); | 
|  | const upb_FileDef* filedef = upb_MessageDef_File(msgdef); | 
|  | const upb_DefPool* symtab = upb_FileDef_Pool(filedef); | 
|  |  | 
|  | PyObject* py_key = | 
|  | PyBytes_FromFormat("%s.%s", upb_MessageDef_FullName(msgdef), name_buf); | 
|  | const char* key = PyUpb_GetStrData(py_key); | 
|  | PyObject* ret = NULL; | 
|  | const upb_MessageDef* nested = upb_DefPool_FindMessageByName(symtab, key); | 
|  | const upb_EnumDef* enumdef; | 
|  | const upb_EnumValueDef* enumval; | 
|  | const upb_FieldDef* ext; | 
|  |  | 
|  | if (nested) { | 
|  | ret = PyUpb_Descriptor_GetClass(nested); | 
|  | } else if ((enumdef = upb_DefPool_FindEnumByName(symtab, key))) { | 
|  | PyUpb_ModuleState* state = PyUpb_ModuleState_Get(); | 
|  | PyObject* klass = state->enum_type_wrapper_class; | 
|  | ret = PyUpb_EnumDescriptor_Get(enumdef); | 
|  | ret = PyObject_CallFunctionObjArgs(klass, ret, NULL); | 
|  | } else if ((enumval = upb_DefPool_FindEnumByNameval(symtab, key))) { | 
|  | ret = PyLong_FromLong(upb_EnumValueDef_Number(enumval)); | 
|  | } else if ((ext = upb_DefPool_FindExtensionByName(symtab, key))) { | 
|  | ret = PyUpb_FieldDescriptor_Get(ext); | 
|  | } | 
|  |  | 
|  | Py_DECREF(py_key); | 
|  |  | 
|  | const char* suffix = "_FIELD_NUMBER"; | 
|  | size_t n = strlen(name_buf); | 
|  | size_t suffix_n = strlen(suffix); | 
|  | if (n > suffix_n && memcmp(suffix, name_buf + n - suffix_n, suffix_n) == 0) { | 
|  | // We can't look up field names dynamically, because the <NAME>_FIELD_NUMBER | 
|  | // naming scheme upper-cases the field name and is therefore non-reversible. | 
|  | // So we just add all field numbers. | 
|  | int n = upb_MessageDef_FieldCount(msgdef); | 
|  | for (int i = 0; i < n; i++) { | 
|  | PyUpb_MessageMeta_AddFieldNumber(self, upb_MessageDef_Field(msgdef, i)); | 
|  | } | 
|  | n = upb_MessageDef_NestedExtensionCount(msgdef); | 
|  | for (int i = 0; i < n; i++) { | 
|  | PyUpb_MessageMeta_AddFieldNumber( | 
|  | self, upb_MessageDef_NestedExtension(msgdef, i)); | 
|  | } | 
|  | ret = PyObject_GenericGetAttr(self, name); | 
|  | } | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static PyObject* PyUpb_MessageMeta_GetAttr(PyObject* self, PyObject* name) { | 
|  | // We want to first delegate to the type's tp_dict to retrieve any attributes | 
|  | // that were previously calculated and cached in the type's dict. | 
|  | PyObject* ret = cpython_bits.type_getattro(self, name); | 
|  | if (ret) return ret; | 
|  |  | 
|  | // We did not find a cached attribute. Try to calculate the attribute | 
|  | // dynamically, using the descriptor as an argument. | 
|  | PyErr_Clear(); | 
|  | ret = PyUpb_MessageMeta_GetDynamicAttr(self, name); | 
|  |  | 
|  | if (ret) { | 
|  | PyObject_SetAttr(self, name, ret); | 
|  | PyErr_Clear(); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | PyErr_SetObject(PyExc_AttributeError, name); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | static int PyUpb_MessageMeta_Traverse(PyObject* self, visitproc visit, | 
|  | void* arg) { | 
|  | PyUpb_MessageMeta* meta = PyUpb_GetMessageMeta(self); | 
|  | Py_VISIT(meta->py_message_descriptor); | 
|  | return cpython_bits.type_traverse(self, visit, arg); | 
|  | } | 
|  |  | 
|  | static int PyUpb_MessageMeta_Clear(PyObject* self, visitproc visit, void* arg) { | 
|  | PyUpb_MessageMeta* meta = PyUpb_GetMessageMeta(self); | 
|  | Py_CLEAR(meta->py_message_descriptor); | 
|  | return cpython_bits.type_clear(self); | 
|  | } | 
|  |  | 
|  | static PyType_Slot PyUpb_MessageMeta_Slots[] = { | 
|  | {Py_tp_new, PyUpb_MessageMeta_New}, | 
|  | {Py_tp_dealloc, PyUpb_MessageMeta_Dealloc}, | 
|  | {Py_tp_getattro, PyUpb_MessageMeta_GetAttr}, | 
|  | {Py_tp_traverse, PyUpb_MessageMeta_Traverse}, | 
|  | {Py_tp_clear, PyUpb_MessageMeta_Clear}, | 
|  | {0, NULL}}; | 
|  |  | 
|  | static PyType_Spec PyUpb_MessageMeta_Spec = { | 
|  | PYUPB_MODULE_NAME ".MessageMeta",  // tp_name | 
|  | 0,  // To be filled in by size of base     // tp_basicsize | 
|  | 0,  // tp_itemsize | 
|  | // TODO: remove BASETYPE, Python should just use MessageMeta | 
|  | // directly instead of subclassing it. | 
|  | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,  // tp_flags | 
|  | PyUpb_MessageMeta_Slots, | 
|  | }; | 
|  |  | 
|  | static PyObject* PyUpb_MessageMeta_CreateType(void) { | 
|  | PyObject* bases = Py_BuildValue("(O)", &PyType_Type); | 
|  | if (!bases) return NULL; | 
|  | PyUpb_MessageMeta_Spec.basicsize = | 
|  | cpython_bits.type_basicsize + sizeof(PyUpb_MessageMeta); | 
|  | PyObject* type = PyType_FromSpecWithBases(&PyUpb_MessageMeta_Spec, bases); | 
|  | Py_DECREF(bases); | 
|  | return type; | 
|  | } | 
|  |  | 
|  | bool PyUpb_InitMessage(PyObject* m) { | 
|  | if (!PyUpb_CPythonBits_Init(&cpython_bits)) return false; | 
|  | PyObject* message_meta_type = PyUpb_MessageMeta_CreateType(); | 
|  |  | 
|  | PyUpb_ModuleState* state = PyUpb_ModuleState_GetFromModule(m); | 
|  | state->cmessage_type = PyUpb_AddClass(m, &PyUpb_Message_Spec); | 
|  | state->message_meta_type = (PyTypeObject*)message_meta_type; | 
|  |  | 
|  | if (!state->cmessage_type || !state->message_meta_type) return false; | 
|  | if (PyModule_AddObject(m, "MessageMeta", message_meta_type)) return false; | 
|  | state->listfields_item_key = PyObject_GetAttrString( | 
|  | (PyObject*)state->cmessage_type, "_ListFieldsItemKey"); | 
|  |  | 
|  | PyObject* mod = | 
|  | PyImport_ImportModule(PYUPB_PROTOBUF_PUBLIC_PACKAGE ".message"); | 
|  | if (mod == NULL) return false; | 
|  |  | 
|  | state->encode_error_class = PyObject_GetAttrString(mod, "EncodeError"); | 
|  | state->decode_error_class = PyObject_GetAttrString(mod, "DecodeError"); | 
|  | state->message_class = PyObject_GetAttrString(mod, "Message"); | 
|  | Py_DECREF(mod); | 
|  |  | 
|  | PyObject* enum_type_wrapper = PyImport_ImportModule( | 
|  | PYUPB_PROTOBUF_INTERNAL_PACKAGE ".enum_type_wrapper"); | 
|  | if (enum_type_wrapper == NULL) return false; | 
|  |  | 
|  | state->enum_type_wrapper_class = | 
|  | PyObject_GetAttrString(enum_type_wrapper, "EnumTypeWrapper"); | 
|  | Py_DECREF(enum_type_wrapper); | 
|  |  | 
|  | if (!state->encode_error_class || !state->decode_error_class || | 
|  | !state->message_class || !state->listfields_item_key || | 
|  | !state->enum_type_wrapper_class) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } |