blob: 81d5381f5563ea1c5926ddd7479eda2e61c70022 [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"
Joshua Haberman4111d132021-12-04 18:42:53 -080035#include "upb/def.h"
36#include "upb/reflection.h"
37#include "upb/text_encode.h"
38#include "upb/util/required_fields.h"
39
Joshua Habermaneb38a2a2021-12-05 23:54:34 -080040static const upb_msgdef* PyUpb_MessageMeta_GetMsgdef(PyObject* cls);
41static PyObject* PyUpb_MessageMeta_GetAttr(PyObject* self, PyObject* name);
Joshua Haberman4111d132021-12-04 18:42:53 -080042
43// -----------------------------------------------------------------------------
44// CPythonBits
45// -----------------------------------------------------------------------------
46
47// This struct contains a few things that are not exposed directly through the
48// limited API, but that we can get at in somewhat more roundabout ways. The
49// roundabout ways are slower, so we cache the values here.
50//
51// These values are valid to cache in a global, even across sub-interpreters,
52// because they are not pointers to interpreter state. They are process
53// globals that will be the same for any interpreter in this process.
54typedef struct {
55 // For each member, we note the equivalent expression that we could use in the
56 // full (non-limited) API.
57 newfunc type_new; // PyTypeObject.tp_new
58 getattrofunc type_getattro; // PyTypeObject.tp_getattro
59 setattrofunc type_setattro; // PyTypeObject.tp_setattro
60 size_t type_basicsize; // sizeof(PyHeapTypeObject)
61
62 // While we can refer to PY_VERSION_HEX in the limited API, this will give us
63 // the version of Python we were compiled against, which may be different
64 // than the version we are dynamically linked against. Here we want the
65 // version that is actually running in this process.
66 long python_version_hex; // PY_VERSION_HEX
Joshua Haberman4111d132021-12-04 18:42:53 -080067} PyUpb_CPythonBits;
68
69// A global containing the values for this process.
70PyUpb_CPythonBits cpython_bits;
71
72static bool PyUpb_CPythonBits_Init(PyUpb_CPythonBits* bits) {
Joshua Habermanc42beeb2021-12-06 23:07:14 -080073 PyObject* bases = NULL;
74 PyTypeObject* type = NULL;
75 PyObject* size = NULL;
76 PyObject* sys = NULL;
77 PyObject* hex_version = NULL;
78 bool ret = false;
79
Joshua Haberman4111d132021-12-04 18:42:53 -080080 // PyType_GetSlot() only works on heap types, so we cannot use it on
81 // &PyType_Type directly. Instead we create our own (temporary) type derived
82 // from PyType_Type: this will inherit all of the slots from PyType_Type, but
83 // as a heap type it can be queried with PyType_GetSlot().
84 static PyType_Slot dummy_slots[] = {{0, NULL}};
85
86 static PyType_Spec dummy_spec = {
87 "module.DummyClass", // tp_name
88 0, // To be filled in by size of base // tp_basicsize
89 0, // tp_itemsize
90 Py_TPFLAGS_DEFAULT, // tp_flags
91 dummy_slots,
92 };
93
Joshua Habermanc42beeb2021-12-06 23:07:14 -080094 bases = Py_BuildValue("(O)", &PyType_Type);
95 if (!bases) goto err;
96 type = (PyTypeObject*)PyType_FromSpecWithBases(&dummy_spec, bases);
97 if (!type) goto err;
Joshua Haberman4111d132021-12-04 18:42:53 -080098
Joshua Habermanc42beeb2021-12-06 23:07:14 -080099 bits->type_new = PyType_GetSlot(type, Py_tp_new);
100 bits->type_getattro = PyType_GetSlot(type, Py_tp_getattro);
101 bits->type_setattro = PyType_GetSlot(type, Py_tp_setattro);
Joshua Haberman4111d132021-12-04 18:42:53 -0800102
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800103 size = PyObject_GetAttrString((PyObject*)&PyType_Type, "__basicsize__");
104 if (!size) goto err;
Joshua Haberman4111d132021-12-04 18:42:53 -0800105 bits->type_basicsize = PyLong_AsLong(size);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800106 if (bits->type_basicsize == -1) goto err;
Joshua Haberman4111d132021-12-04 18:42:53 -0800107
108 assert(bits->type_new && bits->type_getattro && bits->type_setattro);
109
110#ifndef Py_LIMITED_API
111 assert(bits->type_new == PyType_Type.tp_new);
112 assert(bits->type_getattro == PyType_Type.tp_getattro);
113 assert(bits->type_setattro == PyType_Type.tp_setattro);
114 assert(bits->type_basicsize == sizeof(PyHeapTypeObject));
115#endif
116
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800117 sys = PyImport_ImportModule("sys");
118 hex_version = PyObject_GetAttrString(sys, "hexversion");
Joshua Haberman4111d132021-12-04 18:42:53 -0800119 bits->python_version_hex = PyLong_AsLong(hex_version);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800120 ret = true;
Joshua Haberman4111d132021-12-04 18:42:53 -0800121
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800122err:
123 Py_XDECREF(bases);
124 Py_XDECREF(type);
125 Py_XDECREF(size);
126 Py_XDECREF(sys);
127 Py_XDECREF(hex_version);
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800128 return ret;
Joshua Haberman4111d132021-12-04 18:42:53 -0800129}
130
131// -----------------------------------------------------------------------------
132// CMessage
133// -----------------------------------------------------------------------------
134
135// The main message object. The type of the object (PyUpb_CMessage.ob_type)
136// will be an instance of the PyUpb_MessageMeta type (defined below). So the
137// chain is:
138// FooMessage = MessageMeta(...)
139// foo = FooMessage()
140//
141// Which becomes:
142// Object C Struct Type Python type (ob_type)
143// ----------------- ----------------- ---------------------
144// foo PyUpb_CMessage FooMessage
145// FooMessage PyUpb_MessageMeta message_meta_type
146// message_meta_type PyTypeObject 'type' in Python
147//
148// A message object can be in one of two states: present or non-present. When
149// a message is non-present, it stores a reference to its parent, and a write
150// to any attribute will trigger the message to become present in its parent.
151// The parent may also be non-present, in which case a mutation will trigger a
152// chain reaction.
153typedef struct PyUpb_CMessage {
154 PyObject_HEAD
155 PyObject* arena;
156 uintptr_t def; // Tagged, low bit 1 == upb_fielddef*, else upb_msgdef*
157 union {
158 // when def is msgdef, the data for this msg.
159 upb_msg* msg;
160 // when def is fielddef, owning pointer to parent
161 struct PyUpb_CMessage* parent;
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800162 } ptr;
Joshua Haberman4111d132021-12-04 18:42:53 -0800163 PyObject* ext_dict; // Weak pointer to extension dict, if any.
164 // name->obj dict for non-present msg/map/repeated, NULL if none.
165 PyUpb_WeakMap* unset_subobj_map;
166 int version;
167} PyUpb_CMessage;
168
169static PyObject* PyUpb_CMessage_GetAttr(PyObject* _self, PyObject* attr);
170
Joshua Haberman0549fc02022-01-01 15:42:51 -0800171bool PyUpb_CMessage_IsStub(PyUpb_CMessage* msg) { return msg->def & 1; }
Joshua Haberman4111d132021-12-04 18:42:53 -0800172
173const upb_fielddef* PyUpb_CMessage_GetFieldDef(PyUpb_CMessage* msg) {
Joshua Haberman0549fc02022-01-01 15:42:51 -0800174 assert(PyUpb_CMessage_IsStub(msg));
Joshua Haberman4111d132021-12-04 18:42:53 -0800175 return (void*)(msg->def & ~(uintptr_t)1);
176}
177
178static const upb_msgdef* _PyUpb_CMessage_GetMsgdef(PyUpb_CMessage* msg) {
Joshua Haberman0549fc02022-01-01 15:42:51 -0800179 return PyUpb_CMessage_IsStub(msg)
Joshua Haberman4111d132021-12-04 18:42:53 -0800180 ? upb_fielddef_msgsubdef(PyUpb_CMessage_GetFieldDef(msg))
181 : (void*)msg->def;
182}
183
184const upb_msgdef* PyUpb_CMessage_GetMsgdef(PyObject* self) {
185 return _PyUpb_CMessage_GetMsgdef((PyUpb_CMessage*)self);
186}
187
188static upb_msg* PyUpb_CMessage_GetMsg(PyUpb_CMessage* self) {
Joshua Haberman0549fc02022-01-01 15:42:51 -0800189 assert(!PyUpb_CMessage_IsStub(self));
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800190 return self->ptr.msg;
Joshua Haberman4111d132021-12-04 18:42:53 -0800191}
192
193bool PyUpb_CMessage_TryCheck(PyObject* self) {
194 PyUpb_ModuleState* state = PyUpb_ModuleState_Get();
195 PyObject* type = (PyObject*)Py_TYPE(self);
196 return Py_TYPE(type) == state->message_meta_type;
197}
198
199bool PyUpb_CMessage_Check(PyObject* self) {
200 if (!PyUpb_CMessage_TryCheck(self)) {
201 PyErr_Format(PyExc_TypeError, "Expected a message object, but got %R.",
202 self);
203 return false;
204 }
205 return true;
206}
207
Joshua Haberman58960e02021-12-30 10:50:41 -0800208// If the message is reified, returns it. Otherwise, returns NULL.
209// If NULL is returned, the object is empty and has no underlying data.
210upb_msg* PyUpb_CMessage_GetIfReified(PyObject* _self) {
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800211 PyUpb_CMessage* self = (void*)_self;
Joshua Haberman0549fc02022-01-01 15:42:51 -0800212 return PyUpb_CMessage_IsStub(self) ? NULL : self->ptr.msg;
Joshua Haberman4111d132021-12-04 18:42:53 -0800213}
214
215static PyObject* PyUpb_CMessage_New(PyObject* cls, PyObject* unused_args,
216 PyObject* unused_kwargs) {
217 const upb_msgdef* msgdef = PyUpb_MessageMeta_GetMsgdef(cls);
218 PyUpb_CMessage* msg = (void*)PyType_GenericAlloc((PyTypeObject*)cls, 0);
219 msg->def = (uintptr_t)msgdef;
220 msg->arena = PyUpb_Arena_New();
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800221 msg->ptr.msg = upb_msg_new(msgdef, PyUpb_Arena_Get(msg->arena));
Joshua Haberman4111d132021-12-04 18:42:53 -0800222 msg->unset_subobj_map = NULL;
223 msg->ext_dict = NULL;
224 msg->version = 0;
225
226 PyObject* ret = &msg->ob_base;
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800227 PyUpb_ObjCache_Add(msg->ptr.msg, ret);
Joshua Haberman4111d132021-12-04 18:42:53 -0800228 return ret;
229}
230
Joshua Habermaneb38a2a2021-12-05 23:54:34 -0800231/*
232 * PyUpb_CMessage_LookupName()
233 *
234 * Tries to find a field or oneof named `py_name` in the message object `self`.
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800235 * The user must pass `f` and/or `o` to indicate whether a field or a oneof name
236 * is expected. If the name is found and it has an expected type, the function
Joshua Habermaneb38a2a2021-12-05 23:54:34 -0800237 * sets `*f` or `*o` respectively and returns true. Otherwise returns false
238 * and sets an exception of type `exc_type` if provided.
239 */
Joshua Haberman4111d132021-12-04 18:42:53 -0800240static bool PyUpb_CMessage_LookupName(PyUpb_CMessage* self, PyObject* py_name,
241 const upb_fielddef** f,
242 const upb_oneofdef** o,
243 PyObject* exc_type) {
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800244 assert(f || o);
Joshua Haberman4111d132021-12-04 18:42:53 -0800245 Py_ssize_t size;
246 const char* name = PyUnicode_AsUTF8AndSize(py_name, &size);
247 if (!name) return NULL;
248 const upb_msgdef* msgdef = _PyUpb_CMessage_GetMsgdef(self);
249
250 if (!upb_msgdef_lookupname(msgdef, name, size, f, o)) {
251 if (exc_type) {
252 PyErr_Format(exc_type,
253 "Protocol message %s has no field or oneof named %s.",
254 upb_msgdef_fullname(msgdef), name);
255 }
256 return false;
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800257 }
258
259 if (!o && !*f) {
Joshua Haberman4111d132021-12-04 18:42:53 -0800260 if (exc_type) {
261 PyErr_Format(exc_type, "Expected a field name, but got oneof name %s.",
262 name);
263 }
264 return false;
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800265 }
266
267 if (!f && !*o) {
Joshua Haberman4111d132021-12-04 18:42:53 -0800268 if (exc_type) {
269 PyErr_Format(exc_type, "Expected a oneof name, but got field name %s.",
270 name);
271 }
272 return false;
273 }
274
275 return true;
276}
277
Joshua Habermaneb38a2a2021-12-05 23:54:34 -0800278static bool PyUpb_CMessage_InitMessageMapEntry(PyObject* dst, PyObject* src) {
279 if (!src || !dst) return false;
280
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800281 // TODO(haberman): Currently we are doing Clear()+MergeFrom(). Replace with
282 // CopyFrom() once that is implemented.
Joshua Habermaneb38a2a2021-12-05 23:54:34 -0800283 PyObject* ok = PyObject_CallMethod(dst, "Clear", NULL);
284 if (!ok) return false;
285 Py_DECREF(ok);
286 ok = PyObject_CallMethod(dst, "MergeFrom", "O", src);
287 if (!ok) return false;
288 Py_DECREF(ok);
289
290 return true;
291}
292
Joshua Habermanbf74b3e2021-12-30 00:52:12 -0800293int PyUpb_CMessage_InitMapAttributes(PyObject* map, PyObject* value,
294 const upb_fielddef* f) {
Joshua Haberman4111d132021-12-04 18:42:53 -0800295 const upb_msgdef* entry_m = upb_fielddef_msgsubdef(f);
296 const upb_fielddef* val_f = upb_msgdef_field(entry_m, 1);
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800297 PyObject* it = NULL;
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800298 PyObject* tmp = NULL;
299 int ret = -1;
Joshua Haberman4111d132021-12-04 18:42:53 -0800300 if (upb_fielddef_issubmsg(val_f)) {
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800301 it = PyObject_GetIter(value);
302 if (it == NULL) {
Joshua Haberman4111d132021-12-04 18:42:53 -0800303 PyErr_Format(PyExc_TypeError, "Argument for field %s is not iterable",
304 upb_fielddef_fullname(f));
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800305 goto err;
Joshua Haberman4111d132021-12-04 18:42:53 -0800306 }
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800307 PyObject* e;
308 while ((e = PyIter_Next(it)) != NULL) {
309 PyObject* src = PyObject_GetItem(value, e);
310 PyObject* dst = PyObject_GetItem(map, e);
311 Py_DECREF(e);
Joshua Habermaneb38a2a2021-12-05 23:54:34 -0800312 bool ok = PyUpb_CMessage_InitMessageMapEntry(dst, src);
313 Py_XDECREF(src);
314 Py_XDECREF(dst);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800315 if (!ok) goto err;
Joshua Haberman4111d132021-12-04 18:42:53 -0800316 }
Joshua Haberman4111d132021-12-04 18:42:53 -0800317 } else {
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800318 tmp = PyObject_CallMethod(map, "update", "O", value);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800319 if (!tmp) goto err;
Joshua Haberman4111d132021-12-04 18:42:53 -0800320 }
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800321 ret = 0;
322
323err:
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800324 Py_XDECREF(it);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800325 Py_XDECREF(tmp);
326 return ret;
Joshua Haberman4111d132021-12-04 18:42:53 -0800327}
328
Joshua Haberman54b775d2022-01-05 12:55:52 -0800329void PyUpb_CMessage_EnsureReified(PyUpb_CMessage* self);
Joshua Haberman4111d132021-12-04 18:42:53 -0800330
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800331static bool PyUpb_CMessage_InitMapAttribute(PyObject* _self, PyObject* name,
332 const upb_fielddef* f,
333 PyObject* value) {
Joshua Habermanbf74b3e2021-12-30 00:52:12 -0800334 PyObject* map = PyUpb_CMessage_GetAttr(_self, name);
335 int ok = PyUpb_CMessage_InitMapAttributes(map, value, f);
336 Py_DECREF(map);
337 return ok >= 0;
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800338}
339
Joshua Haberman455426e2021-12-08 23:32:05 -0800340static bool PyUpb_CMessage_InitRepeatedAttribute(PyObject* _self,
341 PyObject* name,
342 PyObject* value) {
343 PyObject* repeated = PyUpb_CMessage_GetAttr(_self, name);
344 PyObject* tmp = PyUpb_RepeatedContainer_Extend(repeated, value);
345 if (!tmp) return false;
346 Py_DECREF(tmp);
347 return true;
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800348}
349
350static bool PyUpb_CMessage_InitMessageAttribute(PyObject* _self, PyObject* name,
351 PyObject* value) {
352 PyObject* submsg = PyUpb_CMessage_GetAttr(_self, name);
353 if (!submsg) return -1;
354 assert(!PyErr_Occurred());
355 bool ok;
356 if (PyUpb_CMessage_TryCheck(value)) {
357 PyObject* tmp = PyUpb_CMessage_MergeFrom(submsg, value);
358 ok = tmp != NULL;
359 Py_DECREF(tmp);
360 } else {
361 assert(!PyErr_Occurred());
362 ok = PyUpb_CMessage_InitAttributes(submsg, NULL, value) >= 0;
363 }
364 Py_DECREF(submsg);
365 return ok;
366}
367
368static bool PyUpb_CMessage_InitScalarAttribute(upb_msg* msg,
369 const upb_fielddef* f,
370 PyObject* value,
371 upb_arena* arena) {
372 upb_msgval msgval;
373 assert(!PyErr_Occurred());
374 if (!PyUpb_PyToUpb(value, f, &msgval, arena)) {
375 PyErr_Clear();
376 PyErr_Format(PyExc_ValueError, "Error initializing field %s",
377 upb_fielddef_fullname(f));
378 return false;
379 }
380 upb_msg_set(msg, f, msgval, arena);
381 return true;
382}
383
Joshua Haberman4111d132021-12-04 18:42:53 -0800384int PyUpb_CMessage_InitAttributes(PyObject* _self, PyObject* args,
385 PyObject* kwargs) {
386 assert(!PyErr_Occurred());
387
388 if (args != NULL && PyTuple_Size(args) != 0) {
389 PyErr_SetString(PyExc_TypeError, "No positional arguments allowed");
390 return -1;
391 }
392
393 if (kwargs == NULL) return 0;
394
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800395 PyUpb_CMessage* self = (void*)_self;
Joshua Haberman4111d132021-12-04 18:42:53 -0800396 Py_ssize_t pos = 0;
397 PyObject* name;
398 PyObject* value;
Joshua Haberman54b775d2022-01-05 12:55:52 -0800399 PyUpb_CMessage_EnsureReified(self);
Joshua Haberman4111d132021-12-04 18:42:53 -0800400 upb_msg* msg = PyUpb_CMessage_GetMsg(self);
401 upb_arena* arena = PyUpb_Arena_Get(self->arena);
402
403 while (PyDict_Next(kwargs, &pos, &name, &value)) {
404 assert(!PyErr_Occurred());
405 const upb_fielddef* f;
406 assert(!PyErr_Occurred());
407 if (!PyUpb_CMessage_LookupName(self, name, &f, NULL, PyExc_ValueError)) {
408 return -1;
409 }
410
411 if (value == Py_None) continue; // Ignored.
412
413 assert(!PyErr_Occurred());
414
415 if (upb_fielddef_ismap(f)) {
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800416 if (!PyUpb_CMessage_InitMapAttribute(_self, name, f, value)) return -1;
Joshua Haberman4111d132021-12-04 18:42:53 -0800417 } else if (upb_fielddef_isseq(f)) {
Joshua Haberman455426e2021-12-08 23:32:05 -0800418 if (!PyUpb_CMessage_InitRepeatedAttribute(_self, name, value)) return -1;
Joshua Haberman4111d132021-12-04 18:42:53 -0800419 } else if (upb_fielddef_issubmsg(f)) {
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800420 if (!PyUpb_CMessage_InitMessageAttribute(_self, name, value)) return -1;
Joshua Haberman4111d132021-12-04 18:42:53 -0800421 } else {
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800422 if (!PyUpb_CMessage_InitScalarAttribute(msg, f, value, arena)) return -1;
Joshua Haberman4111d132021-12-04 18:42:53 -0800423 }
424 if (PyErr_Occurred()) return -1;
425 }
426
427 if (PyErr_Occurred()) return -1;
428 return 0;
429}
430
431static int PyUpb_CMessage_Init(PyObject* _self, PyObject* args,
432 PyObject* kwargs) {
433 if (args != NULL && PyTuple_Size(args) != 0) {
434 PyErr_SetString(PyExc_TypeError, "No positional arguments allowed");
435 return -1;
436 }
437
438 return PyUpb_CMessage_InitAttributes(_self, args, kwargs);
439}
440
Joshua Habermanfaac2d82021-12-30 01:04:49 -0800441static PyObject* PyUpb_CMessage_NewStub(PyObject* parent, const upb_fielddef* f,
442 PyObject* arena) {
Joshua Haberman4111d132021-12-04 18:42:53 -0800443 const upb_msgdef* sub_m = upb_fielddef_msgsubdef(f);
444 PyObject* cls = PyUpb_Descriptor_GetClass(sub_m);
445
446 PyUpb_CMessage* msg = (void*)PyType_GenericAlloc((PyTypeObject*)cls, 0);
447 msg->def = (uintptr_t)f | 1;
448 msg->arena = arena;
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800449 msg->ptr.parent = (PyUpb_CMessage*)parent;
Joshua Haberman4111d132021-12-04 18:42:53 -0800450 msg->unset_subobj_map = NULL;
451 msg->ext_dict = NULL;
452 msg->version = 0;
453
454 Py_DECREF(cls);
455 Py_INCREF(parent);
456 Py_INCREF(arena);
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800457 return &msg->ob_base;
Joshua Haberman4111d132021-12-04 18:42:53 -0800458}
459
460static bool PyUpb_CMessage_IsEqual(PyUpb_CMessage* m1, PyObject* _m2) {
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800461 PyUpb_CMessage* m2 = (void*)_m2;
Joshua Haberman4111d132021-12-04 18:42:53 -0800462 if (m1 == m2) return true;
463 if (!PyObject_TypeCheck(_m2, m1->ob_base.ob_type)) {
464 return false;
465 }
466 const upb_msgdef* m1_msgdef = _PyUpb_CMessage_GetMsgdef(m1);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800467#ifndef NDEBUG
Joshua Haberman4111d132021-12-04 18:42:53 -0800468 const upb_msgdef* m2_msgdef = _PyUpb_CMessage_GetMsgdef(m2);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800469 assert(m1_msgdef == m2_msgdef);
470#endif
Joshua Haberman58960e02021-12-30 10:50:41 -0800471 const upb_msg* m1_msg = PyUpb_CMessage_GetIfReified((PyObject*)m1);
472 const upb_msg* m2_msg = PyUpb_CMessage_GetIfReified(_m2);
Joshua Haberman4111d132021-12-04 18:42:53 -0800473 return PyUpb_Message_IsEqual(m1_msg, m2_msg, m1_msgdef);
474}
475
Joshua Habermandc0d1b42021-12-08 15:40:38 -0800476static const upb_fielddef* PyUpb_CMessage_InitAsMsg(PyUpb_CMessage* m,
477 upb_arena* arena) {
478 const upb_fielddef* f = PyUpb_CMessage_GetFieldDef(m);
479 m->ptr.msg = upb_msg_new(upb_fielddef_msgsubdef(f), arena);
480 m->def = (uintptr_t)upb_fielddef_msgsubdef(f);
Joshua Haberman32ebb482021-12-08 20:06:07 -0800481 PyUpb_ObjCache_Add(m->ptr.msg, &m->ob_base);
Joshua Habermandc0d1b42021-12-08 15:40:38 -0800482 return f;
483}
484
Joshua Haberman32ebb482021-12-08 20:06:07 -0800485static void PyUpb_CMessage_SetField(PyUpb_CMessage* parent,
486 const upb_fielddef* f,
487 PyUpb_CMessage* child, upb_arena* arena) {
488 upb_msgval msgval = {.msg_val = PyUpb_CMessage_GetMsg(child)};
489 upb_msg_set(PyUpb_CMessage_GetMsg(parent), f, msgval, arena);
490 PyUpb_WeakMap_Delete(parent->unset_subobj_map, f);
491 // Releases a ref previously owned by child->ptr.parent of our child.
492 Py_DECREF(child);
Joshua Habermandc0d1b42021-12-08 15:40:38 -0800493}
494
Joshua Haberman4111d132021-12-04 18:42:53 -0800495/*
Joshua Haberman54b775d2022-01-05 12:55:52 -0800496 * PyUpb_CMessage_EnsureReified()
Joshua Haberman4111d132021-12-04 18:42:53 -0800497 *
498 * This implements the "expando" behavior of Python protos:
499 * foo = FooProto()
500 *
501 * # The intermediate messages don't really exist, and won't be serialized.
502 * x = foo.bar.bar.bar.bar.bar.baz
503 *
504 * # Now all the intermediate objects are created.
505 * foo.bar.bar.bar.bar.bar.baz = 5
506 *
507 * This function should be called before performing any mutation of a protobuf
508 * object.
509 *
510 * Post-condition:
Joshua Haberman0549fc02022-01-01 15:42:51 -0800511 * PyUpb_CMessage_IsStub(self) is false
Joshua Haberman4111d132021-12-04 18:42:53 -0800512 */
Joshua Haberman54b775d2022-01-05 12:55:52 -0800513void PyUpb_CMessage_EnsureReified(PyUpb_CMessage* self) {
Joshua Haberman0549fc02022-01-01 15:42:51 -0800514 if (!PyUpb_CMessage_IsStub(self)) return;
Joshua Haberman32ebb482021-12-08 20:06:07 -0800515 upb_arena* arena = PyUpb_Arena_Get(self->arena);
516
Joshua Haberman4111d132021-12-04 18:42:53 -0800517 // This is a non-present message. We need to create a real upb_msg for this
518 // object and every parent until we reach a present message.
Joshua Haberman32ebb482021-12-08 20:06:07 -0800519 PyUpb_CMessage* child = self;
520 PyUpb_CMessage* parent = self->ptr.parent;
Joshua Habermandc0d1b42021-12-08 15:40:38 -0800521 const upb_fielddef* child_f = PyUpb_CMessage_InitAsMsg(child, arena);
Joshua Haberman32ebb482021-12-08 20:06:07 -0800522 Py_INCREF(child); // To avoid a special-case in PyUpb_CMessage_SetField().
523
Joshua Habermandc0d1b42021-12-08 15:40:38 -0800524 do {
Joshua Haberman32ebb482021-12-08 20:06:07 -0800525 PyUpb_CMessage* next_parent = parent->ptr.parent;
Joshua Haberman4111d132021-12-04 18:42:53 -0800526 const upb_fielddef* parent_f = NULL;
Joshua Haberman0549fc02022-01-01 15:42:51 -0800527 if (PyUpb_CMessage_IsStub(parent)) {
Joshua Habermandc0d1b42021-12-08 15:40:38 -0800528 parent_f = PyUpb_CMessage_InitAsMsg(parent, arena);
Joshua Haberman4111d132021-12-04 18:42:53 -0800529 }
Joshua Habermandc0d1b42021-12-08 15:40:38 -0800530 PyUpb_CMessage_SetField(parent, child_f, child, arena);
Joshua Habermandc0d1b42021-12-08 15:40:38 -0800531 child = parent;
Joshua Haberman32ebb482021-12-08 20:06:07 -0800532 child_f = parent_f;
Joshua Haberman4111d132021-12-04 18:42:53 -0800533 parent = next_parent;
Joshua Haberman32ebb482021-12-08 20:06:07 -0800534 } while (child_f);
Joshua Haberman4111d132021-12-04 18:42:53 -0800535
Joshua Haberman32ebb482021-12-08 20:06:07 -0800536 // Releases ref previously owned by child->ptr.parent of our child.
537 Py_DECREF(child);
538 self->version++;
Joshua Haberman4111d132021-12-04 18:42:53 -0800539}
540
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800541static void PyUpb_CMessage_SyncSubobjs(PyUpb_CMessage* self);
542
543/*
Joshua Habermanfaac2d82021-12-30 01:04:49 -0800544 * PyUpb_CMessage_Reify()
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800545 *
Joshua Habermanfaac2d82021-12-30 01:04:49 -0800546 * The message equivalent of PyUpb_*Container_Reify(), this transitions
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800547 * the wrapper from the unset state (owning a reference on self->ptr.parent) to the
548 * set state (having a non-owning pointer to self->ptr.msg).
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800549 */
Joshua Habermanfaac2d82021-12-30 01:04:49 -0800550static void PyUpb_CMessage_Reify(PyUpb_CMessage* self, const upb_fielddef* f,
551 upb_msg* msg) {
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800552 assert(f == PyUpb_CMessage_GetFieldDef(self));
553 PyUpb_ObjCache_Add(msg, &self->ob_base);
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800554 Py_DECREF(&self->ptr.parent->ob_base);
555 self->ptr.msg = msg; // Overwrites self->ptr.parent
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800556 self->def = (uintptr_t)upb_fielddef_msgsubdef(f);
557 PyUpb_CMessage_SyncSubobjs(self);
558}
559
Joshua Habermaneb38a2a2021-12-05 23:54:34 -0800560/*
561 * PyUpb_CMessage_SyncSubobjs()
562 *
563 * This operation must be invoked whenever the underlying upb_msg has been
564 * mutated directly in C. This will attach any newly-present field data
Joshua Haberman54b775d2022-01-05 12:55:52 -0800565 * to previously returned stub wrapper objects.
Joshua Habermaneb38a2a2021-12-05 23:54:34 -0800566 *
567 * For example:
568 * foo = FooMessage()
569 * sub = foo.submsg # Empty, unset sub-message
570 *
571 * # SyncSubobjs() is required to connect our existing 'sub' wrapper to the
572 * # newly created foo.submsg data in C.
573 * foo.MergeFrom(FooMessage(submsg={}))
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800574 *
575 * This requires that all of the new sub-objects that have appeared are owned
576 * by `self`'s arena.
Joshua Habermaneb38a2a2021-12-05 23:54:34 -0800577 */
Joshua Haberman4111d132021-12-04 18:42:53 -0800578static void PyUpb_CMessage_SyncSubobjs(PyUpb_CMessage* self) {
579 PyUpb_WeakMap* subobj_map = self->unset_subobj_map;
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800580 if (!subobj_map) return;
581
Joshua Haberman4111d132021-12-04 18:42:53 -0800582 upb_msg* msg = PyUpb_CMessage_GetMsg(self);
583 intptr_t iter = PYUPB_WEAKMAP_BEGIN;
584 const void* key;
585 PyObject* obj;
586
Joshua Haberman4111d132021-12-04 18:42:53 -0800587 // The last ref to this message could disappear during iteration.
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800588 // When we call PyUpb_*Container_SwitchToSet() below, the container will drop
589 // its ref on `self`. If that was the last ref on self, the object will be
590 // deleted, and `subobj_map` along with it. We need it to live until we are
591 // done iterating.
Joshua Haberman4111d132021-12-04 18:42:53 -0800592 Py_INCREF(&self->ob_base);
593
594 while (PyUpb_WeakMap_Next(subobj_map, &key, &obj, &iter)) {
595 const upb_fielddef* f = key;
596 if (upb_fielddef_haspresence(f) && !upb_msg_has(msg, f)) continue;
597 upb_msgval msgval = upb_msg_get(msg, f);
598 PyUpb_WeakMap_DeleteIter(subobj_map, &iter);
599 if (upb_fielddef_ismap(f)) {
600 if (!msgval.map_val) continue;
Joshua Habermanfaac2d82021-12-30 01:04:49 -0800601 PyUpb_MapContainer_Reify(obj, (upb_map*)msgval.map_val);
Joshua Haberman4111d132021-12-04 18:42:53 -0800602 } else if (upb_fielddef_isseq(f)) {
603 if (!msgval.array_val) continue;
Joshua Haberman2d4ffbf2021-12-09 16:21:43 -0800604 PyUpb_RepeatedContainer_Reify(obj, (upb_array*)msgval.array_val);
Joshua Haberman4111d132021-12-04 18:42:53 -0800605 } else {
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800606 PyUpb_CMessage* sub = (void*)obj;
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800607 assert(self == sub->ptr.parent);
Joshua Habermanfaac2d82021-12-30 01:04:49 -0800608 PyUpb_CMessage_Reify(sub, f, (upb_msg*)msgval.msg_val);
Joshua Haberman4111d132021-12-04 18:42:53 -0800609 }
610 }
611
612 Py_DECREF(&self->ob_base);
Joshua Habermaneb38a2a2021-12-05 23:54:34 -0800613
614 // TODO(haberman): present fields need to be iterated too if they can reach
615 // a WeakMap.
Joshua Haberman4111d132021-12-04 18:42:53 -0800616}
617
618static PyObject* PyUpb_CMessage_ToString(PyUpb_CMessage* self) {
Joshua Haberman0549fc02022-01-01 15:42:51 -0800619 if (PyUpb_CMessage_IsStub(self)) {
Joshua Haberman4111d132021-12-04 18:42:53 -0800620 return PyUnicode_FromStringAndSize(NULL, 0);
621 }
622 upb_msg* msg = PyUpb_CMessage_GetMsg(self);
623 const upb_msgdef* msgdef = _PyUpb_CMessage_GetMsgdef(self);
624 const upb_symtab* symtab = upb_filedef_symtab(upb_msgdef_file(msgdef));
625 char buf[1024];
626 int options = UPB_TXTENC_SKIPUNKNOWN;
627 size_t size = upb_text_encode(msg, msgdef, symtab, options, buf, sizeof(buf));
628 if (size < sizeof(buf)) {
629 return PyUnicode_FromStringAndSize(buf, size);
630 } else {
631 char* buf2 = malloc(size + 1);
632 size_t size2 =
633 upb_text_encode(msg, msgdef, symtab, options, buf2, size + 1);
634 assert(size == size2);
635 PyObject* ret = PyUnicode_FromStringAndSize(buf2, size2);
636 free(buf2);
637 return ret;
638 }
639}
640
641static PyObject* PyUpb_CMessage_RichCompare(PyObject* _self, PyObject* other,
642 int opid) {
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800643 PyUpb_CMessage* self = (void*)_self;
Joshua Haberman4111d132021-12-04 18:42:53 -0800644 if (opid != Py_EQ && opid != Py_NE) {
645 Py_INCREF(Py_NotImplemented);
646 return Py_NotImplemented;
647 }
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800648 bool ret = PyUpb_CMessage_IsEqual(self, other);
649 if (opid == Py_NE) ret = !ret;
Joshua Haberman4111d132021-12-04 18:42:53 -0800650 return PyBool_FromLong(ret);
651}
652
653void PyUpb_CMessage_CacheDelete(PyObject* _self, const upb_fielddef* f) {
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800654 PyUpb_CMessage* self = (void*)_self;
Joshua Haberman4111d132021-12-04 18:42:53 -0800655 PyUpb_WeakMap_Delete(self->unset_subobj_map, f);
656}
657
658void PyUpb_CMessage_SetConcreteSubobj(PyObject* _self, const upb_fielddef* f,
659 upb_msgval subobj) {
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800660 PyUpb_CMessage* self = (void*)_self;
Joshua Haberman54b775d2022-01-05 12:55:52 -0800661 PyUpb_CMessage_EnsureReified(self);
Joshua Haberman4111d132021-12-04 18:42:53 -0800662 PyUpb_CMessage_CacheDelete(_self, f);
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800663 upb_msg_set(self->ptr.msg, f, subobj, PyUpb_Arena_Get(self->arena));
Joshua Haberman4111d132021-12-04 18:42:53 -0800664}
665
666static void PyUpb_CMessage_Dealloc(PyObject* _self) {
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800667 PyUpb_CMessage* self = (void*)_self;
Joshua Haberman4111d132021-12-04 18:42:53 -0800668
Joshua Haberman0549fc02022-01-01 15:42:51 -0800669 if (PyUpb_CMessage_IsStub(self)) {
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800670 PyUpb_CMessage_CacheDelete((PyObject*)self->ptr.parent,
Joshua Haberman4111d132021-12-04 18:42:53 -0800671 PyUpb_CMessage_GetFieldDef(self));
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800672 Py_DECREF(self->ptr.parent);
Joshua Haberman4111d132021-12-04 18:42:53 -0800673 } else {
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800674 PyUpb_ObjCache_Delete(self->ptr.msg);
Joshua Haberman4111d132021-12-04 18:42:53 -0800675 }
676
677 if (self->unset_subobj_map) {
678 PyUpb_WeakMap_Free(self->unset_subobj_map);
679 }
680
681 Py_DECREF(self->arena);
682
683 // We do not use PyUpb_Dealloc() here because CMessage is a base type and for
684 // base types there is a bug we have to work around in this case (see below).
685 PyTypeObject* tp = Py_TYPE(self);
686 freefunc tp_free = PyType_GetSlot(tp, Py_tp_free);
687 tp_free(self);
688
689 if (cpython_bits.python_version_hex >= 0x03080000) {
690 // Prior to Python 3.8 there is a bug where deallocating the type here would
691 // lead to a double-decref: https://bugs.python.org/issue37879
692 Py_DECREF(tp);
693 }
694}
695
696PyObject* PyUpb_CMessage_Get(upb_msg* u_msg, const upb_msgdef* m,
697 PyObject* arena) {
698 PyObject* ret = PyUpb_ObjCache_Get(u_msg);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800699 if (ret) return ret;
Joshua Haberman4111d132021-12-04 18:42:53 -0800700
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800701 PyObject* cls = PyUpb_Descriptor_GetClass(m);
702 // It is not safe to use PyObject_{,GC}_New() due to:
703 // https://bugs.python.org/issue35810
704 PyUpb_CMessage* py_msg = (void*)PyType_GenericAlloc((PyTypeObject*)cls, 0);
705 py_msg->arena = arena;
706 py_msg->def = (uintptr_t)m;
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800707 py_msg->ptr.msg = u_msg;
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800708 py_msg->unset_subobj_map = NULL;
709 py_msg->ext_dict = NULL;
710 py_msg->version = 0;
711 ret = &py_msg->ob_base;
712 Py_DECREF(cls);
713 Py_INCREF(arena);
714 PyUpb_ObjCache_Add(u_msg, ret);
715 return ret;
716}
717
Joshua Habermane5d8d282022-01-05 15:47:59 -0800718/* PyUpb_CMessage_GetStub()
719 *
720 * Non-present messages return "stub" objects that point to their parent, but
721 * will materialize into real upb objects if they are mutated.
722 *
723 * Note: we do *not* create stubs for repeated/map fields unless the parent
724 * is a stub:
725 *
726 * msg = TestMessage()
727 * msg.submessage # (A) Creates a stub
728 * msg.repeated_foo # (B) Does *not* create a stub
729 * msg.submessage.repeated_bar # (C) Creates a stub
730 *
731 * In case (B) we have some freedom: we could either create a stub, or create
732 * a reified object with underlying data. It appears that either could work
733 * equally well, with no observable change to users. There isn't a clear
734 * advantage to either choice. We choose to follow the behavior of the
735 * pre-existing C++ behavior for consistency, but if it becomes apparent that
736 * there would be some benefit to reversing this decision, it should be totally
737 * within the realm of possibility.
738 */
739PyObject* PyUpb_CMessage_GetStub(PyUpb_CMessage* self,
740 const upb_fielddef* field) {
Joshua Haberman455426e2021-12-08 23:32:05 -0800741 PyObject* _self = (void*)self;
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800742 if (!self->unset_subobj_map) {
743 self->unset_subobj_map = PyUpb_WeakMap_New();
744 }
745 PyObject* subobj = PyUpb_WeakMap_Get(self->unset_subobj_map, field);
746
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800747 if (subobj) return subobj;
748
749 if (upb_fielddef_ismap(field)) {
Joshua Habermanfaac2d82021-12-30 01:04:49 -0800750 subobj = PyUpb_MapContainer_NewStub(_self, field, self->arena);
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800751 } else if (upb_fielddef_isseq(field)) {
Joshua Habermanfaac2d82021-12-30 01:04:49 -0800752 subobj = PyUpb_RepeatedContainer_NewStub(_self, field, self->arena);
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800753 } else {
Joshua Habermanfaac2d82021-12-30 01:04:49 -0800754 subobj = PyUpb_CMessage_NewStub(&self->ob_base, field, self->arena);
Joshua Haberman4111d132021-12-04 18:42:53 -0800755 }
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800756 PyUpb_WeakMap_Add(self->unset_subobj_map, field, subobj);
Joshua Haberman4111d132021-12-04 18:42:53 -0800757
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800758 assert(!PyErr_Occurred());
759 return subobj;
760}
761
762PyObject* PyUpb_CMessage_GetPresentWrapper(PyUpb_CMessage* self,
763 const upb_fielddef* field) {
Joshua Haberman0549fc02022-01-01 15:42:51 -0800764 assert(!PyUpb_CMessage_IsStub(self));
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800765 upb_mutmsgval mutval =
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800766 upb_msg_mutable(self->ptr.msg, field, PyUpb_Arena_Get(self->arena));
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800767 if (upb_fielddef_ismap(field)) {
Joshua Habermanbf74b3e2021-12-30 00:52:12 -0800768 return PyUpb_MapContainer_GetOrCreateWrapper(mutval.map, field,
769 self->arena);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800770 } else {
Joshua Haberman455426e2021-12-08 23:32:05 -0800771 return PyUpb_RepeatedContainer_GetOrCreateWrapper(mutval.array, field,
772 self->arena);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800773 }
774}
775
776PyObject* PyUpb_CMessage_GetScalarValue(PyUpb_CMessage* self,
777 const upb_fielddef* field) {
778 upb_msgval val;
Joshua Haberman0549fc02022-01-01 15:42:51 -0800779 if (PyUpb_CMessage_IsStub(self)) {
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800780 // Unset message always returns default values.
781 val = upb_fielddef_default(field);
782 } else {
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800783 val = upb_msg_get(self->ptr.msg, field);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800784 }
785 return PyUpb_UpbToPy(val, field, self->arena);
Joshua Haberman4111d132021-12-04 18:42:53 -0800786}
787
Joshua Habermaneb38a2a2021-12-05 23:54:34 -0800788/*
789 * PyUpb_CMessage_GetFieldValue()
790 *
791 * Implements the equivalent of getattr(msg, field), once `field` has
792 * already been resolved to a `upb_fielddef*`.
793 *
794 * This may involve constructing a wrapper object for the given field, or
795 * returning one that was previously constructed. If the field is not actually
796 * set, the wrapper object will be an "unset" object that is not actually
797 * connected to any C data.
798 */
Joshua Haberman4111d132021-12-04 18:42:53 -0800799PyObject* PyUpb_CMessage_GetFieldValue(PyObject* _self,
800 const upb_fielddef* field) {
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800801 PyUpb_CMessage* self = (void*)_self;
Joshua Haberman4111d132021-12-04 18:42:53 -0800802 assert(upb_fielddef_containingtype(field) == PyUpb_CMessage_GetMsgdef(_self));
803 bool submsg = upb_fielddef_issubmsg(field);
804 bool seq = upb_fielddef_isseq(field);
805
Joshua Haberman0549fc02022-01-01 15:42:51 -0800806 if ((PyUpb_CMessage_IsStub(self) && (submsg || seq)) ||
Joshua Habermane5d8d282022-01-05 15:47:59 -0800807 (submsg && !seq && !upb_msg_has(self->ptr.msg, field))) {
808 return PyUpb_CMessage_GetStub(self, field);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800809 } else if (seq) {
810 return PyUpb_CMessage_GetPresentWrapper(self, field);
Joshua Haberman4111d132021-12-04 18:42:53 -0800811 } else {
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800812 return PyUpb_CMessage_GetScalarValue(self, field);
Joshua Haberman4111d132021-12-04 18:42:53 -0800813 }
814}
815
816int PyUpb_CMessage_SetFieldValue(PyObject* _self, const upb_fielddef* field,
817 PyObject* value) {
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800818 PyUpb_CMessage* self = (void*)_self;
Joshua Haberman0549fc02022-01-01 15:42:51 -0800819 assert(value);
820
Joshua Haberman4111d132021-12-04 18:42:53 -0800821 if (upb_fielddef_issubmsg(field) || upb_fielddef_isseq(field)) {
822 PyErr_Format(PyExc_AttributeError,
823 "Assignment not allowed to message, map, or repeated "
824 "field \"%s\" in protocol message object.",
825 upb_fielddef_name(field));
826 return -1;
827 }
828
Joshua Haberman54b775d2022-01-05 12:55:52 -0800829 PyUpb_CMessage_EnsureReified(self);
Joshua Haberman4111d132021-12-04 18:42:53 -0800830
831 upb_msgval val;
832 upb_arena* arena = PyUpb_Arena_Get(self->arena);
833 if (!PyUpb_PyToUpb(value, field, &val, arena)) {
834 return -1;
835 }
836
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800837 upb_msg_set(self->ptr.msg, field, val, arena);
Joshua Haberman4111d132021-12-04 18:42:53 -0800838 return 0;
839}
840
841int PyUpb_CMessage_GetVersion(PyObject* _self) {
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800842 PyUpb_CMessage* self = (void*)_self;
Joshua Haberman4111d132021-12-04 18:42:53 -0800843 return self->version;
844}
845
Joshua Haberman4111d132021-12-04 18:42:53 -0800846/*
847 * PyUpb_CMessage_GetAttr()
848 *
849 * Implements:
850 * foo = msg.foo
851 *
852 * Attribute lookup must find both message fields and base class methods like
853 * msg.SerializeToString().
854 */
855__attribute__((flatten)) static PyObject* PyUpb_CMessage_GetAttr(
856 PyObject* _self, PyObject* attr) {
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800857 PyUpb_CMessage* self = (void*)_self;
Joshua Haberman4111d132021-12-04 18:42:53 -0800858
859 // Lookup field by name.
860 const upb_fielddef* field;
861 if (PyUpb_CMessage_LookupName(self, attr, &field, NULL, NULL)) {
862 return PyUpb_CMessage_GetFieldValue(_self, field);
863 }
864
865 // Check base class attributes.
866 assert(!PyErr_Occurred());
867 PyObject* ret = PyObject_GenericGetAttr(_self, attr);
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800868 if (ret) return ret;
Joshua Haberman4111d132021-12-04 18:42:53 -0800869
Joshua Haberman14372452021-12-31 12:02:36 -0800870 // Swallow AttributeError if it occurred and try again on the metaclass
871 // to pick up class attributes. But we have to special-case "Extensions"
872 // which affirmatively returns AttributeError when a message is not
873 // extendable.
874 if (PyErr_ExceptionMatches(PyExc_AttributeError) &&
875 strcmp(PyUpb_GetStrData(attr), "Extensions") != 0) {
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800876 PyErr_Clear();
877 return PyUpb_MessageMeta_GetAttr((PyObject*)Py_TYPE(_self), attr);
Joshua Haberman4111d132021-12-04 18:42:53 -0800878 }
Joshua Haberman4111d132021-12-04 18:42:53 -0800879
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800880 return NULL;
Joshua Haberman4111d132021-12-04 18:42:53 -0800881}
882
883/*
884 * PyUpb_CMessage_SetAttr()
885 *
886 * Implements:
887 * msg.foo = foo
888 */
889static int PyUpb_CMessage_SetAttr(PyObject* _self, PyObject* attr,
890 PyObject* value) {
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800891 PyUpb_CMessage* self = (void*)_self;
Joshua Haberman4111d132021-12-04 18:42:53 -0800892 const upb_fielddef* field;
893 if (!PyUpb_CMessage_LookupName(self, attr, &field, NULL,
894 PyExc_AttributeError)) {
895 return -1;
896 }
897
898 return PyUpb_CMessage_SetFieldValue(_self, field, value);
899}
900
901static PyObject* PyUpb_CMessage_HasField(PyObject* _self, PyObject* arg) {
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800902 PyUpb_CMessage* self = (void*)_self;
Joshua Haberman4111d132021-12-04 18:42:53 -0800903 const upb_fielddef* field;
904 const upb_oneofdef* oneof;
905
906 if (!PyUpb_CMessage_LookupName(self, arg, &field, &oneof, PyExc_ValueError)) {
907 return NULL;
908 }
909
910 if (field && !upb_fielddef_haspresence(field)) {
911 PyErr_Format(PyExc_ValueError, "Field %s does not have presence.",
912 upb_fielddef_fullname(field));
913 return NULL;
914 }
915
Joshua Haberman0549fc02022-01-01 15:42:51 -0800916 if (PyUpb_CMessage_IsStub(self)) Py_RETURN_FALSE;
Joshua Haberman4111d132021-12-04 18:42:53 -0800917
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800918 return PyBool_FromLong(field ? upb_msg_has(self->ptr.msg, field)
919 : upb_msg_whichoneof(self->ptr.msg, oneof) != NULL);
Joshua Haberman4111d132021-12-04 18:42:53 -0800920}
921
922static PyObject* PyUpb_CMessage_ListFields(PyObject* _self, PyObject* arg) {
923 PyObject* list = PyList_New(0);
Joshua Haberman58960e02021-12-30 10:50:41 -0800924 upb_msg* msg = PyUpb_CMessage_GetIfReified(_self);
Joshua Haberman4423e912021-12-27 18:04:58 -0800925 if (!msg) return list;
Joshua Haberman4111d132021-12-04 18:42:53 -0800926
Joshua Haberman4423e912021-12-27 18:04:58 -0800927 size_t iter1 = UPB_MSG_BEGIN;
928 const upb_msgdef* m = PyUpb_CMessage_GetMsgdef(_self);
929 const upb_symtab* symtab = upb_filedef_symtab(upb_msgdef_file(m));
930 const upb_fielddef* f;
931 PyObject* field_desc = NULL;
932 PyObject* py_val = NULL;
933 PyObject* tuple = NULL;
934 upb_msgval val;
935 while (upb_msg_next(msg, m, symtab, &f, &val, &iter1)) {
936 PyObject* field_desc = PyUpb_FieldDescriptor_Get(f);
937 PyObject* py_val = PyUpb_CMessage_GetFieldValue(_self, f);
938 if (!field_desc || !py_val) goto err;
939 PyObject* tuple = Py_BuildValue("(NN)", field_desc, py_val);
940 field_desc = NULL;
941 py_val = NULL;
942 if (!tuple) goto err;
Joshua Habermanaee30142021-12-28 20:27:17 -0800943 if (PyList_Append(list, tuple)) goto err;
Joshua Haberman4423e912021-12-27 18:04:58 -0800944 Py_DECREF(tuple);
945 tuple = NULL;
Joshua Haberman4111d132021-12-04 18:42:53 -0800946 }
947
948 return list;
Joshua Haberman4423e912021-12-27 18:04:58 -0800949
950err:
951 Py_XDECREF(field_desc);
952 Py_XDECREF(py_val);
953 Py_XDECREF(tuple);
954 Py_DECREF(list);
955 return NULL;
Joshua Haberman4111d132021-12-04 18:42:53 -0800956}
957
958PyObject* PyUpb_CMessage_MergeFrom(PyObject* self, PyObject* arg) {
959 if (self->ob_type != arg->ob_type) {
960 PyErr_Format(PyExc_TypeError,
961 "Parameter to MergeFrom() must be instance of same class: "
962 "expected %S got %S.",
963 Py_TYPE(self), Py_TYPE(arg));
964 return NULL;
965 }
966 // OPT: exit if src is empty.
967 PyObject* subargs = PyTuple_New(0);
968 PyObject* serialized = PyUpb_CMessage_SerializeToString(arg, subargs, NULL);
969 Py_DECREF(subargs);
970 if (!serialized) return NULL;
971 PyObject* ret = PyUpb_CMessage_MergeFromString(self, serialized);
972 Py_DECREF(serialized);
973 Py_DECREF(ret);
974 Py_RETURN_NONE;
975}
976
977static PyObject* PyUpb_CMessage_SetInParent(PyObject* _self, PyObject* arg) {
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800978 PyUpb_CMessage* self = (void*)_self;
Joshua Haberman54b775d2022-01-05 12:55:52 -0800979 PyUpb_CMessage_EnsureReified(self);
Joshua Haberman4111d132021-12-04 18:42:53 -0800980 Py_RETURN_NONE;
981}
982
983static PyObject* PyUpb_CMessage_UnknownFields(PyObject* _self, PyObject* arg) {
984 // TODO(haberman): re-enable when unknown fields are added.
985 // return PyUpb_UnknownFields_New(_self);
986 PyErr_SetString(PyExc_NotImplementedError, "unknown field accessor");
987 return NULL;
988}
989
990PyObject* PyUpb_CMessage_MergeFromString(PyObject* _self, PyObject* arg) {
Joshua Habermanc42beeb2021-12-06 23:07:14 -0800991 PyUpb_CMessage* self = (void*)_self;
Joshua Haberman4111d132021-12-04 18:42:53 -0800992 char* buf;
993 Py_ssize_t size;
994 PyObject* bytes = NULL;
995
996 if (PyMemoryView_Check(arg)) {
997 bytes = PyBytes_FromObject(arg);
Joshua Haberman6bb891e2021-12-08 15:29:48 -0800998 // Cannot fail when passed something of the correct type.
999 int err = PyBytes_AsStringAndSize(bytes, &buf, &size);
1000 (void)err;
1001 assert(err >= 0);
Joshua Haberman4111d132021-12-04 18:42:53 -08001002 } else if (PyBytes_AsStringAndSize(arg, &buf, &size) < 0) {
1003 return NULL;
1004 }
1005
Joshua Haberman54b775d2022-01-05 12:55:52 -08001006 PyUpb_CMessage_EnsureReified(self);
Joshua Haberman4111d132021-12-04 18:42:53 -08001007 const upb_msgdef* msgdef = _PyUpb_CMessage_GetMsgdef(self);
1008 const upb_filedef* file = upb_msgdef_file(msgdef);
1009 const upb_extreg* extreg = upb_symtab_extreg(upb_filedef_symtab(file));
1010 const upb_msglayout* layout = upb_msgdef_layout(msgdef);
1011 upb_arena* arena = PyUpb_Arena_Get(self->arena);
Joshua Haberman14372452021-12-31 12:02:36 -08001012 PyUpb_ModuleState* state = PyUpb_ModuleState_Get();
Joshua Haberman5b3447e2021-12-31 15:37:23 -08001013 int options =
Joshua Haberman14372452021-12-31 12:02:36 -08001014 UPB_DECODE_MAXDEPTH(state->allow_oversize_protos ? UINT32_MAX : 100);
Joshua Haberman4111d132021-12-04 18:42:53 -08001015 upb_DecodeStatus status =
Joshua Haberman14372452021-12-31 12:02:36 -08001016 _upb_decode(buf, size, self->ptr.msg, layout, extreg, options, arena);
Joshua Haberman4111d132021-12-04 18:42:53 -08001017 Py_XDECREF(bytes);
1018 if (status != kUpb_DecodeStatus_Ok) {
Joshua Haberman4111d132021-12-04 18:42:53 -08001019 PyErr_Format(state->decode_error_class, "Error parsing message");
1020 return NULL;
1021 }
1022 PyUpb_CMessage_SyncSubobjs(self);
1023 return PyLong_FromSsize_t(size);
1024}
1025
1026static PyObject* PyUpb_CMessage_Clear(PyUpb_CMessage* self, PyObject* args);
1027
1028static PyObject* PyUpb_CMessage_ParseFromString(PyObject* self, PyObject* arg) {
1029 PyObject* tmp = PyUpb_CMessage_Clear((PyUpb_CMessage*)self, NULL);
1030 Py_DECREF(tmp);
1031 return PyUpb_CMessage_MergeFromString(self, arg);
1032}
1033
1034static PyObject* PyUpb_CMessage_ByteSize(PyObject* self, PyObject* args) {
Joshua Haberman6bb891e2021-12-08 15:29:48 -08001035 // TODO(https://github.com/protocolbuffers/upb/issues/462): At the moment upb
1036 // does not have a "byte size" function, so we just serialize to string and
1037 // get the size of the string.
Joshua Haberman4111d132021-12-04 18:42:53 -08001038 PyObject* subargs = PyTuple_New(0);
1039 PyObject* serialized = PyUpb_CMessage_SerializeToString(self, subargs, NULL);
1040 Py_DECREF(subargs);
1041 if (!serialized) return NULL;
1042 size_t size = PyBytes_Size(serialized);
1043 Py_DECREF(serialized);
1044 return PyLong_FromSize_t(size);
1045}
1046
1047static PyObject* PyUpb_CMessage_Clear(PyUpb_CMessage* self, PyObject* args) {
Joshua Haberman54b775d2022-01-05 12:55:52 -08001048 PyUpb_CMessage_EnsureReified(self);
Joshua Haberman4111d132021-12-04 18:42:53 -08001049 const upb_msgdef* msgdef = _PyUpb_CMessage_GetMsgdef(self);
Joshua Haberman6bb891e2021-12-08 15:29:48 -08001050 upb_msg_clear(self->ptr.msg, msgdef);
Joshua Haberman4111d132021-12-04 18:42:53 -08001051 Py_RETURN_NONE;
1052}
1053
Joshua Haberman0549fc02022-01-01 15:42:51 -08001054void PyUpb_CMessage_DoClearField(PyObject* _self, const upb_fielddef* f) {
1055 PyUpb_CMessage* self = (void*)_self;
Joshua Haberman54b775d2022-01-05 12:55:52 -08001056 PyUpb_CMessage_EnsureReified((PyUpb_CMessage*)self);
1057
1058 // We must ensure that any stub object is reified so its parent no longer
1059 // points to us.
1060 PyObject* sub = self->unset_subobj_map
1061 ? PyUpb_WeakMap_Get(self->unset_subobj_map, f)
1062 : NULL;
Joshua Haberman4111d132021-12-04 18:42:53 -08001063
1064 if (upb_fielddef_ismap(f)) {
Joshua Haberman54b775d2022-01-05 12:55:52 -08001065 // For maps we additionally have to invalidate any iterators. So we need
1066 // to get an object even if it's reified.
1067 if (!sub) {
1068 sub = PyUpb_CMessage_GetFieldValue(_self, f);
Joshua Haberman4111d132021-12-04 18:42:53 -08001069 }
Joshua Haberman54b775d2022-01-05 12:55:52 -08001070 PyUpb_MapContainer_EnsureReified(sub);
1071 PyUpb_MapContainer_Invalidate(sub);
1072 } else if (upb_fielddef_isseq(f)) {
1073 if (sub) {
Joshua Habermane5d8d282022-01-05 15:47:59 -08001074 PyUpb_RepeatedContainer_EnsureReified(sub);
Joshua Haberman4111d132021-12-04 18:42:53 -08001075 }
Joshua Haberman54b775d2022-01-05 12:55:52 -08001076 } else if (upb_fielddef_issubmsg(f)) {
1077 if (sub) {
1078 PyUpb_CMessage_EnsureReified((PyUpb_CMessage*)sub);
Joshua Haberman0549fc02022-01-01 15:42:51 -08001079 }
Joshua Haberman4111d132021-12-04 18:42:53 -08001080 }
1081
Joshua Haberman54b775d2022-01-05 12:55:52 -08001082 Py_XDECREF(sub);
Joshua Haberman0549fc02022-01-01 15:42:51 -08001083 upb_msg_clearfield(self->ptr.msg, f);
1084}
Joshua Haberman4111d132021-12-04 18:42:53 -08001085
Joshua Haberman0549fc02022-01-01 15:42:51 -08001086static PyObject* PyUpb_CMessage_ClearExtension(PyObject* _self, PyObject* arg) {
1087 PyUpb_CMessage* self = (void*)_self;
Joshua Haberman54b775d2022-01-05 12:55:52 -08001088 PyUpb_CMessage_EnsureReified(self);
Joshua Haberman72603462022-01-01 16:08:29 -08001089 const upb_fielddef* f = PyUpb_CMessage_GetExtensionDef(_self, arg);
Joshua Haberman0549fc02022-01-01 15:42:51 -08001090 if (!f) return NULL;
Joshua Haberman0549fc02022-01-01 15:42:51 -08001091 PyUpb_CMessage_DoClearField(_self, f);
1092 Py_RETURN_NONE;
1093}
1094
1095static PyObject* PyUpb_CMessage_ClearField(PyObject* _self, PyObject* arg) {
1096 PyUpb_CMessage* self = (void*)_self;
1097
Joshua Haberman54b775d2022-01-05 12:55:52 -08001098 // We always need EnsureReified() here (even for an unset message) to
Joshua Haberman0549fc02022-01-01 15:42:51 -08001099 // preserve behavior like:
1100 // msg = FooMessage()
1101 // msg.foo.Clear()
1102 // assert msg.HasField("foo")
Joshua Haberman54b775d2022-01-05 12:55:52 -08001103 PyUpb_CMessage_EnsureReified(self);
Joshua Haberman0549fc02022-01-01 15:42:51 -08001104
1105 const upb_fielddef* f;
1106 const upb_oneofdef* o;
1107 if (!PyUpb_CMessage_LookupName(self, arg, &f, &o, PyExc_ValueError)) {
1108 return NULL;
1109 }
1110
1111 if (o) f = upb_msg_whichoneof(self->ptr.msg, o);
1112 PyUpb_CMessage_DoClearField(_self, f);
Joshua Haberman4111d132021-12-04 18:42:53 -08001113 Py_RETURN_NONE;
1114}
1115
1116static PyObject* PyUpb_CMessage_DiscardUnknownFields(PyUpb_CMessage* self,
1117 PyObject* arg) {
Joshua Haberman54b775d2022-01-05 12:55:52 -08001118 PyUpb_CMessage_EnsureReified(self);
Joshua Haberman4111d132021-12-04 18:42:53 -08001119 const upb_msgdef* msgdef = _PyUpb_CMessage_GetMsgdef(self);
Joshua Haberman6bb891e2021-12-08 15:29:48 -08001120 upb_msg_discardunknown(self->ptr.msg, msgdef, 64);
Joshua Haberman4111d132021-12-04 18:42:53 -08001121 Py_RETURN_NONE;
1122}
1123
1124static PyObject* PyUpb_CMessage_FindInitializationErrors(PyObject* _self,
1125 PyObject* arg) {
Joshua Habermanc42beeb2021-12-06 23:07:14 -08001126 PyUpb_CMessage* self = (void*)_self;
Joshua Haberman58960e02021-12-30 10:50:41 -08001127 upb_msg* msg = PyUpb_CMessage_GetIfReified(_self);
Joshua Haberman4111d132021-12-04 18:42:53 -08001128 if (!msg) return PyList_New(0);
1129 const upb_msgdef* msgdef = _PyUpb_CMessage_GetMsgdef(self);
1130 const upb_symtab* ext_pool = NULL; // TODO
1131 upb_FieldPathEntry* fields;
1132 PyObject* ret = PyList_New(0);
1133 if (upb_util_HasUnsetRequired(msg, msgdef, ext_pool, &fields)) {
1134 char* buf = NULL;
1135 size_t size = 0;
1136 size_t i = 0;
1137 while (fields) {
1138 upb_FieldPathEntry* field = fields;
1139 size_t need = upb_FieldPath_ToText(&fields, buf, size);
1140 if (need >= size) {
1141 fields = field;
Joshua Habermanc42beeb2021-12-06 23:07:14 -08001142 size = size ? size * 2 : 16;
Joshua Haberman4111d132021-12-04 18:42:53 -08001143 while (size <= need) size *= 2;
1144 buf = realloc(buf, size);
1145 need = upb_FieldPath_ToText(&fields, buf, size);
1146 assert(size > need);
1147 }
1148 PyList_SetItem(ret, i, PyUnicode_FromString(buf));
1149 }
1150 free(buf);
1151 }
1152 return ret;
1153}
1154
1155static PyObject* PyUpb_CMessage_FromString(PyObject* cls,
1156 PyObject* serialized) {
Joshua Habermanc42beeb2021-12-06 23:07:14 -08001157 PyObject* ret = NULL;
1158 PyObject* length = NULL;
Joshua Haberman4111d132021-12-04 18:42:53 -08001159
Joshua Habermanc42beeb2021-12-06 23:07:14 -08001160 ret = PyObject_CallObject(cls, NULL);
1161 if (ret == NULL) goto err;
1162 length = PyUpb_CMessage_MergeFromString(ret, serialized);
1163 if (length == NULL) goto err;
Joshua Haberman4111d132021-12-04 18:42:53 -08001164
Joshua Habermanc42beeb2021-12-06 23:07:14 -08001165done:
1166 Py_XDECREF(length);
Joshua Haberman4111d132021-12-04 18:42:53 -08001167 return ret;
Joshua Habermanc42beeb2021-12-06 23:07:14 -08001168
1169err:
1170 Py_XDECREF(ret);
1171 ret = NULL;
1172 goto done;
Joshua Haberman4111d132021-12-04 18:42:53 -08001173}
1174
Joshua Haberman72603462022-01-01 16:08:29 -08001175const upb_fielddef* PyUpb_CMessage_GetExtensionDef(PyObject* _self, PyObject* key) {
1176 const upb_fielddef* f = PyUpb_FieldDescriptor_GetDef(key);
1177 if (!f) {
1178 PyErr_Clear();
1179 PyErr_Format(PyExc_KeyError, "Object %R is not a field descriptor\n", key);
1180 return NULL;
1181 }
1182 if (!upb_fielddef_isextension(f)) {
1183 PyErr_Format(PyExc_KeyError, "Field %s is not an extension\n",
1184 upb_fielddef_fullname(f));
1185 return NULL;
1186 }
1187 const upb_msgdef* msgdef = PyUpb_CMessage_GetMsgdef(_self);
1188 if (upb_fielddef_containingtype(f) != msgdef) {
1189 PyErr_Format(PyExc_KeyError, "Extension doesn't match (%s vs %s)",
1190 upb_msgdef_fullname(msgdef), upb_fielddef_fullname(f));
1191 return NULL;
1192 }
1193 return f;
1194}
1195
1196
Joshua Haberman4111d132021-12-04 18:42:53 -08001197static PyObject* PyUpb_CMessage_HasExtension(PyObject* _self,
1198 PyObject* ext_desc) {
Joshua Haberman58960e02021-12-30 10:50:41 -08001199 upb_msg* msg = PyUpb_CMessage_GetIfReified(_self);
Joshua Haberman72603462022-01-01 16:08:29 -08001200 const upb_fielddef* f = PyUpb_CMessage_GetExtensionDef(_self, ext_desc);
Joshua Haberman4111d132021-12-04 18:42:53 -08001201 if (!f) return NULL;
Joshua Haberman72603462022-01-01 16:08:29 -08001202 if (upb_fielddef_isseq(f)) {
1203 PyErr_SetString(PyExc_KeyError,
1204 "Field is repeated. A singular method is required.");
1205 return NULL;
1206 }
Joshua Haberman4111d132021-12-04 18:42:53 -08001207 if (!msg) Py_RETURN_FALSE;
1208 return PyBool_FromLong(upb_msg_has(msg, f));
1209}
1210
1211PyObject* PyUpb_CMessage_SerializeInternal(PyObject* _self, PyObject* args,
1212 PyObject* kwargs,
1213 bool check_required) {
Joshua Habermanc42beeb2021-12-06 23:07:14 -08001214 PyUpb_CMessage* self = (void*)_self;
Joshua Haberman4111d132021-12-04 18:42:53 -08001215 if (!PyUpb_CMessage_Check((PyObject*)self)) return NULL;
1216 static const char* kwlist[] = {"deterministic", NULL};
1217 int deterministic = 0;
1218 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|p", (char**)(kwlist),
1219 &deterministic)) {
1220 return NULL;
1221 }
1222
Joshua Haberman0549fc02022-01-01 15:42:51 -08001223 if (PyUpb_CMessage_IsStub(self)) {
Joshua Haberman4111d132021-12-04 18:42:53 -08001224 return PyBytes_FromStringAndSize(NULL, 0);
1225 }
1226
1227 upb_arena* arena = upb_arena_new();
1228 const upb_msgdef* msgdef = _PyUpb_CMessage_GetMsgdef(self);
1229 const upb_msglayout* layout = upb_msgdef_layout(msgdef);
1230 size_t size = 0;
Joshua Haberman5b3447e2021-12-31 15:37:23 -08001231 int options = UPB_ENCODE_MAXDEPTH(UINT32_MAX);
Joshua Haberman4111d132021-12-04 18:42:53 -08001232 if (check_required) options |= UPB_ENCODE_CHECKREQUIRED;
1233 if (deterministic) options |= UPB_ENCODE_DETERMINISTIC;
Joshua Haberman14372452021-12-31 12:02:36 -08001234 // Python does not currently have any effective limit on serialization depth.
Joshua Haberman6bb891e2021-12-08 15:29:48 -08001235 char* pb = upb_encode_ex(self->ptr.msg, layout, options, arena, &size);
Joshua Haberman4111d132021-12-04 18:42:53 -08001236 PyObject* ret = NULL;
1237
1238 if (!pb) {
1239 PyUpb_ModuleState* state = PyUpb_ModuleState_Get();
1240 PyErr_Format(state->encode_error_class, "Failed to serialize proto");
1241 goto done;
1242 }
1243
1244 ret = PyBytes_FromStringAndSize(pb, size);
1245
1246done:
1247 upb_arena_free(arena);
1248 return ret;
1249}
1250
1251PyObject* PyUpb_CMessage_SerializeToString(PyObject* _self, PyObject* args,
1252 PyObject* kwargs) {
1253 return PyUpb_CMessage_SerializeInternal(_self, args, kwargs, true);
1254}
1255
1256PyObject* PyUpb_CMessage_SerializePartialToString(PyObject* _self,
1257 PyObject* args,
1258 PyObject* kwargs) {
1259 return PyUpb_CMessage_SerializeInternal(_self, args, kwargs, false);
1260}
1261
1262static PyObject* PyUpb_CMessage_WhichOneof(PyObject* _self, PyObject* name) {
Joshua Habermanc42beeb2021-12-06 23:07:14 -08001263 PyUpb_CMessage* self = (void*)_self;
Joshua Haberman4111d132021-12-04 18:42:53 -08001264 const upb_oneofdef* o;
1265 if (!PyUpb_CMessage_LookupName(self, name, NULL, &o, PyExc_ValueError)) {
1266 return NULL;
1267 }
Joshua Haberman58960e02021-12-30 10:50:41 -08001268 upb_msg* msg = PyUpb_CMessage_GetIfReified(_self);
Joshua Haberman4111d132021-12-04 18:42:53 -08001269 if (!msg) Py_RETURN_NONE;
1270 const upb_fielddef* f = upb_msg_whichoneof(msg, o);
1271 if (!f) Py_RETURN_NONE;
1272 return PyUnicode_FromString(upb_fielddef_name(f));
1273}
1274
1275void PyUpb_CMessage_ClearExtensionDict(PyObject* _self) {
Joshua Habermanc42beeb2021-12-06 23:07:14 -08001276 PyUpb_CMessage* self = (void*)_self;
Joshua Haberman4111d132021-12-04 18:42:53 -08001277 assert(self->ext_dict);
1278 self->ext_dict = NULL;
1279}
1280
1281static PyObject* PyUpb_CMessage_GetExtensionDict(PyObject* _self,
1282 void* closure) {
Joshua Habermanc42beeb2021-12-06 23:07:14 -08001283 PyUpb_CMessage* self = (void*)_self;
Joshua Haberman4111d132021-12-04 18:42:53 -08001284 if (self->ext_dict) {
1285 return self->ext_dict;
1286 }
1287
1288 const upb_msgdef* m = _PyUpb_CMessage_GetMsgdef(self);
1289 if (upb_msgdef_extrangecount(m) == 0) {
1290 PyErr_SetNone(PyExc_AttributeError);
1291 return NULL;
1292 }
1293
Joshua Haberman627c44b2021-12-30 17:47:12 -08001294 self->ext_dict = PyUpb_ExtensionDict_New(_self);
1295 return self->ext_dict;
Joshua Haberman4111d132021-12-04 18:42:53 -08001296}
1297
1298static PyGetSetDef PyUpb_CMessage_Getters[] = {
1299 {"Extensions", PyUpb_CMessage_GetExtensionDict, NULL, "Extension dict"},
Joshua Haberman4111d132021-12-04 18:42:53 -08001300 {NULL}};
1301
1302static PyMethodDef PyUpb_CMessage_Methods[] = {
Joshua Habermaneb38a2a2021-12-05 23:54:34 -08001303 // TODO(https://github.com/protocolbuffers/upb/issues/459)
Joshua Haberman4111d132021-12-04 18:42:53 -08001304 //{ "__deepcopy__", (PyCFunction)DeepCopy, METH_VARARGS,
1305 // "Makes a deep copy of the class." },
1306 //{ "__unicode__", (PyCFunction)ToUnicode, METH_NOARGS,
1307 // "Outputs a unicode representation of the message." },
1308 {"ByteSize", (PyCFunction)PyUpb_CMessage_ByteSize, METH_NOARGS,
1309 "Returns the size of the message in bytes."},
1310 {"Clear", (PyCFunction)PyUpb_CMessage_Clear, METH_NOARGS,
1311 "Clears the message."},
Joshua Haberman0549fc02022-01-01 15:42:51 -08001312 {"ClearExtension", PyUpb_CMessage_ClearExtension, METH_O,
Joshua Haberman4111d132021-12-04 18:42:53 -08001313 "Clears a message field."},
Joshua Haberman0549fc02022-01-01 15:42:51 -08001314 {"ClearField", PyUpb_CMessage_ClearField, METH_O,
Joshua Haberman4111d132021-12-04 18:42:53 -08001315 "Clears a message field."},
Joshua Habermaneb38a2a2021-12-05 23:54:34 -08001316 // TODO(https://github.com/protocolbuffers/upb/issues/459)
Joshua Haberman4111d132021-12-04 18:42:53 -08001317 //{ "CopyFrom", (PyCFunction)CopyFrom, METH_O,
1318 // "Copies a protocol message into the current message." },
1319 {"DiscardUnknownFields", (PyCFunction)PyUpb_CMessage_DiscardUnknownFields,
1320 METH_NOARGS, "Discards the unknown fields."},
1321 {"FindInitializationErrors",
1322 (PyCFunction)PyUpb_CMessage_FindInitializationErrors, METH_NOARGS,
1323 "Finds unset required fields."},
1324 {"FromString", PyUpb_CMessage_FromString, METH_O | METH_CLASS,
1325 "Creates new method instance from given serialized data."},
1326 {"HasExtension", PyUpb_CMessage_HasExtension, METH_O,
1327 "Checks if a message field is set."},
1328 {"HasField", PyUpb_CMessage_HasField, METH_O,
1329 "Checks if a message field is set."},
Joshua Habermaneb38a2a2021-12-05 23:54:34 -08001330 // TODO(https://github.com/protocolbuffers/upb/issues/459)
Joshua Haberman4111d132021-12-04 18:42:53 -08001331 //{ "IsInitialized", (PyCFunction)IsInitialized, METH_VARARGS,
1332 // "Checks if all required fields of a protocol message are set." },
1333 {"ListFields", PyUpb_CMessage_ListFields, METH_NOARGS,
1334 "Lists all set fields of a message."},
1335 {"MergeFrom", PyUpb_CMessage_MergeFrom, METH_O,
1336 "Merges a protocol message into the current message."},
1337 {"MergeFromString", PyUpb_CMessage_MergeFromString, METH_O,
1338 "Merges a serialized message into the current message."},
1339 {"ParseFromString", PyUpb_CMessage_ParseFromString, METH_O,
1340 "Parses a serialized message into the current message."},
Joshua Habermaneb38a2a2021-12-05 23:54:34 -08001341 // TODO(https://github.com/protocolbuffers/upb/issues/459)
Joshua Haberman4111d132021-12-04 18:42:53 -08001342 //{ "RegisterExtension", (PyCFunction)RegisterExtension, METH_O |
1343 // METH_CLASS,
1344 // "Registers an extension with the current message." },
1345 {"SerializePartialToString",
1346 (PyCFunction)PyUpb_CMessage_SerializePartialToString,
1347 METH_VARARGS | METH_KEYWORDS,
1348 "Serializes the message to a string, even if it isn't initialized."},
1349 {"SerializeToString", (PyCFunction)PyUpb_CMessage_SerializeToString,
1350 METH_VARARGS | METH_KEYWORDS,
1351 "Serializes the message to a string, only for initialized messages."},
1352 {"SetInParent", (PyCFunction)PyUpb_CMessage_SetInParent, METH_NOARGS,
1353 "Sets the has bit of the given field in its parent message."},
1354 {"UnknownFields", (PyCFunction)PyUpb_CMessage_UnknownFields, METH_NOARGS,
1355 "Parse unknown field set"},
1356 {"WhichOneof", PyUpb_CMessage_WhichOneof, METH_O,
1357 "Returns the name of the field set inside a oneof, "
1358 "or None if no field is set."},
Joshua Habermaneb38a2a2021-12-05 23:54:34 -08001359 // TODO(https://github.com/protocolbuffers/upb/issues/459)
Joshua Haberman4111d132021-12-04 18:42:53 -08001360 //{ "_CheckCalledFromGeneratedFile",
1361 //(PyCFunction)_CheckCalledFromGeneratedFile,
1362 // METH_NOARGS | METH_STATIC,
1363 // "Raises TypeError if the caller is not in a _pb2.py file."},
1364 {NULL, NULL}};
1365
1366static PyType_Slot PyUpb_CMessage_Slots[] = {
1367 {Py_tp_dealloc, PyUpb_CMessage_Dealloc},
1368 {Py_tp_doc, "A ProtocolMessage"},
1369 {Py_tp_getattro, PyUpb_CMessage_GetAttr},
1370 {Py_tp_getset, PyUpb_CMessage_Getters},
1371 {Py_tp_hash, PyObject_HashNotImplemented},
1372 {Py_tp_methods, PyUpb_CMessage_Methods},
1373 {Py_tp_new, PyUpb_CMessage_New},
1374 {Py_tp_str, PyUpb_CMessage_ToString},
1375 {Py_tp_repr, PyUpb_CMessage_ToString},
1376 {Py_tp_richcompare, PyUpb_CMessage_RichCompare},
1377 {Py_tp_setattro, PyUpb_CMessage_SetAttr},
1378 {Py_tp_init, PyUpb_CMessage_Init},
1379 {0, NULL}};
1380
1381PyType_Spec PyUpb_CMessage_Spec = {
1382 PYUPB_MODULE_NAME ".CMessage", // tp_name
1383 sizeof(PyUpb_CMessage), // tp_basicsize
1384 0, // tp_itemsize
1385 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, // tp_flags
1386 PyUpb_CMessage_Slots,
1387};
1388
1389// -----------------------------------------------------------------------------
1390// MessageMeta
1391// -----------------------------------------------------------------------------
1392
Joshua Habermaneb38a2a2021-12-05 23:54:34 -08001393// MessageMeta is the metaclass for message objects. The generated code uses it
1394// to construct message classes, ie.
1395//
1396// FooMessage = _message.MessageMeta('FooMessage', (_message.Message), {...})
1397//
1398// (This is not quite true: at the moment the Python library subclasses
1399// MessageMeta, and uses that subclass as the metaclass. There is a TODO below
1400// to simplify this, so that the illustration above is indeed accurate).
1401
Joshua Haberman4111d132021-12-04 18:42:53 -08001402typedef struct {
1403 const upb_msglayout* layout;
1404 PyObject* py_message_descriptor;
1405} PyUpb_MessageMeta;
1406
Joshua Habermaneb38a2a2021-12-05 23:54:34 -08001407// The PyUpb_MessageMeta struct is trailing data tacked onto the end of
1408// MessageMeta instances. This means that we get our instances of this struct
1409// by adding the appropriate number of bytes.
1410static PyUpb_MessageMeta* PyUpb_GetMessageMeta(PyObject* cls) {
Joshua Haberman4111d132021-12-04 18:42:53 -08001411#ifndef NDEBUG
1412 PyUpb_ModuleState* state = PyUpb_ModuleState_MaybeGet();
1413 assert(!state || cls->ob_type == state->message_meta_type);
1414#endif
1415 return (PyUpb_MessageMeta*)((char*)cls + cpython_bits.type_basicsize);
1416}
1417
Joshua Habermaneb38a2a2021-12-05 23:54:34 -08001418static const upb_msgdef* PyUpb_MessageMeta_GetMsgdef(PyObject* cls) {
1419 PyUpb_MessageMeta* self = PyUpb_GetMessageMeta(cls);
1420 return PyUpb_Descriptor_GetDef(self->py_message_descriptor);
1421}
1422
Joshua Haberman4111d132021-12-04 18:42:53 -08001423PyObject* PyUpb_MessageMeta_DoCreateClass(PyObject* py_descriptor,
1424 const char* name, PyObject* dict) {
1425 PyUpb_ModuleState* state = PyUpb_ModuleState_Get();
1426 PyTypeObject* descriptor_type = state->descriptor_types[kPyUpb_Descriptor];
1427 if (!PyObject_TypeCheck(py_descriptor, descriptor_type)) {
1428 return PyErr_Format(PyExc_TypeError, "Expected a message Descriptor");
1429 }
1430
1431 const upb_msgdef* msgdef = PyUpb_Descriptor_GetDef(py_descriptor);
1432 assert(msgdef);
1433 assert(!PyUpb_ObjCache_Get(upb_msgdef_layout(msgdef)));
1434
1435 PyObject* slots = PyTuple_New(0);
1436 if (PyDict_SetItemString(dict, "__slots__", slots) < 0) {
1437 return NULL;
1438 }
1439
1440 // Bases are either:
1441 // (CMessage, Message) # for regular messages
1442 // (CMessage, Message, WktBase) # For well-known types
1443 PyObject* wkt_bases = PyUpb_GetWktBases(state);
1444 PyObject* wkt_base =
1445 PyDict_GetItemString(wkt_bases, upb_msgdef_fullname(msgdef));
1446 PyObject* args;
1447 if (wkt_base == NULL) {
1448 args = Py_BuildValue("s(OO)O", name, state->cmessage_type,
1449 state->message_class, dict);
1450 } else {
1451 args = Py_BuildValue("s(OOO)O", name, state->cmessage_type,
1452 state->message_class, wkt_base, dict);
1453 }
1454
1455 PyObject* ret = cpython_bits.type_new(state->message_meta_type, args, NULL);
Joshua Haberman4111d132021-12-04 18:42:53 -08001456 Py_DECREF(args);
1457 if (!ret) return NULL;
1458
1459 PyUpb_MessageMeta* meta = PyUpb_GetMessageMeta(ret);
1460 meta->py_message_descriptor = py_descriptor;
1461 meta->layout = upb_msgdef_layout(msgdef);
1462 Py_INCREF(meta->py_message_descriptor);
1463
1464 PyUpb_ObjCache_Add(upb_msgdef_layout(msgdef), ret);
1465
1466 return ret;
1467}
1468
1469static PyObject* PyUpb_MessageMeta_New(PyTypeObject* type, PyObject* args,
1470 PyObject* kwargs) {
1471 PyUpb_ModuleState* state = PyUpb_ModuleState_Get();
1472 static const char* kwlist[] = {"name", "bases", "dict", 0};
1473 PyObject *bases, *dict;
1474 const char* name;
1475
1476 // Check arguments: (name, bases, dict)
1477 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO!O!:type", (char**)kwlist,
1478 &name, &PyTuple_Type, &bases, &PyDict_Type,
1479 &dict)) {
1480 return NULL;
1481 }
1482
1483 // Check bases: only (), or (message.Message,) are allowed
1484 Py_ssize_t size = PyTuple_Size(bases);
1485 if (!(size == 0 ||
1486 (size == 1 && PyTuple_GetItem(bases, 0) == state->message_class))) {
Joshua Haberman4423e912021-12-27 18:04:58 -08001487 PyErr_Format(PyExc_TypeError,
1488 "A Message class can only inherit from Message, not %S",
1489 bases);
Joshua Haberman4111d132021-12-04 18:42:53 -08001490 return NULL;
1491 }
1492
1493 // Check dict['DESCRIPTOR']
1494 PyObject* py_descriptor = PyDict_GetItemString(dict, "DESCRIPTOR");
1495 if (py_descriptor == NULL) {
1496 PyErr_SetString(PyExc_TypeError, "Message class has no DESCRIPTOR");
1497 return NULL;
1498 }
1499
1500 const upb_msgdef* m = PyUpb_Descriptor_GetDef(py_descriptor);
1501 PyObject* ret = PyUpb_ObjCache_Get(upb_msgdef_layout(m));
1502 if (ret) return ret;
1503 return PyUpb_MessageMeta_DoCreateClass(py_descriptor, name, dict);
1504}
1505
1506static void PyUpb_MessageMeta_Dealloc(PyObject* self) {
1507 PyUpb_MessageMeta* meta = PyUpb_GetMessageMeta(self);
1508 PyUpb_ObjCache_Delete(meta->layout);
1509 Py_DECREF(meta->py_message_descriptor);
1510 PyUpb_Dealloc(self);
1511}
1512
Joshua Haberman4111d132021-12-04 18:42:53 -08001513static PyObject* PyUpb_MessageMeta_GetDynamicAttr(PyObject* self,
1514 PyObject* name) {
1515 const char* name_buf = PyUpb_GetStrData(name);
1516 const upb_msgdef* msgdef = PyUpb_MessageMeta_GetMsgdef(self);
1517 const upb_filedef* filedef = upb_msgdef_file(msgdef);
1518 const upb_symtab* symtab = upb_filedef_symtab(filedef);
1519
1520 PyObject* py_key =
1521 PyBytes_FromFormat("%s.%s", upb_msgdef_fullname(msgdef), name_buf);
1522 const char* key = PyUpb_GetStrData(py_key);
1523 PyObject* ret = NULL;
1524 const upb_msgdef* nested = upb_symtab_lookupmsg(symtab, key);
1525 const upb_enumdef* enumdef;
1526 const upb_enumvaldef* enumval;
1527 const upb_fielddef* ext;
1528
1529 if (nested) {
1530 ret = PyUpb_Descriptor_GetClass(nested);
1531 } else if ((enumdef = upb_symtab_lookupenum(symtab, key))) {
1532 PyUpb_ModuleState* state = PyUpb_ModuleState_Get();
1533 PyObject* klass = state->enum_type_wrapper_class;
1534 ret = PyUpb_EnumDescriptor_Get(enumdef);
1535 ret = PyObject_CallFunctionObjArgs(klass, ret, NULL);
1536 } else if ((enumval = upb_symtab_lookupenumval(symtab, key))) {
1537 ret = PyLong_FromLong(upb_enumvaldef_number(enumval));
1538 } else if ((ext = upb_symtab_lookupext(symtab, key))) {
1539 ret = PyUpb_FieldDescriptor_Get(ext);
1540 }
1541
Joshua Habermaneb38a2a2021-12-05 23:54:34 -08001542 // TODO(haberman): *_FIELD_NUMBER attributes? Haven't seen any failing
1543 // tests for these yet.
1544
Joshua Haberman4111d132021-12-04 18:42:53 -08001545 Py_DECREF(py_key);
1546
1547 return ret;
1548}
1549
1550static PyObject* PyUpb_MessageMeta_GetAttr(PyObject* self, PyObject* name) {
1551 // We want to first delegate to the type's tp_dict to retrieve any attributes
1552 // that were previously calculated and cached in the type's dict.
1553 PyObject* ret = cpython_bits.type_getattro(self, name);
1554 if (ret) return ret;
1555
1556 // We did not find a cached attribute. Try to calculate the attribute
1557 // dynamically, using the descriptor as an argument.
1558 PyErr_Clear();
1559 ret = PyUpb_MessageMeta_GetDynamicAttr(self, name);
1560
1561 if (ret) {
1562 PyObject_SetAttr(self, name, ret);
1563 PyErr_Clear();
1564 return ret;
1565 }
1566
1567 PyErr_SetObject(PyExc_AttributeError, name);
1568 return NULL;
1569}
1570
1571static PyType_Slot PyUpb_MessageMeta_Slots[] = {
1572 {Py_tp_new, PyUpb_MessageMeta_New},
1573 {Py_tp_dealloc, PyUpb_MessageMeta_Dealloc},
1574 {Py_tp_getattro, PyUpb_MessageMeta_GetAttr},
1575 {0, NULL}};
1576
1577static PyType_Spec PyUpb_MessageMeta_Spec = {
1578 PYUPB_MODULE_NAME ".MessageMeta", // tp_name
1579 0, // To be filled in by size of base // tp_basicsize
1580 0, // tp_itemsize
1581 // TODO(haberman): remove BASETYPE, Python should just use MessageMeta
1582 // directly instead of subclassing it.
1583 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, // tp_flags
1584 PyUpb_MessageMeta_Slots,
1585};
1586
Joshua Habermane079f1b2021-12-18 22:10:46 -08001587static PyObject* PyUpb_MessageMeta_CreateType(void) {
Joshua Haberman4111d132021-12-04 18:42:53 -08001588 PyObject* bases = Py_BuildValue("(O)", &PyType_Type);
Joshua Habermaneb38a2a2021-12-05 23:54:34 -08001589 if (!bases) return NULL;
Joshua Haberman4111d132021-12-04 18:42:53 -08001590 PyUpb_MessageMeta_Spec.basicsize =
1591 cpython_bits.type_basicsize + sizeof(PyUpb_MessageMeta);
1592 PyObject* type = PyType_FromSpecWithBases(&PyUpb_MessageMeta_Spec, bases);
1593 Py_DECREF(bases);
Joshua Habermaneb38a2a2021-12-05 23:54:34 -08001594 return type;
1595}
Joshua Haberman4111d132021-12-04 18:42:53 -08001596
Joshua Habermaneb38a2a2021-12-05 23:54:34 -08001597bool PyUpb_InitMessage(PyObject* m) {
1598 if (!PyUpb_CPythonBits_Init(&cpython_bits)) return false;
1599 PyObject* message_meta_type = PyUpb_MessageMeta_CreateType();
Joshua Haberman4111d132021-12-04 18:42:53 -08001600
Joshua Habermaneb38a2a2021-12-05 23:54:34 -08001601 PyUpb_ModuleState* state = PyUpb_ModuleState_GetFromModule(m);
1602 state->cmessage_type = PyUpb_AddClass(m, &PyUpb_CMessage_Spec);
1603 state->message_meta_type = (PyTypeObject*)message_meta_type;
1604
1605 if (!state->cmessage_type || !state->message_meta_type) return false;
1606 if (PyModule_AddObject(m, "MessageMeta", message_meta_type)) return false;
1607
Joshua Haberman4423e912021-12-27 18:04:58 -08001608 PyObject* mod = PyImport_ImportModule("google.protobuf.message");
1609
1610 if (mod == NULL) return false;
1611
1612 state->encode_error_class = PyObject_GetAttrString(mod, "EncodeError");
1613 state->decode_error_class = PyObject_GetAttrString(mod, "DecodeError");
1614 state->message_class = PyObject_GetAttrString(mod, "Message");
1615 Py_DECREF(mod);
1616
1617 if (!state->encode_error_class || !state->decode_error_class ||
1618 !state->message_class) {
1619 return false;
1620 }
1621
Joshua Habermaneb38a2a2021-12-05 23:54:34 -08001622 return true;
Joshua Haberman4111d132021-12-04 18:42:53 -08001623}