blob: 2fe5126b831324efbf4af1586017600ae850ad58 [file] [log] [blame]
Joshua Haberman4111d132021-12-04 18:42:53 -08001/*
2 * Copyright (c) 2009-2021, Google LLC
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of Google LLC nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include "python/message.h"
29
30#include "python/convert.h"
31#include "python/descriptor.h"
Joshua Haberman627c44b2021-12-30 17:47:12 -080032#include "python/extension_dict.h"
Joshua Habermanbf74b3e2021-12-30 00:52:12 -080033#include "python/map.h"
Joshua Haberman455426e2021-12-08 23:32:05 -080034#include "python/repeated.h"
Eric Saloedecfd52022-09-15 10:26:14 -070035#include "upb/reflection/def.h"
36#include "upb/reflection/message.h"
Eric Salo0bb46632022-11-03 10:33:57 -070037#include "upb/text/encode.h"
Joshua Haberman4111d132021-12-04 18:42:53 -080038#include "upb/util/required_fields.h"
Protobuf Team Bot9d2b5d12023-04-09 10:01:22 -070039#include "upb/wire/common.h"
Joshua Haberman4111d132021-12-04 18:42:53 -080040
Joshua Haberman1c955f32022-01-12 07:19:28 -080041static const upb_MessageDef* PyUpb_MessageMeta_GetMsgdef(PyObject* cls);
Joshua Habermaneb38a2a2021-12-05 23:54:34 -080042static PyObject* PyUpb_MessageMeta_GetAttr(PyObject* self, PyObject* name);
Joshua Haberman4111d132021-12-04 18:42:53 -080043
44// -----------------------------------------------------------------------------
45// CPythonBits
46// -----------------------------------------------------------------------------
47
48// This struct contains a few things that are not exposed directly through the
49// limited API, but that we can get at in somewhat more roundabout ways. The
50// roundabout ways are slower, so we cache the values here.
51//
52// These values are valid to cache in a global, even across sub-interpreters,
53// because they are not pointers to interpreter state. They are process
54// globals that will be the same for any interpreter in this process.
55typedef struct {
56 // For each member, we note the equivalent expression that we could use in the
57 // full (non-limited) API.
58 newfunc type_new; // PyTypeObject.tp_new
Joshua Habermanffdcc462022-01-12 08:38:36 -080059 destructor type_dealloc; // PyTypeObject.tp_dealloc
Joshua Haberman4111d132021-12-04 18:42:53 -080060 getattrofunc type_getattro; // PyTypeObject.tp_getattro
61 setattrofunc type_setattro; // PyTypeObject.tp_setattro
62 size_t type_basicsize; // sizeof(PyHeapTypeObject)
63
64 // While we can refer to PY_VERSION_HEX in the limited API, this will give us
65 // the version of Python we were compiled against, which may be different
66 // than the version we are dynamically linked against. Here we want the
67 // version that is actually running in this process.
Joshua Haberman1c955f32022-01-12 07:19:28 -080068 long python_version_hex; // PY_VERSION_HEX
Joshua Haberman4111d132021-12-04 18:42:53 -080069} PyUpb_CPythonBits;
70
71// A global containing the values for this process.
72PyUpb_CPythonBits cpython_bits;
73
Joshua Habermanffdcc462022-01-12 08:38:36 -080074destructor upb_Pre310_PyType_GetDeallocSlot(PyTypeObject* type_subclass) {
75 // This is a bit desperate. We need type_dealloc(), but PyType_GetSlot(type,
76 // Py_tp_dealloc) will return subtype_dealloc(). There appears to be no way
77 // whatsoever to fetch type_dealloc() through the limited API until Python
78 // 3.10.
79 //
80 // To work around this so we attempt to find it by looking for the offset of
81 // tp_dealloc in PyTypeObject, then memcpy() it directly. This should always
82 // work in practice.
83 //
84 // Starting with Python 3.10 on you can call PyType_GetSlot() on non-heap
85 // types. We will be able to replace all this hack with just:
86 //
87 // PyType_GetSlot(&PyType_Type, Py_tp_dealloc)
88 //
89 destructor subtype_dealloc = PyType_GetSlot(type_subclass, Py_tp_dealloc);
90 for (size_t i = 0; i < 2000; i += sizeof(uintptr_t)) {
91 destructor maybe_subtype_dealloc;
92 memcpy(&maybe_subtype_dealloc, (char*)type_subclass + i,
93 sizeof(destructor));
94 if (maybe_subtype_dealloc == subtype_dealloc) {
95 destructor type_dealloc;
96 memcpy(&type_dealloc, (char*)&PyType_Type + i, sizeof(destructor));
97 return type_dealloc;
98 }
99 }
100 assert(false);
101 return NULL;
102}
103
Joshua Haberman4111d132021-12-04 18:42:53 -0800104static bool PyUpb_CPythonBits_Init(PyUpb_CPythonBits* bits) {
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800105 PyObject* bases = NULL;
106 PyTypeObject* type = NULL;
107 PyObject* size = NULL;
108 PyObject* sys = NULL;
109 PyObject* hex_version = NULL;
110 bool ret = false;
111
Joshua Haberman4111d132021-12-04 18:42:53 -0800112 // PyType_GetSlot() only works on heap types, so we cannot use it on
113 // &PyType_Type directly. Instead we create our own (temporary) type derived
114 // from PyType_Type: this will inherit all of the slots from PyType_Type, but
115 // as a heap type it can be queried with PyType_GetSlot().
116 static PyType_Slot dummy_slots[] = {{0, NULL}};
117
118 static PyType_Spec dummy_spec = {
119 "module.DummyClass", // tp_name
120 0, // To be filled in by size of base // tp_basicsize
121 0, // tp_itemsize
122 Py_TPFLAGS_DEFAULT, // tp_flags
123 dummy_slots,
124 };
125
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800126 bases = Py_BuildValue("(O)", &PyType_Type);
127 if (!bases) goto err;
128 type = (PyTypeObject*)PyType_FromSpecWithBases(&dummy_spec, bases);
129 if (!type) goto err;
Joshua Haberman4111d132021-12-04 18:42:53 -0800130
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800131 bits->type_new = PyType_GetSlot(type, Py_tp_new);
Joshua Habermanffdcc462022-01-12 08:38:36 -0800132 bits->type_dealloc = upb_Pre310_PyType_GetDeallocSlot(type);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800133 bits->type_getattro = PyType_GetSlot(type, Py_tp_getattro);
134 bits->type_setattro = PyType_GetSlot(type, Py_tp_setattro);
Joshua Haberman4111d132021-12-04 18:42:53 -0800135
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800136 size = PyObject_GetAttrString((PyObject*)&PyType_Type, "__basicsize__");
137 if (!size) goto err;
Joshua Haberman4111d132021-12-04 18:42:53 -0800138 bits->type_basicsize = PyLong_AsLong(size);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800139 if (bits->type_basicsize == -1) goto err;
Joshua Haberman4111d132021-12-04 18:42:53 -0800140
Joshua Habermanffdcc462022-01-12 08:38:36 -0800141 assert(bits->type_new);
142 assert(bits->type_dealloc);
143 assert(bits->type_getattro);
144 assert(bits->type_setattro);
Joshua Haberman4111d132021-12-04 18:42:53 -0800145
146#ifndef Py_LIMITED_API
147 assert(bits->type_new == PyType_Type.tp_new);
Joshua Habermanffdcc462022-01-12 08:38:36 -0800148 assert(bits->type_dealloc == PyType_Type.tp_dealloc);
Joshua Haberman4111d132021-12-04 18:42:53 -0800149 assert(bits->type_getattro == PyType_Type.tp_getattro);
150 assert(bits->type_setattro == PyType_Type.tp_setattro);
151 assert(bits->type_basicsize == sizeof(PyHeapTypeObject));
152#endif
153
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800154 sys = PyImport_ImportModule("sys");
155 hex_version = PyObject_GetAttrString(sys, "hexversion");
Joshua Haberman4111d132021-12-04 18:42:53 -0800156 bits->python_version_hex = PyLong_AsLong(hex_version);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800157 ret = true;
Joshua Haberman4111d132021-12-04 18:42:53 -0800158
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800159err:
160 Py_XDECREF(bases);
161 Py_XDECREF(type);
162 Py_XDECREF(size);
163 Py_XDECREF(sys);
164 Py_XDECREF(hex_version);
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800165 return ret;
Joshua Haberman4111d132021-12-04 18:42:53 -0800166}
167
168// -----------------------------------------------------------------------------
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700169// Message
Joshua Haberman4111d132021-12-04 18:42:53 -0800170// -----------------------------------------------------------------------------
171
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700172// The main message object. The type of the object (PyUpb_Message.ob_type)
Joshua Haberman4111d132021-12-04 18:42:53 -0800173// will be an instance of the PyUpb_MessageMeta type (defined below). So the
174// chain is:
175// FooMessage = MessageMeta(...)
176// foo = FooMessage()
177//
178// Which becomes:
179// Object C Struct Type Python type (ob_type)
180// ----------------- ----------------- ---------------------
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700181// foo PyUpb_Message FooMessage
Joshua Haberman4111d132021-12-04 18:42:53 -0800182// FooMessage PyUpb_MessageMeta message_meta_type
183// message_meta_type PyTypeObject 'type' in Python
184//
185// A message object can be in one of two states: present or non-present. When
186// a message is non-present, it stores a reference to its parent, and a write
187// to any attribute will trigger the message to become present in its parent.
188// The parent may also be non-present, in which case a mutation will trigger a
189// chain reaction.
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700190typedef struct PyUpb_Message {
Joshua Haberman1c955f32022-01-12 07:19:28 -0800191 PyObject_HEAD;
Joshua Haberman4111d132021-12-04 18:42:53 -0800192 PyObject* arena;
Joshua Haberman1c955f32022-01-12 07:19:28 -0800193 uintptr_t def; // Tagged, low bit 1 == upb_FieldDef*, else upb_MessageDef*
Joshua Haberman4111d132021-12-04 18:42:53 -0800194 union {
195 // when def is msgdef, the data for this msg.
Joshua Haberman499c2cc2022-01-12 09:09:59 -0800196 upb_Message* msg;
Joshua Haberman4111d132021-12-04 18:42:53 -0800197 // when def is fielddef, owning pointer to parent
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700198 struct PyUpb_Message* parent;
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800199 } ptr;
Joshua Haberman4111d132021-12-04 18:42:53 -0800200 PyObject* ext_dict; // Weak pointer to extension dict, if any.
201 // name->obj dict for non-present msg/map/repeated, NULL if none.
202 PyUpb_WeakMap* unset_subobj_map;
203 int version;
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700204} PyUpb_Message;
Joshua Haberman4111d132021-12-04 18:42:53 -0800205
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700206static PyObject* PyUpb_Message_GetAttr(PyObject* _self, PyObject* attr);
Joshua Haberman4111d132021-12-04 18:42:53 -0800207
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700208bool PyUpb_Message_IsStub(PyUpb_Message* msg) { return msg->def & 1; }
Joshua Haberman4111d132021-12-04 18:42:53 -0800209
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700210const upb_FieldDef* PyUpb_Message_GetFieldDef(PyUpb_Message* msg) {
211 assert(PyUpb_Message_IsStub(msg));
Joshua Haberman4111d132021-12-04 18:42:53 -0800212 return (void*)(msg->def & ~(uintptr_t)1);
213}
214
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700215static const upb_MessageDef* _PyUpb_Message_GetMsgdef(PyUpb_Message* msg) {
216 return PyUpb_Message_IsStub(msg)
217 ? upb_FieldDef_MessageSubDef(PyUpb_Message_GetFieldDef(msg))
Joshua Haberman4111d132021-12-04 18:42:53 -0800218 : (void*)msg->def;
219}
220
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700221const upb_MessageDef* PyUpb_Message_GetMsgdef(PyObject* self) {
222 return _PyUpb_Message_GetMsgdef((PyUpb_Message*)self);
Joshua Haberman4111d132021-12-04 18:42:53 -0800223}
224
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700225static upb_Message* PyUpb_Message_GetMsg(PyUpb_Message* self) {
226 assert(!PyUpb_Message_IsStub(self));
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800227 return self->ptr.msg;
Joshua Haberman4111d132021-12-04 18:42:53 -0800228}
229
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700230bool PyUpb_Message_TryCheck(PyObject* self) {
Joshua Haberman4111d132021-12-04 18:42:53 -0800231 PyUpb_ModuleState* state = PyUpb_ModuleState_Get();
232 PyObject* type = (PyObject*)Py_TYPE(self);
233 return Py_TYPE(type) == state->message_meta_type;
234}
235
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700236bool PyUpb_Message_Verify(PyObject* self) {
237 if (!PyUpb_Message_TryCheck(self)) {
Joshua Haberman4111d132021-12-04 18:42:53 -0800238 PyErr_Format(PyExc_TypeError, "Expected a message object, but got %R.",
239 self);
240 return false;
241 }
242 return true;
243}
244
Joshua Haberman58960e02021-12-30 10:50:41 -0800245// If the message is reified, returns it. Otherwise, returns NULL.
246// If NULL is returned, the object is empty and has no underlying data.
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700247upb_Message* PyUpb_Message_GetIfReified(PyObject* _self) {
248 PyUpb_Message* self = (void*)_self;
249 return PyUpb_Message_IsStub(self) ? NULL : self->ptr.msg;
Joshua Haberman4111d132021-12-04 18:42:53 -0800250}
251
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700252static PyObject* PyUpb_Message_New(PyObject* cls, PyObject* unused_args,
253 PyObject* unused_kwargs) {
Joshua Haberman1c955f32022-01-12 07:19:28 -0800254 const upb_MessageDef* msgdef = PyUpb_MessageMeta_GetMsgdef(cls);
Eric Salo41335a02022-10-10 13:53:47 -0700255 const upb_MiniTable* layout = upb_MessageDef_MiniTable(msgdef);
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700256 PyUpb_Message* msg = (void*)PyType_GenericAlloc((PyTypeObject*)cls, 0);
Joshua Haberman4111d132021-12-04 18:42:53 -0800257 msg->def = (uintptr_t)msgdef;
258 msg->arena = PyUpb_Arena_New();
Eric Salo41335a02022-10-10 13:53:47 -0700259 msg->ptr.msg = upb_Message_New(layout, PyUpb_Arena_Get(msg->arena));
Joshua Haberman4111d132021-12-04 18:42:53 -0800260 msg->unset_subobj_map = NULL;
261 msg->ext_dict = NULL;
262 msg->version = 0;
263
264 PyObject* ret = &msg->ob_base;
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800265 PyUpb_ObjCache_Add(msg->ptr.msg, ret);
Joshua Haberman4111d132021-12-04 18:42:53 -0800266 return ret;
267}
268
Joshua Habermaneb38a2a2021-12-05 23:54:34 -0800269/*
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700270 * PyUpb_Message_LookupName()
Joshua Habermaneb38a2a2021-12-05 23:54:34 -0800271 *
272 * Tries to find a field or oneof named `py_name` in the message object `self`.
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800273 * The user must pass `f` and/or `o` to indicate whether a field or a oneof name
274 * is expected. If the name is found and it has an expected type, the function
Joshua Habermaneb38a2a2021-12-05 23:54:34 -0800275 * sets `*f` or `*o` respectively and returns true. Otherwise returns false
276 * and sets an exception of type `exc_type` if provided.
277 */
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700278static bool PyUpb_Message_LookupName(PyUpb_Message* self, PyObject* py_name,
279 const upb_FieldDef** f,
280 const upb_OneofDef** o,
281 PyObject* exc_type) {
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800282 assert(f || o);
Joshua Haberman4111d132021-12-04 18:42:53 -0800283 Py_ssize_t size;
Joshua Habermanc75b39f2022-01-09 21:48:26 -0800284 const char* name = NULL;
285 if (PyUnicode_Check(py_name)) {
286 name = PyUnicode_AsUTF8AndSize(py_name, &size);
287 } else if (PyBytes_Check(py_name)) {
288 PyBytes_AsStringAndSize(py_name, (char**)&name, &size);
289 }
Joshua Habermanffdcc462022-01-12 08:38:36 -0800290 if (!name) {
291 PyErr_Format(exc_type,
292 "Expected a field name, but got non-string argument %S.",
293 py_name);
294 return false;
295 }
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700296 const upb_MessageDef* msgdef = _PyUpb_Message_GetMsgdef(self);
Joshua Haberman4111d132021-12-04 18:42:53 -0800297
Joshua Haberman1c955f32022-01-12 07:19:28 -0800298 if (!upb_MessageDef_FindByNameWithSize(msgdef, name, size, f, o)) {
Joshua Haberman4111d132021-12-04 18:42:53 -0800299 if (exc_type) {
Joshua Haberman1c955f32022-01-12 07:19:28 -0800300 PyErr_Format(exc_type, "Protocol message %s has no \"%s\" field.",
301 upb_MessageDef_Name(msgdef), name);
Joshua Haberman4111d132021-12-04 18:42:53 -0800302 }
303 return false;
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800304 }
305
306 if (!o && !*f) {
Joshua Haberman4111d132021-12-04 18:42:53 -0800307 if (exc_type) {
308 PyErr_Format(exc_type, "Expected a field name, but got oneof name %s.",
309 name);
310 }
311 return false;
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800312 }
313
314 if (!f && !*o) {
Joshua Haberman4111d132021-12-04 18:42:53 -0800315 if (exc_type) {
316 PyErr_Format(exc_type, "Expected a oneof name, but got field name %s.",
317 name);
318 }
319 return false;
320 }
321
322 return true;
323}
324
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700325static bool PyUpb_Message_InitMessageMapEntry(PyObject* dst, PyObject* src) {
Joshua Habermaneb38a2a2021-12-05 23:54:34 -0800326 if (!src || !dst) return false;
327
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800328 // TODO(haberman): Currently we are doing Clear()+MergeFrom(). Replace with
329 // CopyFrom() once that is implemented.
Joshua Habermaneb38a2a2021-12-05 23:54:34 -0800330 PyObject* ok = PyObject_CallMethod(dst, "Clear", NULL);
331 if (!ok) return false;
332 Py_DECREF(ok);
333 ok = PyObject_CallMethod(dst, "MergeFrom", "O", src);
334 if (!ok) return false;
335 Py_DECREF(ok);
336
337 return true;
338}
339
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700340int PyUpb_Message_InitMapAttributes(PyObject* map, PyObject* value,
341 const upb_FieldDef* f) {
Joshua Haberman1c955f32022-01-12 07:19:28 -0800342 const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(f);
343 const upb_FieldDef* val_f = upb_MessageDef_Field(entry_m, 1);
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800344 PyObject* it = NULL;
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800345 PyObject* tmp = NULL;
346 int ret = -1;
Joshua Haberman1c955f32022-01-12 07:19:28 -0800347 if (upb_FieldDef_IsSubMessage(val_f)) {
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800348 it = PyObject_GetIter(value);
349 if (it == NULL) {
Joshua Haberman4111d132021-12-04 18:42:53 -0800350 PyErr_Format(PyExc_TypeError, "Argument for field %s is not iterable",
Joshua Haberman1c955f32022-01-12 07:19:28 -0800351 upb_FieldDef_FullName(f));
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800352 goto err;
Joshua Haberman4111d132021-12-04 18:42:53 -0800353 }
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800354 PyObject* e;
355 while ((e = PyIter_Next(it)) != NULL) {
356 PyObject* src = PyObject_GetItem(value, e);
357 PyObject* dst = PyObject_GetItem(map, e);
358 Py_DECREF(e);
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700359 bool ok = PyUpb_Message_InitMessageMapEntry(dst, src);
Joshua Habermaneb38a2a2021-12-05 23:54:34 -0800360 Py_XDECREF(src);
361 Py_XDECREF(dst);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800362 if (!ok) goto err;
Joshua Haberman4111d132021-12-04 18:42:53 -0800363 }
Joshua Haberman4111d132021-12-04 18:42:53 -0800364 } else {
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800365 tmp = PyObject_CallMethod(map, "update", "O", value);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800366 if (!tmp) goto err;
Joshua Haberman4111d132021-12-04 18:42:53 -0800367 }
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800368 ret = 0;
369
370err:
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800371 Py_XDECREF(it);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800372 Py_XDECREF(tmp);
373 return ret;
Joshua Haberman4111d132021-12-04 18:42:53 -0800374}
375
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700376void PyUpb_Message_EnsureReified(PyUpb_Message* self);
Joshua Haberman4111d132021-12-04 18:42:53 -0800377
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700378static bool PyUpb_Message_InitMapAttribute(PyObject* _self, PyObject* name,
379 const upb_FieldDef* f,
380 PyObject* value) {
381 PyObject* map = PyUpb_Message_GetAttr(_self, name);
382 int ok = PyUpb_Message_InitMapAttributes(map, value, f);
Joshua Habermanbf74b3e2021-12-30 00:52:12 -0800383 Py_DECREF(map);
384 return ok >= 0;
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800385}
386
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700387static bool PyUpb_Message_InitRepeatedMessageAttribute(PyObject* _self,
388 PyObject* repeated,
389 PyObject* value,
390 const upb_FieldDef* f) {
Joshua Haberman0abdee02022-05-06 20:53:55 -0700391 PyObject* it = PyObject_GetIter(value);
392 if (!it) {
393 PyErr_Format(PyExc_TypeError, "Argument for field %s is not iterable",
394 upb_FieldDef_FullName(f));
395 return false;
396 }
397 PyObject* e = NULL;
398 PyObject* m = NULL;
399 while ((e = PyIter_Next(it)) != NULL) {
400 if (PyDict_Check(e)) {
401 m = PyUpb_RepeatedCompositeContainer_Add(repeated, NULL, e);
402 if (!m) goto err;
403 } else {
404 m = PyUpb_RepeatedCompositeContainer_Add(repeated, NULL, NULL);
405 if (!m) goto err;
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700406 PyObject* merged = PyUpb_Message_MergeFrom(m, e);
Joshua Haberman0abdee02022-05-06 20:53:55 -0700407 if (!merged) goto err;
408 Py_DECREF(merged);
409 }
410 Py_DECREF(e);
411 Py_DECREF(m);
412 m = NULL;
413 }
414
415err:
416 Py_XDECREF(it);
417 Py_XDECREF(e);
418 Py_XDECREF(m);
419 return !PyErr_Occurred(); // Check PyIter_Next() exit.
420}
421
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700422static bool PyUpb_Message_InitRepeatedAttribute(PyObject* _self, PyObject* name,
423 PyObject* value) {
424 PyUpb_Message* self = (void*)_self;
Joshua Haberman0abdee02022-05-06 20:53:55 -0700425 const upb_FieldDef* field;
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700426 if (!PyUpb_Message_LookupName(self, name, &field, NULL,
427 PyExc_AttributeError)) {
Joshua Haberman0abdee02022-05-06 20:53:55 -0700428 return false;
429 }
Joshua Habermanffdcc462022-01-12 08:38:36 -0800430 bool ok = false;
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700431 PyObject* repeated = PyUpb_Message_GetFieldValue(_self, field);
Joshua Haberman0abdee02022-05-06 20:53:55 -0700432 PyObject* tmp = NULL;
Joshua Habermanc3cfd092022-05-10 08:52:45 -0700433 if (!repeated) goto err;
Joshua Haberman0abdee02022-05-06 20:53:55 -0700434 if (upb_FieldDef_IsSubMessage(field)) {
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700435 if (!PyUpb_Message_InitRepeatedMessageAttribute(_self, repeated, value,
436 field)) {
Joshua Haberman0abdee02022-05-06 20:53:55 -0700437 goto err;
438 }
439 } else {
440 tmp = PyUpb_RepeatedContainer_Extend(repeated, value);
441 if (!tmp) goto err;
442 }
Joshua Habermanffdcc462022-01-12 08:38:36 -0800443 ok = true;
444
445err:
446 Py_XDECREF(repeated);
447 Py_XDECREF(tmp);
448 return ok;
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800449}
450
Eric Saloea4cb792023-03-22 07:25:40 -0700451static PyObject* PyUpb_Message_MergePartialFrom(PyObject*, PyObject*);
452
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700453static bool PyUpb_Message_InitMessageAttribute(PyObject* _self, PyObject* name,
454 PyObject* value) {
455 PyObject* submsg = PyUpb_Message_GetAttr(_self, name);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800456 if (!submsg) return -1;
457 assert(!PyErr_Occurred());
458 bool ok;
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700459 if (PyUpb_Message_TryCheck(value)) {
Eric Saloea4cb792023-03-22 07:25:40 -0700460 PyObject* tmp = PyUpb_Message_MergePartialFrom(submsg, value);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800461 ok = tmp != NULL;
Eric Saloea4cb792023-03-22 07:25:40 -0700462 Py_XDECREF(tmp);
Joshua Haberman61d6eff2022-01-09 20:50:32 -0800463 } else if (PyDict_Check(value)) {
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800464 assert(!PyErr_Occurred());
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700465 ok = PyUpb_Message_InitAttributes(submsg, NULL, value) >= 0;
Joshua Haberman61d6eff2022-01-09 20:50:32 -0800466 } else {
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700467 const upb_MessageDef* m = PyUpb_Message_GetMsgdef(_self);
Joshua Haberman61d6eff2022-01-09 20:50:32 -0800468 PyErr_Format(PyExc_TypeError, "Message must be initialized with a dict: %s",
Joshua Haberman1c955f32022-01-12 07:19:28 -0800469 upb_MessageDef_FullName(m));
Joshua Haberman61d6eff2022-01-09 20:50:32 -0800470 ok = false;
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800471 }
472 Py_DECREF(submsg);
473 return ok;
474}
475
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700476static bool PyUpb_Message_InitScalarAttribute(upb_Message* msg,
477 const upb_FieldDef* f,
478 PyObject* value,
479 upb_Arena* arena) {
Joshua Haberman1c955f32022-01-12 07:19:28 -0800480 upb_MessageValue msgval;
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800481 assert(!PyErr_Occurred());
Joshua Haberman61d6eff2022-01-09 20:50:32 -0800482 if (!PyUpb_PyToUpb(value, f, &msgval, arena)) return false;
Eric Salob747edb2022-12-05 08:40:10 -0800483 upb_Message_SetFieldByDef(msg, f, msgval, arena);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800484 return true;
485}
486
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700487int PyUpb_Message_InitAttributes(PyObject* _self, PyObject* args,
488 PyObject* kwargs) {
Joshua Haberman4111d132021-12-04 18:42:53 -0800489 assert(!PyErr_Occurred());
490
491 if (args != NULL && PyTuple_Size(args) != 0) {
492 PyErr_SetString(PyExc_TypeError, "No positional arguments allowed");
493 return -1;
494 }
495
496 if (kwargs == NULL) return 0;
497
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700498 PyUpb_Message* self = (void*)_self;
Joshua Haberman4111d132021-12-04 18:42:53 -0800499 Py_ssize_t pos = 0;
500 PyObject* name;
501 PyObject* value;
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700502 PyUpb_Message_EnsureReified(self);
503 upb_Message* msg = PyUpb_Message_GetMsg(self);
Joshua Haberman1c955f32022-01-12 07:19:28 -0800504 upb_Arena* arena = PyUpb_Arena_Get(self->arena);
Joshua Haberman4111d132021-12-04 18:42:53 -0800505
506 while (PyDict_Next(kwargs, &pos, &name, &value)) {
507 assert(!PyErr_Occurred());
Joshua Haberman1c955f32022-01-12 07:19:28 -0800508 const upb_FieldDef* f;
Joshua Haberman4111d132021-12-04 18:42:53 -0800509 assert(!PyErr_Occurred());
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700510 if (!PyUpb_Message_LookupName(self, name, &f, NULL, PyExc_ValueError)) {
Joshua Haberman4111d132021-12-04 18:42:53 -0800511 return -1;
512 }
513
514 if (value == Py_None) continue; // Ignored.
515
516 assert(!PyErr_Occurred());
517
Joshua Haberman1c955f32022-01-12 07:19:28 -0800518 if (upb_FieldDef_IsMap(f)) {
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700519 if (!PyUpb_Message_InitMapAttribute(_self, name, f, value)) return -1;
Joshua Haberman1c955f32022-01-12 07:19:28 -0800520 } else if (upb_FieldDef_IsRepeated(f)) {
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700521 if (!PyUpb_Message_InitRepeatedAttribute(_self, name, value)) return -1;
Joshua Haberman1c955f32022-01-12 07:19:28 -0800522 } else if (upb_FieldDef_IsSubMessage(f)) {
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700523 if (!PyUpb_Message_InitMessageAttribute(_self, name, value)) return -1;
Joshua Haberman4111d132021-12-04 18:42:53 -0800524 } else {
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700525 if (!PyUpb_Message_InitScalarAttribute(msg, f, value, arena)) return -1;
Joshua Haberman4111d132021-12-04 18:42:53 -0800526 }
527 if (PyErr_Occurred()) return -1;
528 }
529
530 if (PyErr_Occurred()) return -1;
531 return 0;
532}
533
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700534static int PyUpb_Message_Init(PyObject* _self, PyObject* args,
535 PyObject* kwargs) {
Joshua Haberman4111d132021-12-04 18:42:53 -0800536 if (args != NULL && PyTuple_Size(args) != 0) {
537 PyErr_SetString(PyExc_TypeError, "No positional arguments allowed");
538 return -1;
539 }
540
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700541 return PyUpb_Message_InitAttributes(_self, args, kwargs);
Joshua Haberman4111d132021-12-04 18:42:53 -0800542}
543
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700544static PyObject* PyUpb_Message_NewStub(PyObject* parent, const upb_FieldDef* f,
545 PyObject* arena) {
Joshua Haberman1c955f32022-01-12 07:19:28 -0800546 const upb_MessageDef* sub_m = upb_FieldDef_MessageSubDef(f);
Joshua Haberman4111d132021-12-04 18:42:53 -0800547 PyObject* cls = PyUpb_Descriptor_GetClass(sub_m);
548
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700549 PyUpb_Message* msg = (void*)PyType_GenericAlloc((PyTypeObject*)cls, 0);
Joshua Haberman4111d132021-12-04 18:42:53 -0800550 msg->def = (uintptr_t)f | 1;
551 msg->arena = arena;
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700552 msg->ptr.parent = (PyUpb_Message*)parent;
Joshua Haberman4111d132021-12-04 18:42:53 -0800553 msg->unset_subobj_map = NULL;
554 msg->ext_dict = NULL;
555 msg->version = 0;
556
557 Py_DECREF(cls);
558 Py_INCREF(parent);
559 Py_INCREF(arena);
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800560 return &msg->ob_base;
Joshua Haberman4111d132021-12-04 18:42:53 -0800561}
562
Eric Saloc2c64272022-07-12 21:31:18 -0700563static bool PyUpb_Message_IsEmpty(const upb_Message* msg,
564 const upb_MessageDef* m,
565 const upb_DefPool* ext_pool) {
566 if (!msg) return true;
567
568 size_t iter = kUpb_Message_Begin;
569 const upb_FieldDef* f;
570 upb_MessageValue val;
571 if (upb_Message_Next(msg, m, ext_pool, &f, &val, &iter)) return false;
572
573 size_t len;
574 (void)upb_Message_GetUnknown(msg, &len);
575 return len == 0;
576}
577
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700578static bool PyUpb_Message_IsEqual(PyUpb_Message* m1, PyObject* _m2) {
579 PyUpb_Message* m2 = (void*)_m2;
Joshua Haberman4111d132021-12-04 18:42:53 -0800580 if (m1 == m2) return true;
581 if (!PyObject_TypeCheck(_m2, m1->ob_base.ob_type)) {
582 return false;
583 }
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700584 const upb_MessageDef* m1_msgdef = _PyUpb_Message_GetMsgdef(m1);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800585#ifndef NDEBUG
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700586 const upb_MessageDef* m2_msgdef = _PyUpb_Message_GetMsgdef(m2);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800587 assert(m1_msgdef == m2_msgdef);
588#endif
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700589 const upb_Message* m1_msg = PyUpb_Message_GetIfReified((PyObject*)m1);
590 const upb_Message* m2_msg = PyUpb_Message_GetIfReified(_m2);
Eric Saloc2c64272022-07-12 21:31:18 -0700591 const upb_DefPool* symtab = upb_FileDef_Pool(upb_MessageDef_File(m1_msgdef));
592
593 const bool e1 = PyUpb_Message_IsEmpty(m1_msg, m1_msgdef, symtab);
594 const bool e2 = PyUpb_Message_IsEmpty(m2_msg, m1_msgdef, symtab);
595 if (e1 || e2) return e1 && e2;
596
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700597 return upb_Message_IsEqual(m1_msg, m2_msg, m1_msgdef);
Joshua Haberman4111d132021-12-04 18:42:53 -0800598}
599
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700600static const upb_FieldDef* PyUpb_Message_InitAsMsg(PyUpb_Message* m,
601 upb_Arena* arena) {
602 const upb_FieldDef* f = PyUpb_Message_GetFieldDef(m);
Eric Salo41335a02022-10-10 13:53:47 -0700603 const upb_MessageDef* m2 = upb_FieldDef_MessageSubDef(f);
604 m->ptr.msg = upb_Message_New(upb_MessageDef_MiniTable(m2), arena);
605 m->def = (uintptr_t)m2;
Joshua Haberman32ebb482021-12-08 20:06:07 -0800606 PyUpb_ObjCache_Add(m->ptr.msg, &m->ob_base);
Joshua Habermandc0d1b42021-12-08 15:40:38 -0800607 return f;
608}
609
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700610static void PyUpb_Message_SetField(PyUpb_Message* parent, const upb_FieldDef* f,
611 PyUpb_Message* child, upb_Arena* arena) {
612 upb_MessageValue msgval = {.msg_val = PyUpb_Message_GetMsg(child)};
Eric Salob747edb2022-12-05 08:40:10 -0800613 upb_Message_SetFieldByDef(PyUpb_Message_GetMsg(parent), f, msgval, arena);
Joshua Haberman32ebb482021-12-08 20:06:07 -0800614 PyUpb_WeakMap_Delete(parent->unset_subobj_map, f);
615 // Releases a ref previously owned by child->ptr.parent of our child.
616 Py_DECREF(child);
Joshua Habermandc0d1b42021-12-08 15:40:38 -0800617}
618
Joshua Haberman4111d132021-12-04 18:42:53 -0800619/*
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700620 * PyUpb_Message_EnsureReified()
Joshua Haberman4111d132021-12-04 18:42:53 -0800621 *
622 * This implements the "expando" behavior of Python protos:
623 * foo = FooProto()
624 *
625 * # The intermediate messages don't really exist, and won't be serialized.
626 * x = foo.bar.bar.bar.bar.bar.baz
627 *
628 * # Now all the intermediate objects are created.
629 * foo.bar.bar.bar.bar.bar.baz = 5
630 *
631 * This function should be called before performing any mutation of a protobuf
632 * object.
633 *
634 * Post-condition:
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700635 * PyUpb_Message_IsStub(self) is false
Joshua Haberman4111d132021-12-04 18:42:53 -0800636 */
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700637void PyUpb_Message_EnsureReified(PyUpb_Message* self) {
638 if (!PyUpb_Message_IsStub(self)) return;
Joshua Haberman1c955f32022-01-12 07:19:28 -0800639 upb_Arena* arena = PyUpb_Arena_Get(self->arena);
Joshua Haberman32ebb482021-12-08 20:06:07 -0800640
Joshua Haberman499c2cc2022-01-12 09:09:59 -0800641 // This is a non-present message. We need to create a real upb_Message for
642 // this object and every parent until we reach a present message.
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700643 PyUpb_Message* child = self;
644 PyUpb_Message* parent = self->ptr.parent;
645 const upb_FieldDef* child_f = PyUpb_Message_InitAsMsg(child, arena);
646 Py_INCREF(child); // To avoid a special-case in PyUpb_Message_SetField().
Joshua Haberman32ebb482021-12-08 20:06:07 -0800647
Joshua Habermandc0d1b42021-12-08 15:40:38 -0800648 do {
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700649 PyUpb_Message* next_parent = parent->ptr.parent;
Joshua Haberman1c955f32022-01-12 07:19:28 -0800650 const upb_FieldDef* parent_f = NULL;
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700651 if (PyUpb_Message_IsStub(parent)) {
652 parent_f = PyUpb_Message_InitAsMsg(parent, arena);
Joshua Haberman4111d132021-12-04 18:42:53 -0800653 }
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700654 PyUpb_Message_SetField(parent, child_f, child, arena);
Joshua Habermandc0d1b42021-12-08 15:40:38 -0800655 child = parent;
Joshua Haberman32ebb482021-12-08 20:06:07 -0800656 child_f = parent_f;
Joshua Haberman4111d132021-12-04 18:42:53 -0800657 parent = next_parent;
Joshua Haberman32ebb482021-12-08 20:06:07 -0800658 } while (child_f);
Joshua Haberman4111d132021-12-04 18:42:53 -0800659
Joshua Haberman32ebb482021-12-08 20:06:07 -0800660 // Releases ref previously owned by child->ptr.parent of our child.
661 Py_DECREF(child);
662 self->version++;
Joshua Haberman4111d132021-12-04 18:42:53 -0800663}
664
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700665static void PyUpb_Message_SyncSubobjs(PyUpb_Message* self);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800666
667/*
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700668 * PyUpb_Message_Reify()
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800669 *
Joshua Habermanfaac2d82021-12-30 01:04:49 -0800670 * The message equivalent of PyUpb_*Container_Reify(), this transitions
Joshua Haberman1c955f32022-01-12 07:19:28 -0800671 * the wrapper from the unset state (owning a reference on self->ptr.parent) to
672 * the set state (having a non-owning pointer to self->ptr.msg).
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800673 */
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700674static void PyUpb_Message_Reify(PyUpb_Message* self, const upb_FieldDef* f,
675 upb_Message* msg) {
676 assert(f == PyUpb_Message_GetFieldDef(self));
Joshua Haberman1be47592022-01-09 10:27:09 -0800677 if (!msg) {
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700678 const upb_MessageDef* msgdef = PyUpb_Message_GetMsgdef((PyObject*)self);
Eric Salo41335a02022-10-10 13:53:47 -0700679 const upb_MiniTable* layout = upb_MessageDef_MiniTable(msgdef);
680 msg = upb_Message_New(layout, PyUpb_Arena_Get(self->arena));
Joshua Haberman1be47592022-01-09 10:27:09 -0800681 }
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800682 PyUpb_ObjCache_Add(msg, &self->ob_base);
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800683 Py_DECREF(&self->ptr.parent->ob_base);
684 self->ptr.msg = msg; // Overwrites self->ptr.parent
Joshua Haberman1c955f32022-01-12 07:19:28 -0800685 self->def = (uintptr_t)upb_FieldDef_MessageSubDef(f);
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700686 PyUpb_Message_SyncSubobjs(self);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800687}
688
Joshua Habermaneb38a2a2021-12-05 23:54:34 -0800689/*
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700690 * PyUpb_Message_SyncSubobjs()
Joshua Habermaneb38a2a2021-12-05 23:54:34 -0800691 *
Joshua Haberman499c2cc2022-01-12 09:09:59 -0800692 * This operation must be invoked whenever the underlying upb_Message has been
Joshua Habermaneb38a2a2021-12-05 23:54:34 -0800693 * mutated directly in C. This will attach any newly-present field data
Joshua Haberman54b775d2022-01-05 12:55:52 -0800694 * to previously returned stub wrapper objects.
Joshua Habermaneb38a2a2021-12-05 23:54:34 -0800695 *
696 * For example:
697 * foo = FooMessage()
698 * sub = foo.submsg # Empty, unset sub-message
699 *
700 * # SyncSubobjs() is required to connect our existing 'sub' wrapper to the
701 * # newly created foo.submsg data in C.
702 * foo.MergeFrom(FooMessage(submsg={}))
Joshua Haberman1c955f32022-01-12 07:19:28 -0800703 *
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800704 * This requires that all of the new sub-objects that have appeared are owned
705 * by `self`'s arena.
Joshua Habermaneb38a2a2021-12-05 23:54:34 -0800706 */
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700707static void PyUpb_Message_SyncSubobjs(PyUpb_Message* self) {
Joshua Haberman4111d132021-12-04 18:42:53 -0800708 PyUpb_WeakMap* subobj_map = self->unset_subobj_map;
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800709 if (!subobj_map) return;
710
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700711 upb_Message* msg = PyUpb_Message_GetMsg(self);
Joshua Haberman4111d132021-12-04 18:42:53 -0800712 intptr_t iter = PYUPB_WEAKMAP_BEGIN;
713 const void* key;
714 PyObject* obj;
715
Joshua Haberman4111d132021-12-04 18:42:53 -0800716 // The last ref to this message could disappear during iteration.
Joshua Haberman1be47592022-01-09 10:27:09 -0800717 // When we call PyUpb_*Container_Reify() below, the container will drop
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800718 // its ref on `self`. If that was the last ref on self, the object will be
719 // deleted, and `subobj_map` along with it. We need it to live until we are
720 // done iterating.
Joshua Haberman4111d132021-12-04 18:42:53 -0800721 Py_INCREF(&self->ob_base);
722
723 while (PyUpb_WeakMap_Next(subobj_map, &key, &obj, &iter)) {
Joshua Haberman1c955f32022-01-12 07:19:28 -0800724 const upb_FieldDef* f = key;
Eric Salob747edb2022-12-05 08:40:10 -0800725 if (upb_FieldDef_HasPresence(f) && !upb_Message_HasFieldByDef(msg, f))
726 continue;
727 upb_MessageValue msgval = upb_Message_GetFieldByDef(msg, f);
Joshua Haberman4111d132021-12-04 18:42:53 -0800728 PyUpb_WeakMap_DeleteIter(subobj_map, &iter);
Joshua Haberman1c955f32022-01-12 07:19:28 -0800729 if (upb_FieldDef_IsMap(f)) {
Joshua Haberman4111d132021-12-04 18:42:53 -0800730 if (!msgval.map_val) continue;
Joshua Haberman1c955f32022-01-12 07:19:28 -0800731 PyUpb_MapContainer_Reify(obj, (upb_Map*)msgval.map_val);
732 } else if (upb_FieldDef_IsRepeated(f)) {
Joshua Haberman4111d132021-12-04 18:42:53 -0800733 if (!msgval.array_val) continue;
Joshua Haberman1c955f32022-01-12 07:19:28 -0800734 PyUpb_RepeatedContainer_Reify(obj, (upb_Array*)msgval.array_val);
Joshua Haberman4111d132021-12-04 18:42:53 -0800735 } else {
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700736 PyUpb_Message* sub = (void*)obj;
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800737 assert(self == sub->ptr.parent);
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700738 PyUpb_Message_Reify(sub, f, (upb_Message*)msgval.msg_val);
Joshua Haberman4111d132021-12-04 18:42:53 -0800739 }
740 }
741
742 Py_DECREF(&self->ob_base);
Joshua Habermaneb38a2a2021-12-05 23:54:34 -0800743
744 // TODO(haberman): present fields need to be iterated too if they can reach
745 // a WeakMap.
Joshua Haberman4111d132021-12-04 18:42:53 -0800746}
747
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700748static PyObject* PyUpb_Message_ToString(PyUpb_Message* self) {
749 if (PyUpb_Message_IsStub(self)) {
Joshua Haberman4111d132021-12-04 18:42:53 -0800750 return PyUnicode_FromStringAndSize(NULL, 0);
751 }
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700752 upb_Message* msg = PyUpb_Message_GetMsg(self);
753 const upb_MessageDef* msgdef = _PyUpb_Message_GetMsgdef(self);
Joshua Haberman1c955f32022-01-12 07:19:28 -0800754 const upb_DefPool* symtab = upb_FileDef_Pool(upb_MessageDef_File(msgdef));
Joshua Haberman4111d132021-12-04 18:42:53 -0800755 char buf[1024];
756 int options = UPB_TXTENC_SKIPUNKNOWN;
Joshua Habermancd214fe2022-01-12 10:43:49 -0800757 size_t size = upb_TextEncode(msg, msgdef, symtab, options, buf, sizeof(buf));
Joshua Haberman4111d132021-12-04 18:42:53 -0800758 if (size < sizeof(buf)) {
759 return PyUnicode_FromStringAndSize(buf, size);
760 } else {
761 char* buf2 = malloc(size + 1);
Joshua Habermancd214fe2022-01-12 10:43:49 -0800762 size_t size2 = upb_TextEncode(msg, msgdef, symtab, options, buf2, size + 1);
Joshua Haberman4111d132021-12-04 18:42:53 -0800763 assert(size == size2);
764 PyObject* ret = PyUnicode_FromStringAndSize(buf2, size2);
765 free(buf2);
766 return ret;
767 }
768}
769
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700770static PyObject* PyUpb_Message_RichCompare(PyObject* _self, PyObject* other,
771 int opid) {
772 PyUpb_Message* self = (void*)_self;
Joshua Haberman4111d132021-12-04 18:42:53 -0800773 if (opid != Py_EQ && opid != Py_NE) {
774 Py_INCREF(Py_NotImplemented);
775 return Py_NotImplemented;
776 }
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700777 bool ret = PyUpb_Message_IsEqual(self, other);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800778 if (opid == Py_NE) ret = !ret;
Joshua Haberman4111d132021-12-04 18:42:53 -0800779 return PyBool_FromLong(ret);
780}
781
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700782void PyUpb_Message_CacheDelete(PyObject* _self, const upb_FieldDef* f) {
783 PyUpb_Message* self = (void*)_self;
Joshua Haberman4111d132021-12-04 18:42:53 -0800784 PyUpb_WeakMap_Delete(self->unset_subobj_map, f);
785}
786
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700787void PyUpb_Message_SetConcreteSubobj(PyObject* _self, const upb_FieldDef* f,
788 upb_MessageValue subobj) {
789 PyUpb_Message* self = (void*)_self;
790 PyUpb_Message_EnsureReified(self);
791 PyUpb_Message_CacheDelete(_self, f);
Eric Salob747edb2022-12-05 08:40:10 -0800792 upb_Message_SetFieldByDef(self->ptr.msg, f, subobj,
793 PyUpb_Arena_Get(self->arena));
Joshua Haberman4111d132021-12-04 18:42:53 -0800794}
795
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700796static void PyUpb_Message_Dealloc(PyObject* _self) {
797 PyUpb_Message* self = (void*)_self;
Joshua Haberman4111d132021-12-04 18:42:53 -0800798
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700799 if (PyUpb_Message_IsStub(self)) {
800 PyUpb_Message_CacheDelete((PyObject*)self->ptr.parent,
801 PyUpb_Message_GetFieldDef(self));
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800802 Py_DECREF(self->ptr.parent);
Joshua Haberman4111d132021-12-04 18:42:53 -0800803 } else {
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800804 PyUpb_ObjCache_Delete(self->ptr.msg);
Joshua Haberman4111d132021-12-04 18:42:53 -0800805 }
806
807 if (self->unset_subobj_map) {
808 PyUpb_WeakMap_Free(self->unset_subobj_map);
809 }
810
811 Py_DECREF(self->arena);
812
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700813 // We do not use PyUpb_Dealloc() here because Message is a base type and for
Joshua Haberman4111d132021-12-04 18:42:53 -0800814 // base types there is a bug we have to work around in this case (see below).
815 PyTypeObject* tp = Py_TYPE(self);
816 freefunc tp_free = PyType_GetSlot(tp, Py_tp_free);
817 tp_free(self);
818
819 if (cpython_bits.python_version_hex >= 0x03080000) {
820 // Prior to Python 3.8 there is a bug where deallocating the type here would
821 // lead to a double-decref: https://bugs.python.org/issue37879
822 Py_DECREF(tp);
823 }
824}
825
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700826PyObject* PyUpb_Message_Get(upb_Message* u_msg, const upb_MessageDef* m,
827 PyObject* arena) {
Joshua Haberman4111d132021-12-04 18:42:53 -0800828 PyObject* ret = PyUpb_ObjCache_Get(u_msg);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800829 if (ret) return ret;
Joshua Haberman4111d132021-12-04 18:42:53 -0800830
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800831 PyObject* cls = PyUpb_Descriptor_GetClass(m);
832 // It is not safe to use PyObject_{,GC}_New() due to:
833 // https://bugs.python.org/issue35810
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700834 PyUpb_Message* py_msg = (void*)PyType_GenericAlloc((PyTypeObject*)cls, 0);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800835 py_msg->arena = arena;
836 py_msg->def = (uintptr_t)m;
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800837 py_msg->ptr.msg = u_msg;
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800838 py_msg->unset_subobj_map = NULL;
839 py_msg->ext_dict = NULL;
840 py_msg->version = 0;
841 ret = &py_msg->ob_base;
842 Py_DECREF(cls);
843 Py_INCREF(arena);
844 PyUpb_ObjCache_Add(u_msg, ret);
845 return ret;
846}
847
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700848/* PyUpb_Message_GetStub()
Joshua Habermane5d8d282022-01-05 15:47:59 -0800849 *
850 * Non-present messages return "stub" objects that point to their parent, but
851 * will materialize into real upb objects if they are mutated.
Joshua Haberman1c955f32022-01-12 07:19:28 -0800852 *
Joshua Habermane5d8d282022-01-05 15:47:59 -0800853 * Note: we do *not* create stubs for repeated/map fields unless the parent
854 * is a stub:
Joshua Haberman1c955f32022-01-12 07:19:28 -0800855 *
Joshua Habermane5d8d282022-01-05 15:47:59 -0800856 * msg = TestMessage()
857 * msg.submessage # (A) Creates a stub
858 * msg.repeated_foo # (B) Does *not* create a stub
859 * msg.submessage.repeated_bar # (C) Creates a stub
Joshua Haberman1c955f32022-01-12 07:19:28 -0800860 *
Joshua Habermane5d8d282022-01-05 15:47:59 -0800861 * In case (B) we have some freedom: we could either create a stub, or create
862 * a reified object with underlying data. It appears that either could work
863 * equally well, with no observable change to users. There isn't a clear
864 * advantage to either choice. We choose to follow the behavior of the
865 * pre-existing C++ behavior for consistency, but if it becomes apparent that
866 * there would be some benefit to reversing this decision, it should be totally
867 * within the realm of possibility.
868 */
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700869PyObject* PyUpb_Message_GetStub(PyUpb_Message* self,
870 const upb_FieldDef* field) {
Joshua Haberman455426e2021-12-08 23:32:05 -0800871 PyObject* _self = (void*)self;
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800872 if (!self->unset_subobj_map) {
873 self->unset_subobj_map = PyUpb_WeakMap_New();
874 }
875 PyObject* subobj = PyUpb_WeakMap_Get(self->unset_subobj_map, field);
876
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800877 if (subobj) return subobj;
878
Joshua Haberman1c955f32022-01-12 07:19:28 -0800879 if (upb_FieldDef_IsMap(field)) {
Joshua Habermanfaac2d82021-12-30 01:04:49 -0800880 subobj = PyUpb_MapContainer_NewStub(_self, field, self->arena);
Joshua Haberman1c955f32022-01-12 07:19:28 -0800881 } else if (upb_FieldDef_IsRepeated(field)) {
Joshua Habermanfaac2d82021-12-30 01:04:49 -0800882 subobj = PyUpb_RepeatedContainer_NewStub(_self, field, self->arena);
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800883 } else {
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700884 subobj = PyUpb_Message_NewStub(&self->ob_base, field, self->arena);
Joshua Haberman4111d132021-12-04 18:42:53 -0800885 }
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800886 PyUpb_WeakMap_Add(self->unset_subobj_map, field, subobj);
Joshua Haberman4111d132021-12-04 18:42:53 -0800887
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800888 assert(!PyErr_Occurred());
889 return subobj;
890}
891
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700892PyObject* PyUpb_Message_GetPresentWrapper(PyUpb_Message* self,
893 const upb_FieldDef* field) {
894 assert(!PyUpb_Message_IsStub(self));
Joshua Haberman1c955f32022-01-12 07:19:28 -0800895 upb_MutableMessageValue mutval =
896 upb_Message_Mutable(self->ptr.msg, field, PyUpb_Arena_Get(self->arena));
897 if (upb_FieldDef_IsMap(field)) {
Joshua Habermanbf74b3e2021-12-30 00:52:12 -0800898 return PyUpb_MapContainer_GetOrCreateWrapper(mutval.map, field,
899 self->arena);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800900 } else {
Joshua Haberman455426e2021-12-08 23:32:05 -0800901 return PyUpb_RepeatedContainer_GetOrCreateWrapper(mutval.array, field,
902 self->arena);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800903 }
904}
905
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700906PyObject* PyUpb_Message_GetScalarValue(PyUpb_Message* self,
907 const upb_FieldDef* field) {
Joshua Haberman1c955f32022-01-12 07:19:28 -0800908 upb_MessageValue val;
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700909 if (PyUpb_Message_IsStub(self)) {
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800910 // Unset message always returns default values.
Joshua Haberman1c955f32022-01-12 07:19:28 -0800911 val = upb_FieldDef_Default(field);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800912 } else {
Eric Salob747edb2022-12-05 08:40:10 -0800913 val = upb_Message_GetFieldByDef(self->ptr.msg, field);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800914 }
915 return PyUpb_UpbToPy(val, field, self->arena);
Joshua Haberman4111d132021-12-04 18:42:53 -0800916}
917
Joshua Habermaneb38a2a2021-12-05 23:54:34 -0800918/*
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700919 * PyUpb_Message_GetFieldValue()
Joshua Habermaneb38a2a2021-12-05 23:54:34 -0800920 *
921 * Implements the equivalent of getattr(msg, field), once `field` has
Joshua Haberman1c955f32022-01-12 07:19:28 -0800922 * already been resolved to a `upb_FieldDef*`.
Joshua Habermaneb38a2a2021-12-05 23:54:34 -0800923 *
924 * This may involve constructing a wrapper object for the given field, or
925 * returning one that was previously constructed. If the field is not actually
926 * set, the wrapper object will be an "unset" object that is not actually
927 * connected to any C data.
928 */
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700929PyObject* PyUpb_Message_GetFieldValue(PyObject* _self,
930 const upb_FieldDef* field) {
931 PyUpb_Message* self = (void*)_self;
932 assert(upb_FieldDef_ContainingType(field) == PyUpb_Message_GetMsgdef(_self));
Joshua Haberman1c955f32022-01-12 07:19:28 -0800933 bool submsg = upb_FieldDef_IsSubMessage(field);
934 bool seq = upb_FieldDef_IsRepeated(field);
Joshua Haberman4111d132021-12-04 18:42:53 -0800935
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700936 if ((PyUpb_Message_IsStub(self) && (submsg || seq)) ||
Eric Salob747edb2022-12-05 08:40:10 -0800937 (submsg && !seq && !upb_Message_HasFieldByDef(self->ptr.msg, field))) {
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700938 return PyUpb_Message_GetStub(self, field);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800939 } else if (seq) {
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700940 return PyUpb_Message_GetPresentWrapper(self, field);
Joshua Haberman4111d132021-12-04 18:42:53 -0800941 } else {
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700942 return PyUpb_Message_GetScalarValue(self, field);
Joshua Haberman4111d132021-12-04 18:42:53 -0800943 }
944}
945
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700946int PyUpb_Message_SetFieldValue(PyObject* _self, const upb_FieldDef* field,
947 PyObject* value, PyObject* exc) {
948 PyUpb_Message* self = (void*)_self;
Joshua Haberman0549fc02022-01-01 15:42:51 -0800949 assert(value);
950
Joshua Haberman1c955f32022-01-12 07:19:28 -0800951 if (upb_FieldDef_IsSubMessage(field) || upb_FieldDef_IsRepeated(field)) {
Joshua Haberman3eae44b2022-01-09 22:08:08 -0800952 PyErr_Format(exc,
Joshua Haberman4111d132021-12-04 18:42:53 -0800953 "Assignment not allowed to message, map, or repeated "
954 "field \"%s\" in protocol message object.",
Joshua Haberman1c955f32022-01-12 07:19:28 -0800955 upb_FieldDef_Name(field));
Joshua Haberman4111d132021-12-04 18:42:53 -0800956 return -1;
957 }
958
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700959 PyUpb_Message_EnsureReified(self);
Joshua Haberman4111d132021-12-04 18:42:53 -0800960
Joshua Haberman1c955f32022-01-12 07:19:28 -0800961 upb_MessageValue val;
962 upb_Arena* arena = PyUpb_Arena_Get(self->arena);
Joshua Haberman4111d132021-12-04 18:42:53 -0800963 if (!PyUpb_PyToUpb(value, field, &val, arena)) {
964 return -1;
965 }
966
Eric Salob747edb2022-12-05 08:40:10 -0800967 upb_Message_SetFieldByDef(self->ptr.msg, field, val, arena);
Joshua Haberman4111d132021-12-04 18:42:53 -0800968 return 0;
969}
970
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700971int PyUpb_Message_GetVersion(PyObject* _self) {
972 PyUpb_Message* self = (void*)_self;
Joshua Haberman4111d132021-12-04 18:42:53 -0800973 return self->version;
974}
975
Joshua Haberman4111d132021-12-04 18:42:53 -0800976/*
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700977 * PyUpb_Message_GetAttr()
Joshua Haberman4111d132021-12-04 18:42:53 -0800978 *
979 * Implements:
980 * foo = msg.foo
981 *
982 * Attribute lookup must find both message fields and base class methods like
983 * msg.SerializeToString().
984 */
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700985__attribute__((flatten)) static PyObject* PyUpb_Message_GetAttr(
Joshua Haberman4111d132021-12-04 18:42:53 -0800986 PyObject* _self, PyObject* attr) {
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700987 PyUpb_Message* self = (void*)_self;
Joshua Haberman4111d132021-12-04 18:42:53 -0800988
989 // Lookup field by name.
Joshua Haberman1c955f32022-01-12 07:19:28 -0800990 const upb_FieldDef* field;
Joshua Haberman12fffeb2022-05-17 14:00:49 -0700991 if (PyUpb_Message_LookupName(self, attr, &field, NULL, NULL)) {
992 return PyUpb_Message_GetFieldValue(_self, field);
Joshua Haberman4111d132021-12-04 18:42:53 -0800993 }
994
995 // Check base class attributes.
996 assert(!PyErr_Occurred());
997 PyObject* ret = PyObject_GenericGetAttr(_self, attr);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800998 if (ret) return ret;
Joshua Haberman4111d132021-12-04 18:42:53 -0800999
Joshua Haberman14372452021-12-31 12:02:36 -08001000 // Swallow AttributeError if it occurred and try again on the metaclass
1001 // to pick up class attributes. But we have to special-case "Extensions"
1002 // which affirmatively returns AttributeError when a message is not
1003 // extendable.
Joshua Habermanb38e4a42022-01-16 19:27:55 -08001004 const char* name;
Joshua Haberman14372452021-12-31 12:02:36 -08001005 if (PyErr_ExceptionMatches(PyExc_AttributeError) &&
Joshua Habermanb38e4a42022-01-16 19:27:55 -08001006 (name = PyUpb_GetStrData(attr)) && strcmp(name, "Extensions") != 0) {
Joshua Habermanc42beeb2021-12-06 23:07:14 -08001007 PyErr_Clear();
1008 return PyUpb_MessageMeta_GetAttr((PyObject*)Py_TYPE(_self), attr);
Joshua Haberman4111d132021-12-04 18:42:53 -08001009 }
Joshua Haberman4111d132021-12-04 18:42:53 -08001010
Joshua Habermanc42beeb2021-12-06 23:07:14 -08001011 return NULL;
Joshua Haberman4111d132021-12-04 18:42:53 -08001012}
1013
1014/*
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001015 * PyUpb_Message_SetAttr()
Joshua Haberman4111d132021-12-04 18:42:53 -08001016 *
1017 * Implements:
1018 * msg.foo = foo
1019 */
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001020static int PyUpb_Message_SetAttr(PyObject* _self, PyObject* attr,
1021 PyObject* value) {
1022 PyUpb_Message* self = (void*)_self;
Joshua Haberman1c955f32022-01-12 07:19:28 -08001023 const upb_FieldDef* field;
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001024 if (!PyUpb_Message_LookupName(self, attr, &field, NULL,
1025 PyExc_AttributeError)) {
Joshua Haberman4111d132021-12-04 18:42:53 -08001026 return -1;
1027 }
1028
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001029 return PyUpb_Message_SetFieldValue(_self, field, value, PyExc_AttributeError);
Joshua Haberman4111d132021-12-04 18:42:53 -08001030}
1031
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001032static PyObject* PyUpb_Message_HasField(PyObject* _self, PyObject* arg) {
1033 PyUpb_Message* self = (void*)_self;
Joshua Haberman1c955f32022-01-12 07:19:28 -08001034 const upb_FieldDef* field;
1035 const upb_OneofDef* oneof;
Joshua Haberman4111d132021-12-04 18:42:53 -08001036
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001037 if (!PyUpb_Message_LookupName(self, arg, &field, &oneof, PyExc_ValueError)) {
Joshua Haberman4111d132021-12-04 18:42:53 -08001038 return NULL;
1039 }
1040
Joshua Haberman1c955f32022-01-12 07:19:28 -08001041 if (field && !upb_FieldDef_HasPresence(field)) {
Joshua Haberman4111d132021-12-04 18:42:53 -08001042 PyErr_Format(PyExc_ValueError, "Field %s does not have presence.",
Joshua Haberman1c955f32022-01-12 07:19:28 -08001043 upb_FieldDef_FullName(field));
Joshua Haberman4111d132021-12-04 18:42:53 -08001044 return NULL;
1045 }
1046
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001047 if (PyUpb_Message_IsStub(self)) Py_RETURN_FALSE;
Joshua Haberman4111d132021-12-04 18:42:53 -08001048
Eric Salob747edb2022-12-05 08:40:10 -08001049 return PyBool_FromLong(field ? upb_Message_HasFieldByDef(self->ptr.msg, field)
Joshua Haberman1c955f32022-01-12 07:19:28 -08001050 : upb_Message_WhichOneof(self->ptr.msg, oneof) !=
1051 NULL);
Joshua Haberman4111d132021-12-04 18:42:53 -08001052}
1053
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001054static PyObject* PyUpb_Message_FindInitializationErrors(PyObject* _self,
1055 PyObject* arg);
Joshua Habermancbe314d2022-01-09 17:25:10 -08001056
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001057static PyObject* PyUpb_Message_IsInitializedAppendErrors(PyObject* _self,
1058 PyObject* errors) {
1059 PyObject* list = PyUpb_Message_FindInitializationErrors(_self, NULL);
Joshua Habermand8915b32022-01-09 23:04:44 -08001060 if (!list) return NULL;
Joshua Haberman8c256cc2022-01-10 10:00:10 -08001061 bool ok = PyList_Size(list) == 0;
1062 PyObject* ret = NULL;
Joshua Haberman201d2262022-01-10 10:05:09 -08001063 PyObject* extend_result = NULL;
Joshua Haberman8c256cc2022-01-10 10:00:10 -08001064 if (!ok) {
Joshua Haberman201d2262022-01-10 10:05:09 -08001065 extend_result = PyObject_CallMethod(errors, "extend", "O", list);
1066 if (!extend_result) goto done;
Joshua Haberman8c256cc2022-01-10 10:00:10 -08001067 }
1068 ret = PyBool_FromLong(ok);
1069
1070done:
Joshua Habermand8915b32022-01-09 23:04:44 -08001071 Py_XDECREF(list);
Joshua Haberman201d2262022-01-10 10:05:09 -08001072 Py_XDECREF(extend_result);
Joshua Haberman8c256cc2022-01-10 10:00:10 -08001073 return ret;
Joshua Habermand8915b32022-01-09 23:04:44 -08001074}
1075
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001076static PyObject* PyUpb_Message_IsInitialized(PyObject* _self, PyObject* args) {
Joshua Habermancbe314d2022-01-09 17:25:10 -08001077 PyObject* errors = NULL;
1078 if (!PyArg_ParseTuple(args, "|O", &errors)) {
1079 return NULL;
1080 }
Joshua Habermancbe314d2022-01-09 17:25:10 -08001081 if (errors) {
Joshua Habermand8915b32022-01-09 23:04:44 -08001082 // We need to collect a list of unset required fields and append it to
1083 // `errors`.
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001084 return PyUpb_Message_IsInitializedAppendErrors(_self, errors);
Joshua Habermancbe314d2022-01-09 17:25:10 -08001085 } else {
Joshua Habermand8915b32022-01-09 23:04:44 -08001086 // We just need to return a boolean "true" or "false" for whether all
1087 // required fields are set.
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001088 upb_Message* msg = PyUpb_Message_GetIfReified(_self);
1089 const upb_MessageDef* m = PyUpb_Message_GetMsgdef(_self);
Joshua Haberman1c955f32022-01-12 07:19:28 -08001090 const upb_DefPool* symtab = upb_FileDef_Pool(upb_MessageDef_File(m));
Joshua Habermancbe314d2022-01-09 17:25:10 -08001091 bool initialized = !upb_util_HasUnsetRequired(msg, m, symtab, NULL);
1092 return PyBool_FromLong(initialized);
1093 }
1094}
1095
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001096static PyObject* PyUpb_Message_ListFieldsItemKey(PyObject* self,
1097 PyObject* val) {
Joshua Haberman4993f7a2022-01-09 18:51:10 -08001098 assert(PyTuple_Check(val));
1099 PyObject* field = PyTuple_GetItem(val, 0);
Joshua Haberman1c955f32022-01-12 07:19:28 -08001100 const upb_FieldDef* f = PyUpb_FieldDescriptor_GetDef(field);
1101 return PyLong_FromLong(upb_FieldDef_Number(f));
Joshua Haberman4993f7a2022-01-09 18:51:10 -08001102}
1103
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001104static PyObject* PyUpb_Message_CheckCalledFromGeneratedFile(
Joshua Haberman4e2bbc82022-05-17 10:08:55 -07001105 PyObject* unused, PyObject* unused_arg) {
1106 PyErr_SetString(
1107 PyExc_TypeError,
1108 "Descriptors cannot not be created directly.\n"
1109 "If this call came from a _pb2.py file, your generated code is out of "
1110 "date and must be regenerated with protoc >= 3.19.0.\n"
1111 "If you cannot immediately regenerate your protos, some other possible "
1112 "workarounds are:\n"
1113 " 1. Downgrade the protobuf package to 3.20.x or lower.\n"
1114 " 2. Set PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python (but this will "
1115 "use pure-Python parsing and will be much slower).\n"
1116 "\n"
1117 "More information: "
1118 "https://developers.google.com/protocol-buffers/docs/news/"
1119 "2022-05-06#python-updates");
1120 return NULL;
1121}
1122
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001123static bool PyUpb_Message_SortFieldList(PyObject* list) {
Joshua Habermand4c0c632022-01-09 23:16:18 -08001124 PyUpb_ModuleState* state = PyUpb_ModuleState_Get();
1125 bool ok = false;
Joshua Habermanffdcc462022-01-12 08:38:36 -08001126 PyObject* args = PyTuple_New(0);
Joshua Habermand4c0c632022-01-09 23:16:18 -08001127 PyObject* kwargs = PyDict_New();
Joshua Haberman4c005382022-01-09 23:17:20 -08001128 PyObject* method = PyObject_GetAttrString(list, "sort");
Joshua Haberman8c256cc2022-01-10 10:00:10 -08001129 PyObject* call_result = NULL;
Joshua Haberman4c005382022-01-09 23:17:20 -08001130 if (!args || !kwargs || !method) goto err;
Joshua Habermand4c0c632022-01-09 23:16:18 -08001131 if (PyDict_SetItemString(kwargs, "key", state->listfields_item_key) < 0) {
1132 goto err;
1133 }
Joshua Haberman8c256cc2022-01-10 10:00:10 -08001134 call_result = PyObject_Call(method, args, kwargs);
1135 if (!call_result) goto err;
Joshua Habermand4c0c632022-01-09 23:16:18 -08001136 ok = true;
1137
Joshua Haberman1c955f32022-01-12 07:19:28 -08001138err:
Joshua Haberman4c005382022-01-09 23:17:20 -08001139 Py_XDECREF(method);
Joshua Habermand4c0c632022-01-09 23:16:18 -08001140 Py_XDECREF(args);
1141 Py_XDECREF(kwargs);
Joshua Haberman8c256cc2022-01-10 10:00:10 -08001142 Py_XDECREF(call_result);
1143 return ok;
Joshua Habermand4c0c632022-01-09 23:16:18 -08001144}
1145
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001146static PyObject* PyUpb_Message_ListFields(PyObject* _self, PyObject* arg) {
Joshua Haberman4111d132021-12-04 18:42:53 -08001147 PyObject* list = PyList_New(0);
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001148 upb_Message* msg = PyUpb_Message_GetIfReified(_self);
Joshua Haberman4423e912021-12-27 18:04:58 -08001149 if (!msg) return list;
Joshua Haberman4111d132021-12-04 18:42:53 -08001150
Joshua Haberman1c955f32022-01-12 07:19:28 -08001151 size_t iter1 = kUpb_Message_Begin;
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001152 const upb_MessageDef* m = PyUpb_Message_GetMsgdef(_self);
Joshua Haberman1c955f32022-01-12 07:19:28 -08001153 const upb_DefPool* symtab = upb_FileDef_Pool(upb_MessageDef_File(m));
1154 const upb_FieldDef* f;
Joshua Haberman4423e912021-12-27 18:04:58 -08001155 PyObject* field_desc = NULL;
1156 PyObject* py_val = NULL;
1157 PyObject* tuple = NULL;
Joshua Haberman1c955f32022-01-12 07:19:28 -08001158 upb_MessageValue val;
Joshua Haberman4993f7a2022-01-09 18:51:10 -08001159 uint32_t last_field = 0;
1160 bool in_order = true;
Joshua Haberman1c955f32022-01-12 07:19:28 -08001161 while (upb_Message_Next(msg, m, symtab, &f, &val, &iter1)) {
1162 const uint32_t field_number = upb_FieldDef_Number(f);
Joshua Haberman4993f7a2022-01-09 18:51:10 -08001163 if (field_number < last_field) in_order = false;
1164 last_field = field_number;
Joshua Haberman4423e912021-12-27 18:04:58 -08001165 PyObject* field_desc = PyUpb_FieldDescriptor_Get(f);
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001166 PyObject* py_val = PyUpb_Message_GetFieldValue(_self, f);
Joshua Haberman4423e912021-12-27 18:04:58 -08001167 if (!field_desc || !py_val) goto err;
1168 PyObject* tuple = Py_BuildValue("(NN)", field_desc, py_val);
1169 field_desc = NULL;
1170 py_val = NULL;
1171 if (!tuple) goto err;
Joshua Habermanaee30142021-12-28 20:27:17 -08001172 if (PyList_Append(list, tuple)) goto err;
Joshua Haberman4423e912021-12-27 18:04:58 -08001173 Py_DECREF(tuple);
1174 tuple = NULL;
Joshua Haberman4111d132021-12-04 18:42:53 -08001175 }
1176
Joshua Haberman4c005382022-01-09 23:17:20 -08001177 // Users rely on fields being returned in field number order.
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001178 if (!in_order && !PyUpb_Message_SortFieldList(list)) goto err;
Joshua Haberman4c005382022-01-09 23:17:20 -08001179
Joshua Haberman4111d132021-12-04 18:42:53 -08001180 return list;
Joshua Haberman4423e912021-12-27 18:04:58 -08001181
1182err:
1183 Py_XDECREF(field_desc);
1184 Py_XDECREF(py_val);
1185 Py_XDECREF(tuple);
1186 Py_DECREF(list);
1187 return NULL;
Joshua Haberman4111d132021-12-04 18:42:53 -08001188}
1189
Eric Saloea4cb792023-03-22 07:25:40 -07001190static PyObject* PyUpb_Message_MergeInternal(PyObject* self, PyObject* arg,
1191 bool check_required) {
Joshua Haberman4111d132021-12-04 18:42:53 -08001192 if (self->ob_type != arg->ob_type) {
1193 PyErr_Format(PyExc_TypeError,
1194 "Parameter to MergeFrom() must be instance of same class: "
1195 "expected %S got %S.",
1196 Py_TYPE(self), Py_TYPE(arg));
1197 return NULL;
1198 }
1199 // OPT: exit if src is empty.
1200 PyObject* subargs = PyTuple_New(0);
Eric Saloea4cb792023-03-22 07:25:40 -07001201 PyObject* serialized =
1202 check_required
1203 ? PyUpb_Message_SerializeToString(arg, subargs, NULL)
1204 : PyUpb_Message_SerializePartialToString(arg, subargs, NULL);
Joshua Haberman4111d132021-12-04 18:42:53 -08001205 Py_DECREF(subargs);
1206 if (!serialized) return NULL;
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001207 PyObject* ret = PyUpb_Message_MergeFromString(self, serialized);
Joshua Haberman4111d132021-12-04 18:42:53 -08001208 Py_DECREF(serialized);
1209 Py_DECREF(ret);
1210 Py_RETURN_NONE;
1211}
1212
Eric Saloea4cb792023-03-22 07:25:40 -07001213PyObject* PyUpb_Message_MergeFrom(PyObject* self, PyObject* arg) {
1214 return PyUpb_Message_MergeInternal(self, arg, true);
1215}
1216
1217static PyObject* PyUpb_Message_MergePartialFrom(PyObject* self, PyObject* arg) {
1218 return PyUpb_Message_MergeInternal(self, arg, false);
1219}
1220
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001221static PyObject* PyUpb_Message_SetInParent(PyObject* _self, PyObject* arg) {
1222 PyUpb_Message* self = (void*)_self;
1223 PyUpb_Message_EnsureReified(self);
Joshua Haberman4111d132021-12-04 18:42:53 -08001224 Py_RETURN_NONE;
1225}
1226
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001227static PyObject* PyUpb_Message_UnknownFields(PyObject* _self, PyObject* arg) {
Joshua Haberman4111d132021-12-04 18:42:53 -08001228 // TODO(haberman): re-enable when unknown fields are added.
1229 // return PyUpb_UnknownFields_New(_self);
1230 PyErr_SetString(PyExc_NotImplementedError, "unknown field accessor");
1231 return NULL;
1232}
1233
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001234PyObject* PyUpb_Message_MergeFromString(PyObject* _self, PyObject* arg) {
1235 PyUpb_Message* self = (void*)_self;
Joshua Haberman4111d132021-12-04 18:42:53 -08001236 char* buf;
1237 Py_ssize_t size;
1238 PyObject* bytes = NULL;
1239
1240 if (PyMemoryView_Check(arg)) {
1241 bytes = PyBytes_FromObject(arg);
Joshua Haberman6bb891e2021-12-08 15:29:48 -08001242 // Cannot fail when passed something of the correct type.
1243 int err = PyBytes_AsStringAndSize(bytes, &buf, &size);
1244 (void)err;
1245 assert(err >= 0);
Joshua Haberman4111d132021-12-04 18:42:53 -08001246 } else if (PyBytes_AsStringAndSize(arg, &buf, &size) < 0) {
1247 return NULL;
1248 }
1249
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001250 PyUpb_Message_EnsureReified(self);
1251 const upb_MessageDef* msgdef = _PyUpb_Message_GetMsgdef(self);
Joshua Haberman1c955f32022-01-12 07:19:28 -08001252 const upb_FileDef* file = upb_MessageDef_File(msgdef);
Joshua Haberman499c2cc2022-01-12 09:09:59 -08001253 const upb_ExtensionRegistry* extreg =
Joshua Haberman1c955f32022-01-12 07:19:28 -08001254 upb_DefPool_ExtensionRegistry(upb_FileDef_Pool(file));
1255 const upb_MiniTable* layout = upb_MessageDef_MiniTable(msgdef);
1256 upb_Arena* arena = PyUpb_Arena_Get(self->arena);
Joshua Haberman14372452021-12-31 12:02:36 -08001257 PyUpb_ModuleState* state = PyUpb_ModuleState_Get();
Protobuf Team Bot9d2b5d12023-04-09 10:01:22 -07001258 int options = upb_DecodeOptions_MaxDepth(
1259 state->allow_oversize_protos ? UINT16_MAX
1260 : kUpb_WireFormat_DefaultDepthLimit);
Joshua Haberman4111d132021-12-04 18:42:53 -08001261 upb_DecodeStatus status =
Joshua Haberman72af9dc2022-01-12 10:04:02 -08001262 upb_Decode(buf, size, self->ptr.msg, layout, extreg, options, arena);
Joshua Haberman4111d132021-12-04 18:42:53 -08001263 Py_XDECREF(bytes);
1264 if (status != kUpb_DecodeStatus_Ok) {
Joshua Haberman4111d132021-12-04 18:42:53 -08001265 PyErr_Format(state->decode_error_class, "Error parsing message");
1266 return NULL;
1267 }
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001268 PyUpb_Message_SyncSubobjs(self);
Joshua Haberman4111d132021-12-04 18:42:53 -08001269 return PyLong_FromSsize_t(size);
1270}
1271
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001272static PyObject* PyUpb_Message_Clear(PyUpb_Message* self, PyObject* args);
Joshua Haberman4111d132021-12-04 18:42:53 -08001273
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001274static PyObject* PyUpb_Message_ParseFromString(PyObject* self, PyObject* arg) {
1275 PyObject* tmp = PyUpb_Message_Clear((PyUpb_Message*)self, NULL);
Joshua Haberman4111d132021-12-04 18:42:53 -08001276 Py_DECREF(tmp);
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001277 return PyUpb_Message_MergeFromString(self, arg);
Joshua Haberman4111d132021-12-04 18:42:53 -08001278}
1279
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001280static PyObject* PyUpb_Message_ByteSize(PyObject* self, PyObject* args) {
Joshua Haberman6bb891e2021-12-08 15:29:48 -08001281 // TODO(https://github.com/protocolbuffers/upb/issues/462): At the moment upb
1282 // does not have a "byte size" function, so we just serialize to string and
1283 // get the size of the string.
Joshua Haberman4111d132021-12-04 18:42:53 -08001284 PyObject* subargs = PyTuple_New(0);
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001285 PyObject* serialized = PyUpb_Message_SerializeToString(self, subargs, NULL);
Joshua Haberman4111d132021-12-04 18:42:53 -08001286 Py_DECREF(subargs);
1287 if (!serialized) return NULL;
1288 size_t size = PyBytes_Size(serialized);
1289 Py_DECREF(serialized);
1290 return PyLong_FromSize_t(size);
1291}
1292
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001293static PyObject* PyUpb_Message_Clear(PyUpb_Message* self, PyObject* args) {
1294 PyUpb_Message_EnsureReified(self);
1295 const upb_MessageDef* msgdef = _PyUpb_Message_GetMsgdef(self);
Joshua Haberman1be47592022-01-09 10:27:09 -08001296 PyUpb_WeakMap* subobj_map = self->unset_subobj_map;
1297
1298 if (subobj_map) {
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001299 upb_Message* msg = PyUpb_Message_GetMsg(self);
Joshua Habermanc3cfd092022-05-10 08:52:45 -07001300 (void)msg; // Suppress unused warning when asserts are disabled.
Joshua Haberman1be47592022-01-09 10:27:09 -08001301 intptr_t iter = PYUPB_WEAKMAP_BEGIN;
1302 const void* key;
1303 PyObject* obj;
1304
1305 while (PyUpb_WeakMap_Next(subobj_map, &key, &obj, &iter)) {
Joshua Haberman1c955f32022-01-12 07:19:28 -08001306 const upb_FieldDef* f = key;
Joshua Haberman1be47592022-01-09 10:27:09 -08001307 PyUpb_WeakMap_DeleteIter(subobj_map, &iter);
Joshua Haberman1c955f32022-01-12 07:19:28 -08001308 if (upb_FieldDef_IsMap(f)) {
Eric Salob747edb2022-12-05 08:40:10 -08001309 assert(upb_Message_GetFieldByDef(msg, f).map_val == NULL);
Joshua Haberman1be47592022-01-09 10:27:09 -08001310 PyUpb_MapContainer_Reify(obj, NULL);
Joshua Haberman1c955f32022-01-12 07:19:28 -08001311 } else if (upb_FieldDef_IsRepeated(f)) {
Eric Salob747edb2022-12-05 08:40:10 -08001312 assert(upb_Message_GetFieldByDef(msg, f).array_val == NULL);
Joshua Haberman1be47592022-01-09 10:27:09 -08001313 PyUpb_RepeatedContainer_Reify(obj, NULL);
1314 } else {
Eric Salob747edb2022-12-05 08:40:10 -08001315 assert(!upb_Message_HasFieldByDef(msg, f));
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001316 PyUpb_Message* sub = (void*)obj;
Joshua Haberman1be47592022-01-09 10:27:09 -08001317 assert(self == sub->ptr.parent);
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001318 PyUpb_Message_Reify(sub, f, NULL);
Joshua Haberman1be47592022-01-09 10:27:09 -08001319 }
1320 }
1321 }
1322
Eric Salob747edb2022-12-05 08:40:10 -08001323 upb_Message_ClearByDef(self->ptr.msg, msgdef);
Joshua Haberman4111d132021-12-04 18:42:53 -08001324 Py_RETURN_NONE;
1325}
1326
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001327void PyUpb_Message_DoClearField(PyObject* _self, const upb_FieldDef* f) {
1328 PyUpb_Message* self = (void*)_self;
1329 PyUpb_Message_EnsureReified((PyUpb_Message*)self);
Joshua Haberman54b775d2022-01-05 12:55:52 -08001330
1331 // We must ensure that any stub object is reified so its parent no longer
1332 // points to us.
1333 PyObject* sub = self->unset_subobj_map
1334 ? PyUpb_WeakMap_Get(self->unset_subobj_map, f)
1335 : NULL;
Joshua Haberman4111d132021-12-04 18:42:53 -08001336
Joshua Haberman1c955f32022-01-12 07:19:28 -08001337 if (upb_FieldDef_IsMap(f)) {
Joshua Haberman54b775d2022-01-05 12:55:52 -08001338 // For maps we additionally have to invalidate any iterators. So we need
1339 // to get an object even if it's reified.
1340 if (!sub) {
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001341 sub = PyUpb_Message_GetFieldValue(_self, f);
Joshua Haberman4111d132021-12-04 18:42:53 -08001342 }
Joshua Haberman54b775d2022-01-05 12:55:52 -08001343 PyUpb_MapContainer_EnsureReified(sub);
1344 PyUpb_MapContainer_Invalidate(sub);
Joshua Haberman1c955f32022-01-12 07:19:28 -08001345 } else if (upb_FieldDef_IsRepeated(f)) {
Joshua Haberman54b775d2022-01-05 12:55:52 -08001346 if (sub) {
Joshua Habermane5d8d282022-01-05 15:47:59 -08001347 PyUpb_RepeatedContainer_EnsureReified(sub);
Joshua Haberman4111d132021-12-04 18:42:53 -08001348 }
Joshua Haberman1c955f32022-01-12 07:19:28 -08001349 } else if (upb_FieldDef_IsSubMessage(f)) {
Joshua Haberman54b775d2022-01-05 12:55:52 -08001350 if (sub) {
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001351 PyUpb_Message_EnsureReified((PyUpb_Message*)sub);
Joshua Haberman0549fc02022-01-01 15:42:51 -08001352 }
Joshua Haberman4111d132021-12-04 18:42:53 -08001353 }
1354
Joshua Haberman54b775d2022-01-05 12:55:52 -08001355 Py_XDECREF(sub);
Eric Salob747edb2022-12-05 08:40:10 -08001356 upb_Message_ClearFieldByDef(self->ptr.msg, f);
Joshua Haberman0549fc02022-01-01 15:42:51 -08001357}
Joshua Haberman4111d132021-12-04 18:42:53 -08001358
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001359static PyObject* PyUpb_Message_ClearExtension(PyObject* _self, PyObject* arg) {
1360 PyUpb_Message* self = (void*)_self;
1361 PyUpb_Message_EnsureReified(self);
1362 const upb_FieldDef* f = PyUpb_Message_GetExtensionDef(_self, arg);
Joshua Haberman0549fc02022-01-01 15:42:51 -08001363 if (!f) return NULL;
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001364 PyUpb_Message_DoClearField(_self, f);
Joshua Haberman0549fc02022-01-01 15:42:51 -08001365 Py_RETURN_NONE;
1366}
1367
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001368static PyObject* PyUpb_Message_ClearField(PyObject* _self, PyObject* arg) {
1369 PyUpb_Message* self = (void*)_self;
Joshua Haberman0549fc02022-01-01 15:42:51 -08001370
Joshua Haberman54b775d2022-01-05 12:55:52 -08001371 // We always need EnsureReified() here (even for an unset message) to
Joshua Haberman0549fc02022-01-01 15:42:51 -08001372 // preserve behavior like:
1373 // msg = FooMessage()
1374 // msg.foo.Clear()
1375 // assert msg.HasField("foo")
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001376 PyUpb_Message_EnsureReified(self);
Joshua Haberman0549fc02022-01-01 15:42:51 -08001377
Joshua Haberman1c955f32022-01-12 07:19:28 -08001378 const upb_FieldDef* f;
1379 const upb_OneofDef* o;
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001380 if (!PyUpb_Message_LookupName(self, arg, &f, &o, PyExc_ValueError)) {
Joshua Haberman0549fc02022-01-01 15:42:51 -08001381 return NULL;
1382 }
1383
Joshua Haberman1c955f32022-01-12 07:19:28 -08001384 if (o) f = upb_Message_WhichOneof(self->ptr.msg, o);
Eric Salo27f8d362022-09-07 21:44:48 -07001385 if (f) PyUpb_Message_DoClearField(_self, f);
Joshua Haberman4111d132021-12-04 18:42:53 -08001386 Py_RETURN_NONE;
1387}
1388
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001389static PyObject* PyUpb_Message_DiscardUnknownFields(PyUpb_Message* self,
1390 PyObject* arg) {
1391 PyUpb_Message_EnsureReified(self);
1392 const upb_MessageDef* msgdef = _PyUpb_Message_GetMsgdef(self);
Joshua Haberman1c955f32022-01-12 07:19:28 -08001393 upb_Message_DiscardUnknown(self->ptr.msg, msgdef, 64);
Joshua Haberman4111d132021-12-04 18:42:53 -08001394 Py_RETURN_NONE;
1395}
1396
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001397static PyObject* PyUpb_Message_FindInitializationErrors(PyObject* _self,
1398 PyObject* arg) {
1399 PyUpb_Message* self = (void*)_self;
1400 upb_Message* msg = PyUpb_Message_GetIfReified(_self);
1401 const upb_MessageDef* msgdef = _PyUpb_Message_GetMsgdef(self);
Joshua Haberman1c955f32022-01-12 07:19:28 -08001402 const upb_DefPool* ext_pool = upb_FileDef_Pool(upb_MessageDef_File(msgdef));
Joshua Haberman4111d132021-12-04 18:42:53 -08001403 upb_FieldPathEntry* fields;
1404 PyObject* ret = PyList_New(0);
1405 if (upb_util_HasUnsetRequired(msg, msgdef, ext_pool, &fields)) {
1406 char* buf = NULL;
1407 size_t size = 0;
Joshua Habermancbe314d2022-01-09 17:25:10 -08001408 assert(fields->field);
1409 while (fields->field) {
Joshua Haberman4111d132021-12-04 18:42:53 -08001410 upb_FieldPathEntry* field = fields;
1411 size_t need = upb_FieldPath_ToText(&fields, buf, size);
1412 if (need >= size) {
1413 fields = field;
Joshua Habermanc42beeb2021-12-06 23:07:14 -08001414 size = size ? size * 2 : 16;
Joshua Haberman4111d132021-12-04 18:42:53 -08001415 while (size <= need) size *= 2;
1416 buf = realloc(buf, size);
1417 need = upb_FieldPath_ToText(&fields, buf, size);
1418 assert(size > need);
1419 }
Joshua Habermanffdcc462022-01-12 08:38:36 -08001420 PyObject* str = PyUnicode_FromString(buf);
1421 PyList_Append(ret, str);
1422 Py_DECREF(str);
Joshua Haberman4111d132021-12-04 18:42:53 -08001423 }
1424 free(buf);
1425 }
1426 return ret;
1427}
1428
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001429static PyObject* PyUpb_Message_FromString(PyObject* cls, PyObject* serialized) {
Joshua Habermanc42beeb2021-12-06 23:07:14 -08001430 PyObject* ret = NULL;
1431 PyObject* length = NULL;
Joshua Haberman4111d132021-12-04 18:42:53 -08001432
Joshua Habermanc42beeb2021-12-06 23:07:14 -08001433 ret = PyObject_CallObject(cls, NULL);
1434 if (ret == NULL) goto err;
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001435 length = PyUpb_Message_MergeFromString(ret, serialized);
Joshua Habermanc42beeb2021-12-06 23:07:14 -08001436 if (length == NULL) goto err;
Joshua Haberman4111d132021-12-04 18:42:53 -08001437
Joshua Habermanc42beeb2021-12-06 23:07:14 -08001438done:
1439 Py_XDECREF(length);
Joshua Haberman4111d132021-12-04 18:42:53 -08001440 return ret;
Joshua Habermanc42beeb2021-12-06 23:07:14 -08001441
1442err:
1443 Py_XDECREF(ret);
1444 ret = NULL;
1445 goto done;
Joshua Haberman4111d132021-12-04 18:42:53 -08001446}
1447
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001448const upb_FieldDef* PyUpb_Message_GetExtensionDef(PyObject* _self,
1449 PyObject* key) {
Joshua Haberman1c955f32022-01-12 07:19:28 -08001450 const upb_FieldDef* f = PyUpb_FieldDescriptor_GetDef(key);
Joshua Haberman72603462022-01-01 16:08:29 -08001451 if (!f) {
1452 PyErr_Clear();
1453 PyErr_Format(PyExc_KeyError, "Object %R is not a field descriptor\n", key);
1454 return NULL;
1455 }
Joshua Haberman1c955f32022-01-12 07:19:28 -08001456 if (!upb_FieldDef_IsExtension(f)) {
Joshua Haberman72603462022-01-01 16:08:29 -08001457 PyErr_Format(PyExc_KeyError, "Field %s is not an extension\n",
Joshua Haberman1c955f32022-01-12 07:19:28 -08001458 upb_FieldDef_FullName(f));
Joshua Haberman72603462022-01-01 16:08:29 -08001459 return NULL;
1460 }
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001461 const upb_MessageDef* msgdef = PyUpb_Message_GetMsgdef(_self);
Joshua Haberman1c955f32022-01-12 07:19:28 -08001462 if (upb_FieldDef_ContainingType(f) != msgdef) {
Joshua Haberman72603462022-01-01 16:08:29 -08001463 PyErr_Format(PyExc_KeyError, "Extension doesn't match (%s vs %s)",
Joshua Haberman1c955f32022-01-12 07:19:28 -08001464 upb_MessageDef_FullName(msgdef), upb_FieldDef_FullName(f));
Joshua Haberman72603462022-01-01 16:08:29 -08001465 return NULL;
1466 }
1467 return f;
1468}
1469
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001470static PyObject* PyUpb_Message_HasExtension(PyObject* _self,
1471 PyObject* ext_desc) {
1472 upb_Message* msg = PyUpb_Message_GetIfReified(_self);
1473 const upb_FieldDef* f = PyUpb_Message_GetExtensionDef(_self, ext_desc);
Joshua Haberman4111d132021-12-04 18:42:53 -08001474 if (!f) return NULL;
Joshua Haberman1c955f32022-01-12 07:19:28 -08001475 if (upb_FieldDef_IsRepeated(f)) {
Joshua Haberman72603462022-01-01 16:08:29 -08001476 PyErr_SetString(PyExc_KeyError,
1477 "Field is repeated. A singular method is required.");
1478 return NULL;
1479 }
Joshua Haberman4111d132021-12-04 18:42:53 -08001480 if (!msg) Py_RETURN_FALSE;
Eric Salob747edb2022-12-05 08:40:10 -08001481 return PyBool_FromLong(upb_Message_HasFieldByDef(msg, f));
Joshua Haberman4111d132021-12-04 18:42:53 -08001482}
1483
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001484void PyUpb_Message_ReportInitializationErrors(const upb_MessageDef* msgdef,
1485 PyObject* errors, PyObject* exc) {
Joshua Habermanfff8dfb2022-01-09 23:31:27 -08001486 PyObject* comma = PyUnicode_FromString(",");
1487 PyObject* missing_fields = NULL;
1488 if (!comma) goto done;
1489 missing_fields = PyUnicode_Join(comma, errors);
1490 if (!missing_fields) goto done;
1491 PyErr_Format(exc, "Message %s is missing required fields: %U",
Joshua Haberman1c955f32022-01-12 07:19:28 -08001492 upb_MessageDef_FullName(msgdef), missing_fields);
Joshua Habermanfff8dfb2022-01-09 23:31:27 -08001493done:
1494 Py_XDECREF(comma);
1495 Py_XDECREF(missing_fields);
1496 Py_DECREF(errors);
1497}
1498
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001499PyObject* PyUpb_Message_SerializeInternal(PyObject* _self, PyObject* args,
1500 PyObject* kwargs,
1501 bool check_required) {
1502 PyUpb_Message* self = (void*)_self;
1503 if (!PyUpb_Message_Verify((PyObject*)self)) return NULL;
Joshua Haberman4111d132021-12-04 18:42:53 -08001504 static const char* kwlist[] = {"deterministic", NULL};
1505 int deterministic = 0;
1506 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|p", (char**)(kwlist),
1507 &deterministic)) {
1508 return NULL;
1509 }
1510
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001511 const upb_MessageDef* msgdef = _PyUpb_Message_GetMsgdef(self);
1512 if (PyUpb_Message_IsStub(self)) {
Joshua Haberman8c256cc2022-01-10 10:00:10 -08001513 // Nothing to serialize, but we do have to check whether the message is
1514 // initialized.
1515 PyUpb_ModuleState* state = PyUpb_ModuleState_Get();
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001516 PyObject* errors = PyUpb_Message_FindInitializationErrors(_self, NULL);
Joshua Haberman8c256cc2022-01-10 10:00:10 -08001517 if (!errors) return NULL;
1518 if (PyList_Size(errors) == 0) {
1519 Py_DECREF(errors);
1520 return PyBytes_FromStringAndSize(NULL, 0);
1521 }
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001522 PyUpb_Message_ReportInitializationErrors(msgdef, errors,
1523 state->encode_error_class);
Joshua Haberman8c256cc2022-01-10 10:00:10 -08001524 return NULL;
Joshua Haberman4111d132021-12-04 18:42:53 -08001525 }
1526
Joshua Haberman1c955f32022-01-12 07:19:28 -08001527 upb_Arena* arena = upb_Arena_New();
1528 const upb_MiniTable* layout = upb_MessageDef_MiniTable(msgdef);
Joshua Haberman4111d132021-12-04 18:42:53 -08001529 size_t size = 0;
Joshua Habermanfff8dfb2022-01-09 23:31:27 -08001530 // Python does not currently have any effective limit on serialization depth.
Joshua Haberman5b3447e2021-12-31 15:37:23 -08001531 int options = UPB_ENCODE_MAXDEPTH(UINT32_MAX);
Protobuf Team Bot65bde4e2022-06-13 17:57:18 -07001532 if (check_required) options |= kUpb_EncodeOption_CheckRequired;
1533 if (deterministic) options |= kUpb_EncodeOption_Deterministic;
1534 char* pb;
1535 upb_EncodeStatus status =
1536 upb_Encode(self->ptr.msg, layout, options, arena, &pb, &size);
Joshua Haberman4111d132021-12-04 18:42:53 -08001537 PyObject* ret = NULL;
1538
Protobuf Team Bot65bde4e2022-06-13 17:57:18 -07001539 if (status != kUpb_EncodeStatus_Ok) {
Joshua Haberman4111d132021-12-04 18:42:53 -08001540 PyUpb_ModuleState* state = PyUpb_ModuleState_Get();
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001541 PyObject* errors = PyUpb_Message_FindInitializationErrors(_self, NULL);
Joshua Haberman4984a222022-01-09 20:46:18 -08001542 if (PyList_Size(errors) != 0) {
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001543 PyUpb_Message_ReportInitializationErrors(msgdef, errors,
1544 state->encode_error_class);
Joshua Habermanfff8dfb2022-01-09 23:31:27 -08001545 } else {
1546 PyErr_Format(state->encode_error_class, "Failed to serialize proto");
Joshua Haberman4984a222022-01-09 20:46:18 -08001547 }
Joshua Haberman4111d132021-12-04 18:42:53 -08001548 goto done;
1549 }
1550
1551 ret = PyBytes_FromStringAndSize(pb, size);
1552
1553done:
Joshua Haberman1c955f32022-01-12 07:19:28 -08001554 upb_Arena_Free(arena);
Joshua Haberman4111d132021-12-04 18:42:53 -08001555 return ret;
1556}
1557
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001558PyObject* PyUpb_Message_SerializeToString(PyObject* _self, PyObject* args,
1559 PyObject* kwargs) {
1560 return PyUpb_Message_SerializeInternal(_self, args, kwargs, true);
Joshua Haberman4111d132021-12-04 18:42:53 -08001561}
1562
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001563PyObject* PyUpb_Message_SerializePartialToString(PyObject* _self,
1564 PyObject* args,
1565 PyObject* kwargs) {
1566 return PyUpb_Message_SerializeInternal(_self, args, kwargs, false);
Joshua Haberman4111d132021-12-04 18:42:53 -08001567}
1568
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001569static PyObject* PyUpb_Message_WhichOneof(PyObject* _self, PyObject* name) {
1570 PyUpb_Message* self = (void*)_self;
Joshua Haberman1c955f32022-01-12 07:19:28 -08001571 const upb_OneofDef* o;
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001572 if (!PyUpb_Message_LookupName(self, name, NULL, &o, PyExc_ValueError)) {
Joshua Haberman4111d132021-12-04 18:42:53 -08001573 return NULL;
1574 }
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001575 upb_Message* msg = PyUpb_Message_GetIfReified(_self);
Joshua Haberman4111d132021-12-04 18:42:53 -08001576 if (!msg) Py_RETURN_NONE;
Joshua Haberman1c955f32022-01-12 07:19:28 -08001577 const upb_FieldDef* f = upb_Message_WhichOneof(msg, o);
Joshua Haberman4111d132021-12-04 18:42:53 -08001578 if (!f) Py_RETURN_NONE;
Joshua Haberman1c955f32022-01-12 07:19:28 -08001579 return PyUnicode_FromString(upb_FieldDef_Name(f));
Joshua Haberman4111d132021-12-04 18:42:53 -08001580}
1581
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001582void PyUpb_Message_ClearExtensionDict(PyObject* _self) {
1583 PyUpb_Message* self = (void*)_self;
Joshua Haberman4111d132021-12-04 18:42:53 -08001584 assert(self->ext_dict);
1585 self->ext_dict = NULL;
1586}
1587
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001588static PyObject* PyUpb_Message_GetExtensionDict(PyObject* _self,
1589 void* closure) {
1590 PyUpb_Message* self = (void*)_self;
Joshua Haberman4111d132021-12-04 18:42:53 -08001591 if (self->ext_dict) {
Joshua Habermanac27e3b2022-02-27 17:51:27 -08001592 Py_INCREF(self->ext_dict);
Joshua Haberman4111d132021-12-04 18:42:53 -08001593 return self->ext_dict;
1594 }
1595
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001596 const upb_MessageDef* m = _PyUpb_Message_GetMsgdef(self);
Joshua Haberman1c955f32022-01-12 07:19:28 -08001597 if (upb_MessageDef_ExtensionRangeCount(m) == 0) {
Joshua Haberman4111d132021-12-04 18:42:53 -08001598 PyErr_SetNone(PyExc_AttributeError);
1599 return NULL;
1600 }
1601
Joshua Haberman627c44b2021-12-30 17:47:12 -08001602 self->ext_dict = PyUpb_ExtensionDict_New(_self);
1603 return self->ext_dict;
Joshua Haberman4111d132021-12-04 18:42:53 -08001604}
1605
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001606static PyGetSetDef PyUpb_Message_Getters[] = {
1607 {"Extensions", PyUpb_Message_GetExtensionDict, NULL, "Extension dict"},
Joshua Haberman4111d132021-12-04 18:42:53 -08001608 {NULL}};
1609
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001610static PyMethodDef PyUpb_Message_Methods[] = {
Joshua Habermaneb38a2a2021-12-05 23:54:34 -08001611 // TODO(https://github.com/protocolbuffers/upb/issues/459)
Joshua Haberman4111d132021-12-04 18:42:53 -08001612 //{ "__deepcopy__", (PyCFunction)DeepCopy, METH_VARARGS,
1613 // "Makes a deep copy of the class." },
1614 //{ "__unicode__", (PyCFunction)ToUnicode, METH_NOARGS,
1615 // "Outputs a unicode representation of the message." },
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001616 {"ByteSize", (PyCFunction)PyUpb_Message_ByteSize, METH_NOARGS,
Joshua Haberman4111d132021-12-04 18:42:53 -08001617 "Returns the size of the message in bytes."},
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001618 {"Clear", (PyCFunction)PyUpb_Message_Clear, METH_NOARGS,
Joshua Haberman4111d132021-12-04 18:42:53 -08001619 "Clears the message."},
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001620 {"ClearExtension", PyUpb_Message_ClearExtension, METH_O,
Joshua Haberman4111d132021-12-04 18:42:53 -08001621 "Clears a message field."},
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001622 {"ClearField", PyUpb_Message_ClearField, METH_O, "Clears a message field."},
Joshua Habermaneb38a2a2021-12-05 23:54:34 -08001623 // TODO(https://github.com/protocolbuffers/upb/issues/459)
Joshua Haberman4111d132021-12-04 18:42:53 -08001624 //{ "CopyFrom", (PyCFunction)CopyFrom, METH_O,
1625 // "Copies a protocol message into the current message." },
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001626 {"DiscardUnknownFields", (PyCFunction)PyUpb_Message_DiscardUnknownFields,
Joshua Haberman4111d132021-12-04 18:42:53 -08001627 METH_NOARGS, "Discards the unknown fields."},
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001628 {"FindInitializationErrors", PyUpb_Message_FindInitializationErrors,
Joshua Habermancbe314d2022-01-09 17:25:10 -08001629 METH_NOARGS, "Finds unset required fields."},
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001630 {"FromString", PyUpb_Message_FromString, METH_O | METH_CLASS,
Joshua Haberman4111d132021-12-04 18:42:53 -08001631 "Creates new method instance from given serialized data."},
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001632 {"HasExtension", PyUpb_Message_HasExtension, METH_O,
Joshua Haberman4111d132021-12-04 18:42:53 -08001633 "Checks if a message field is set."},
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001634 {"HasField", PyUpb_Message_HasField, METH_O,
Joshua Haberman4111d132021-12-04 18:42:53 -08001635 "Checks if a message field is set."},
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001636 {"IsInitialized", PyUpb_Message_IsInitialized, METH_VARARGS,
Joshua Habermancbe314d2022-01-09 17:25:10 -08001637 "Checks if all required fields of a protocol message are set."},
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001638 {"ListFields", PyUpb_Message_ListFields, METH_NOARGS,
Joshua Haberman4111d132021-12-04 18:42:53 -08001639 "Lists all set fields of a message."},
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001640 {"MergeFrom", PyUpb_Message_MergeFrom, METH_O,
Joshua Haberman4111d132021-12-04 18:42:53 -08001641 "Merges a protocol message into the current message."},
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001642 {"MergeFromString", PyUpb_Message_MergeFromString, METH_O,
Joshua Haberman4111d132021-12-04 18:42:53 -08001643 "Merges a serialized message into the current message."},
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001644 {"ParseFromString", PyUpb_Message_ParseFromString, METH_O,
Joshua Haberman4111d132021-12-04 18:42:53 -08001645 "Parses a serialized message into the current message."},
Joshua Habermaneb38a2a2021-12-05 23:54:34 -08001646 // TODO(https://github.com/protocolbuffers/upb/issues/459)
Joshua Haberman4111d132021-12-04 18:42:53 -08001647 //{ "RegisterExtension", (PyCFunction)RegisterExtension, METH_O |
1648 // METH_CLASS,
1649 // "Registers an extension with the current message." },
1650 {"SerializePartialToString",
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001651 (PyCFunction)PyUpb_Message_SerializePartialToString,
Joshua Haberman4111d132021-12-04 18:42:53 -08001652 METH_VARARGS | METH_KEYWORDS,
1653 "Serializes the message to a string, even if it isn't initialized."},
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001654 {"SerializeToString", (PyCFunction)PyUpb_Message_SerializeToString,
Joshua Haberman4111d132021-12-04 18:42:53 -08001655 METH_VARARGS | METH_KEYWORDS,
1656 "Serializes the message to a string, only for initialized messages."},
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001657 {"SetInParent", (PyCFunction)PyUpb_Message_SetInParent, METH_NOARGS,
Joshua Haberman4111d132021-12-04 18:42:53 -08001658 "Sets the has bit of the given field in its parent message."},
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001659 {"UnknownFields", (PyCFunction)PyUpb_Message_UnknownFields, METH_NOARGS,
Joshua Haberman4111d132021-12-04 18:42:53 -08001660 "Parse unknown field set"},
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001661 {"WhichOneof", PyUpb_Message_WhichOneof, METH_O,
Joshua Haberman4111d132021-12-04 18:42:53 -08001662 "Returns the name of the field set inside a oneof, "
1663 "or None if no field is set."},
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001664 {"_ListFieldsItemKey", PyUpb_Message_ListFieldsItemKey,
Joshua Haberman4993f7a2022-01-09 18:51:10 -08001665 METH_O | METH_STATIC,
1666 "Compares ListFields() list entries by field number"},
Joshua Haberman4e2bbc82022-05-17 10:08:55 -07001667 {"_CheckCalledFromGeneratedFile",
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001668 PyUpb_Message_CheckCalledFromGeneratedFile, METH_NOARGS | METH_STATIC,
Joshua Haberman4e2bbc82022-05-17 10:08:55 -07001669 "Raises TypeError if the caller is not in a _pb2.py file."},
Joshua Haberman4111d132021-12-04 18:42:53 -08001670 {NULL, NULL}};
1671
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001672static PyType_Slot PyUpb_Message_Slots[] = {
1673 {Py_tp_dealloc, PyUpb_Message_Dealloc},
Joshua Haberman4111d132021-12-04 18:42:53 -08001674 {Py_tp_doc, "A ProtocolMessage"},
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001675 {Py_tp_getattro, PyUpb_Message_GetAttr},
1676 {Py_tp_getset, PyUpb_Message_Getters},
Joshua Haberman4111d132021-12-04 18:42:53 -08001677 {Py_tp_hash, PyObject_HashNotImplemented},
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001678 {Py_tp_methods, PyUpb_Message_Methods},
1679 {Py_tp_new, PyUpb_Message_New},
1680 {Py_tp_str, PyUpb_Message_ToString},
1681 {Py_tp_repr, PyUpb_Message_ToString},
1682 {Py_tp_richcompare, PyUpb_Message_RichCompare},
1683 {Py_tp_setattro, PyUpb_Message_SetAttr},
1684 {Py_tp_init, PyUpb_Message_Init},
Joshua Haberman4111d132021-12-04 18:42:53 -08001685 {0, NULL}};
1686
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001687PyType_Spec PyUpb_Message_Spec = {
1688 PYUPB_MODULE_NAME ".Message", // tp_name
1689 sizeof(PyUpb_Message), // tp_basicsize
Joshua Haberman4111d132021-12-04 18:42:53 -08001690 0, // tp_itemsize
1691 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, // tp_flags
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001692 PyUpb_Message_Slots,
Joshua Haberman4111d132021-12-04 18:42:53 -08001693};
1694
1695// -----------------------------------------------------------------------------
1696// MessageMeta
1697// -----------------------------------------------------------------------------
1698
Joshua Habermaneb38a2a2021-12-05 23:54:34 -08001699// MessageMeta is the metaclass for message objects. The generated code uses it
1700// to construct message classes, ie.
1701//
1702// FooMessage = _message.MessageMeta('FooMessage', (_message.Message), {...})
1703//
1704// (This is not quite true: at the moment the Python library subclasses
1705// MessageMeta, and uses that subclass as the metaclass. There is a TODO below
1706// to simplify this, so that the illustration above is indeed accurate).
1707
Joshua Haberman4111d132021-12-04 18:42:53 -08001708typedef struct {
Joshua Haberman1c955f32022-01-12 07:19:28 -08001709 const upb_MiniTable* layout;
Joshua Haberman4111d132021-12-04 18:42:53 -08001710 PyObject* py_message_descriptor;
1711} PyUpb_MessageMeta;
1712
Joshua Habermaneb38a2a2021-12-05 23:54:34 -08001713// The PyUpb_MessageMeta struct is trailing data tacked onto the end of
1714// MessageMeta instances. This means that we get our instances of this struct
1715// by adding the appropriate number of bytes.
1716static PyUpb_MessageMeta* PyUpb_GetMessageMeta(PyObject* cls) {
Joshua Haberman4111d132021-12-04 18:42:53 -08001717#ifndef NDEBUG
1718 PyUpb_ModuleState* state = PyUpb_ModuleState_MaybeGet();
1719 assert(!state || cls->ob_type == state->message_meta_type);
1720#endif
1721 return (PyUpb_MessageMeta*)((char*)cls + cpython_bits.type_basicsize);
1722}
1723
Joshua Haberman1c955f32022-01-12 07:19:28 -08001724static const upb_MessageDef* PyUpb_MessageMeta_GetMsgdef(PyObject* cls) {
Joshua Habermaneb38a2a2021-12-05 23:54:34 -08001725 PyUpb_MessageMeta* self = PyUpb_GetMessageMeta(cls);
1726 return PyUpb_Descriptor_GetDef(self->py_message_descriptor);
1727}
1728
Joshua Haberman4111d132021-12-04 18:42:53 -08001729PyObject* PyUpb_MessageMeta_DoCreateClass(PyObject* py_descriptor,
1730 const char* name, PyObject* dict) {
1731 PyUpb_ModuleState* state = PyUpb_ModuleState_Get();
1732 PyTypeObject* descriptor_type = state->descriptor_types[kPyUpb_Descriptor];
1733 if (!PyObject_TypeCheck(py_descriptor, descriptor_type)) {
1734 return PyErr_Format(PyExc_TypeError, "Expected a message Descriptor");
1735 }
1736
Joshua Haberman1c955f32022-01-12 07:19:28 -08001737 const upb_MessageDef* msgdef = PyUpb_Descriptor_GetDef(py_descriptor);
Joshua Haberman4111d132021-12-04 18:42:53 -08001738 assert(msgdef);
Joshua Haberman1c955f32022-01-12 07:19:28 -08001739 assert(!PyUpb_ObjCache_Get(upb_MessageDef_MiniTable(msgdef)));
Joshua Haberman4111d132021-12-04 18:42:53 -08001740
1741 PyObject* slots = PyTuple_New(0);
Joshua Habermanffdcc462022-01-12 08:38:36 -08001742 if (!slots) return NULL;
1743 int status = PyDict_SetItemString(dict, "__slots__", slots);
1744 Py_DECREF(slots);
1745 if (status < 0) return NULL;
Joshua Haberman4111d132021-12-04 18:42:53 -08001746
1747 // Bases are either:
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001748 // (Message, Message) # for regular messages
1749 // (Message, Message, WktBase) # For well-known types
Joshua Haberman4111d132021-12-04 18:42:53 -08001750 PyObject* wkt_bases = PyUpb_GetWktBases(state);
1751 PyObject* wkt_base =
Joshua Haberman1c955f32022-01-12 07:19:28 -08001752 PyDict_GetItemString(wkt_bases, upb_MessageDef_FullName(msgdef));
Joshua Haberman4111d132021-12-04 18:42:53 -08001753 PyObject* args;
1754 if (wkt_base == NULL) {
1755 args = Py_BuildValue("s(OO)O", name, state->cmessage_type,
1756 state->message_class, dict);
1757 } else {
1758 args = Py_BuildValue("s(OOO)O", name, state->cmessage_type,
1759 state->message_class, wkt_base, dict);
1760 }
1761
1762 PyObject* ret = cpython_bits.type_new(state->message_meta_type, args, NULL);
Joshua Haberman4111d132021-12-04 18:42:53 -08001763 Py_DECREF(args);
1764 if (!ret) return NULL;
1765
1766 PyUpb_MessageMeta* meta = PyUpb_GetMessageMeta(ret);
1767 meta->py_message_descriptor = py_descriptor;
Joshua Haberman1c955f32022-01-12 07:19:28 -08001768 meta->layout = upb_MessageDef_MiniTable(msgdef);
Joshua Haberman4111d132021-12-04 18:42:53 -08001769 Py_INCREF(meta->py_message_descriptor);
1770
Joshua Habermanffdcc462022-01-12 08:38:36 -08001771 PyUpb_ObjCache_Add(meta->layout, ret);
Joshua Haberman4111d132021-12-04 18:42:53 -08001772
1773 return ret;
1774}
1775
1776static PyObject* PyUpb_MessageMeta_New(PyTypeObject* type, PyObject* args,
1777 PyObject* kwargs) {
1778 PyUpb_ModuleState* state = PyUpb_ModuleState_Get();
1779 static const char* kwlist[] = {"name", "bases", "dict", 0};
1780 PyObject *bases, *dict;
1781 const char* name;
1782
1783 // Check arguments: (name, bases, dict)
1784 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO!O!:type", (char**)kwlist,
1785 &name, &PyTuple_Type, &bases, &PyDict_Type,
1786 &dict)) {
1787 return NULL;
1788 }
1789
1790 // Check bases: only (), or (message.Message,) are allowed
1791 Py_ssize_t size = PyTuple_Size(bases);
1792 if (!(size == 0 ||
1793 (size == 1 && PyTuple_GetItem(bases, 0) == state->message_class))) {
Joshua Haberman4423e912021-12-27 18:04:58 -08001794 PyErr_Format(PyExc_TypeError,
1795 "A Message class can only inherit from Message, not %S",
1796 bases);
Joshua Haberman4111d132021-12-04 18:42:53 -08001797 return NULL;
1798 }
1799
1800 // Check dict['DESCRIPTOR']
1801 PyObject* py_descriptor = PyDict_GetItemString(dict, "DESCRIPTOR");
1802 if (py_descriptor == NULL) {
1803 PyErr_SetString(PyExc_TypeError, "Message class has no DESCRIPTOR");
1804 return NULL;
1805 }
1806
Joshua Haberman1c955f32022-01-12 07:19:28 -08001807 const upb_MessageDef* m = PyUpb_Descriptor_GetDef(py_descriptor);
1808 PyObject* ret = PyUpb_ObjCache_Get(upb_MessageDef_MiniTable(m));
Joshua Haberman4111d132021-12-04 18:42:53 -08001809 if (ret) return ret;
1810 return PyUpb_MessageMeta_DoCreateClass(py_descriptor, name, dict);
1811}
1812
1813static void PyUpb_MessageMeta_Dealloc(PyObject* self) {
1814 PyUpb_MessageMeta* meta = PyUpb_GetMessageMeta(self);
1815 PyUpb_ObjCache_Delete(meta->layout);
1816 Py_DECREF(meta->py_message_descriptor);
Joshua Habermanffdcc462022-01-12 08:38:36 -08001817 PyTypeObject* tp = Py_TYPE(self);
1818 cpython_bits.type_dealloc(self);
1819 Py_DECREF(tp);
Joshua Haberman4111d132021-12-04 18:42:53 -08001820}
1821
Joshua Haberman1c955f32022-01-12 07:19:28 -08001822void PyUpb_MessageMeta_AddFieldNumber(PyObject* self, const upb_FieldDef* f) {
Joshua Haberman8af637b2022-01-09 21:59:29 -08001823 PyObject* name =
Joshua Haberman1c955f32022-01-12 07:19:28 -08001824 PyUnicode_FromFormat("%s_FIELD_NUMBER", upb_FieldDef_Name(f));
Joshua Haberman8af637b2022-01-09 21:59:29 -08001825 PyObject* upper = PyObject_CallMethod(name, "upper", "");
Joshua Haberman1c955f32022-01-12 07:19:28 -08001826 PyObject_SetAttr(self, upper, PyLong_FromLong(upb_FieldDef_Number(f)));
Joshua Haberman8af637b2022-01-09 21:59:29 -08001827 Py_DECREF(name);
1828 Py_DECREF(upper);
1829}
1830
Joshua Haberman4111d132021-12-04 18:42:53 -08001831static PyObject* PyUpb_MessageMeta_GetDynamicAttr(PyObject* self,
1832 PyObject* name) {
1833 const char* name_buf = PyUpb_GetStrData(name);
Joshua Habermanb38e4a42022-01-16 19:27:55 -08001834 if (!name_buf) return NULL;
Joshua Haberman1c955f32022-01-12 07:19:28 -08001835 const upb_MessageDef* msgdef = PyUpb_MessageMeta_GetMsgdef(self);
1836 const upb_FileDef* filedef = upb_MessageDef_File(msgdef);
1837 const upb_DefPool* symtab = upb_FileDef_Pool(filedef);
Joshua Haberman4111d132021-12-04 18:42:53 -08001838
1839 PyObject* py_key =
Joshua Haberman1c955f32022-01-12 07:19:28 -08001840 PyBytes_FromFormat("%s.%s", upb_MessageDef_FullName(msgdef), name_buf);
Joshua Haberman4111d132021-12-04 18:42:53 -08001841 const char* key = PyUpb_GetStrData(py_key);
1842 PyObject* ret = NULL;
Joshua Haberman1c955f32022-01-12 07:19:28 -08001843 const upb_MessageDef* nested = upb_DefPool_FindMessageByName(symtab, key);
1844 const upb_EnumDef* enumdef;
1845 const upb_EnumValueDef* enumval;
1846 const upb_FieldDef* ext;
Joshua Haberman4111d132021-12-04 18:42:53 -08001847
1848 if (nested) {
1849 ret = PyUpb_Descriptor_GetClass(nested);
Joshua Haberman1c955f32022-01-12 07:19:28 -08001850 } else if ((enumdef = upb_DefPool_FindEnumByName(symtab, key))) {
Joshua Haberman4111d132021-12-04 18:42:53 -08001851 PyUpb_ModuleState* state = PyUpb_ModuleState_Get();
1852 PyObject* klass = state->enum_type_wrapper_class;
1853 ret = PyUpb_EnumDescriptor_Get(enumdef);
1854 ret = PyObject_CallFunctionObjArgs(klass, ret, NULL);
Joshua Haberman1c955f32022-01-12 07:19:28 -08001855 } else if ((enumval = upb_DefPool_FindEnumByNameval(symtab, key))) {
1856 ret = PyLong_FromLong(upb_EnumValueDef_Number(enumval));
1857 } else if ((ext = upb_DefPool_FindExtensionByName(symtab, key))) {
Joshua Haberman4111d132021-12-04 18:42:53 -08001858 ret = PyUpb_FieldDescriptor_Get(ext);
1859 }
1860
1861 Py_DECREF(py_key);
1862
Joshua Haberman1c955f32022-01-12 07:19:28 -08001863 const char* suffix = "_FIELD_NUMBER";
Joshua Haberman3b25e6f2022-01-09 19:28:04 -08001864 size_t n = strlen(name_buf);
1865 size_t suffix_n = strlen(suffix);
Joshua Haberman8c256cc2022-01-10 10:00:10 -08001866 if (n > suffix_n && memcmp(suffix, name_buf + n - suffix_n, suffix_n) == 0) {
Joshua Haberman3b25e6f2022-01-09 19:28:04 -08001867 // We can't look up field names dynamically, because the <NAME>_FIELD_NUMBER
1868 // naming scheme upper-cases the field name and is therefore non-reversible.
1869 // So we just add all field numbers.
Joshua Haberman1c955f32022-01-12 07:19:28 -08001870 int n = upb_MessageDef_FieldCount(msgdef);
Joshua Haberman3b25e6f2022-01-09 19:28:04 -08001871 for (int i = 0; i < n; i++) {
Joshua Haberman1c955f32022-01-12 07:19:28 -08001872 PyUpb_MessageMeta_AddFieldNumber(self, upb_MessageDef_Field(msgdef, i));
Joshua Haberman8af637b2022-01-09 21:59:29 -08001873 }
Joshua Haberman1c955f32022-01-12 07:19:28 -08001874 n = upb_MessageDef_NestedExtensionCount(msgdef);
Joshua Haberman8af637b2022-01-09 21:59:29 -08001875 for (int i = 0; i < n; i++) {
Joshua Haberman1c955f32022-01-12 07:19:28 -08001876 PyUpb_MessageMeta_AddFieldNumber(
1877 self, upb_MessageDef_NestedExtension(msgdef, i));
Joshua Haberman3b25e6f2022-01-09 19:28:04 -08001878 }
1879 ret = PyObject_GenericGetAttr(self, name);
1880 }
1881
Joshua Haberman4111d132021-12-04 18:42:53 -08001882 return ret;
1883}
1884
1885static PyObject* PyUpb_MessageMeta_GetAttr(PyObject* self, PyObject* name) {
1886 // We want to first delegate to the type's tp_dict to retrieve any attributes
1887 // that were previously calculated and cached in the type's dict.
1888 PyObject* ret = cpython_bits.type_getattro(self, name);
1889 if (ret) return ret;
1890
1891 // We did not find a cached attribute. Try to calculate the attribute
1892 // dynamically, using the descriptor as an argument.
1893 PyErr_Clear();
1894 ret = PyUpb_MessageMeta_GetDynamicAttr(self, name);
1895
1896 if (ret) {
1897 PyObject_SetAttr(self, name, ret);
1898 PyErr_Clear();
1899 return ret;
1900 }
1901
1902 PyErr_SetObject(PyExc_AttributeError, name);
1903 return NULL;
1904}
1905
1906static PyType_Slot PyUpb_MessageMeta_Slots[] = {
1907 {Py_tp_new, PyUpb_MessageMeta_New},
1908 {Py_tp_dealloc, PyUpb_MessageMeta_Dealloc},
1909 {Py_tp_getattro, PyUpb_MessageMeta_GetAttr},
1910 {0, NULL}};
1911
1912static PyType_Spec PyUpb_MessageMeta_Spec = {
1913 PYUPB_MODULE_NAME ".MessageMeta", // tp_name
1914 0, // To be filled in by size of base // tp_basicsize
1915 0, // tp_itemsize
1916 // TODO(haberman): remove BASETYPE, Python should just use MessageMeta
1917 // directly instead of subclassing it.
1918 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, // tp_flags
1919 PyUpb_MessageMeta_Slots,
1920};
1921
Joshua Habermane079f1b2021-12-18 22:10:46 -08001922static PyObject* PyUpb_MessageMeta_CreateType(void) {
Joshua Haberman4111d132021-12-04 18:42:53 -08001923 PyObject* bases = Py_BuildValue("(O)", &PyType_Type);
Joshua Habermaneb38a2a2021-12-05 23:54:34 -08001924 if (!bases) return NULL;
Joshua Haberman4111d132021-12-04 18:42:53 -08001925 PyUpb_MessageMeta_Spec.basicsize =
1926 cpython_bits.type_basicsize + sizeof(PyUpb_MessageMeta);
1927 PyObject* type = PyType_FromSpecWithBases(&PyUpb_MessageMeta_Spec, bases);
1928 Py_DECREF(bases);
Joshua Habermaneb38a2a2021-12-05 23:54:34 -08001929 return type;
1930}
Joshua Haberman4111d132021-12-04 18:42:53 -08001931
Joshua Habermaneb38a2a2021-12-05 23:54:34 -08001932bool PyUpb_InitMessage(PyObject* m) {
1933 if (!PyUpb_CPythonBits_Init(&cpython_bits)) return false;
1934 PyObject* message_meta_type = PyUpb_MessageMeta_CreateType();
Joshua Haberman4111d132021-12-04 18:42:53 -08001935
Joshua Habermaneb38a2a2021-12-05 23:54:34 -08001936 PyUpb_ModuleState* state = PyUpb_ModuleState_GetFromModule(m);
Joshua Haberman12fffeb2022-05-17 14:00:49 -07001937 state->cmessage_type = PyUpb_AddClass(m, &PyUpb_Message_Spec);
Joshua Habermaneb38a2a2021-12-05 23:54:34 -08001938 state->message_meta_type = (PyTypeObject*)message_meta_type;
1939
1940 if (!state->cmessage_type || !state->message_meta_type) return false;
1941 if (PyModule_AddObject(m, "MessageMeta", message_meta_type)) return false;
Joshua Haberman1c955f32022-01-12 07:19:28 -08001942 state->listfields_item_key = PyObject_GetAttrString(
1943 (PyObject*)state->cmessage_type, "_ListFieldsItemKey");
Joshua Habermaneb38a2a2021-12-05 23:54:34 -08001944
Joshua Haberman6a94a382022-02-27 17:35:52 -08001945 PyObject* mod =
1946 PyImport_ImportModule(PYUPB_PROTOBUF_PUBLIC_PACKAGE ".message");
Joshua Haberman4423e912021-12-27 18:04:58 -08001947 if (mod == NULL) return false;
1948
1949 state->encode_error_class = PyObject_GetAttrString(mod, "EncodeError");
1950 state->decode_error_class = PyObject_GetAttrString(mod, "DecodeError");
1951 state->message_class = PyObject_GetAttrString(mod, "Message");
1952 Py_DECREF(mod);
1953
Joshua Haberman0a858bb2022-02-27 13:01:15 -08001954 PyObject* enum_type_wrapper = PyImport_ImportModule(
1955 PYUPB_PROTOBUF_INTERNAL_PACKAGE ".enum_type_wrapper");
Joshua Haberman4447d872022-01-09 13:13:59 -08001956 if (enum_type_wrapper == NULL) return false;
1957
1958 state->enum_type_wrapper_class =
1959 PyObject_GetAttrString(enum_type_wrapper, "EnumTypeWrapper");
1960 Py_DECREF(enum_type_wrapper);
1961
Joshua Haberman4423e912021-12-27 18:04:58 -08001962 if (!state->encode_error_class || !state->decode_error_class ||
Joshua Habermand4c0c632022-01-09 23:16:18 -08001963 !state->message_class || !state->listfields_item_key ||
Joshua Haberman4993f7a2022-01-09 18:51:10 -08001964 !state->enum_type_wrapper_class) {
Joshua Haberman4423e912021-12-27 18:04:58 -08001965 return false;
1966 }
1967
Joshua Habermaneb38a2a2021-12-05 23:54:34 -08001968 return true;
Joshua Haberman4111d132021-12-04 18:42:53 -08001969}