blob: cb79f899583f9d0202f963aed61064bc725531c6 [file] [log] [blame]
// Protocol Buffers - Google's data interchange format
// Copyright 2023 Google LLC. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
#include "python/descriptor_pool.h"
#include "google/protobuf/descriptor.upbdefs.h"
#include "python/convert.h"
#include "python/descriptor.h"
#include "python/message.h"
#include "python/protobuf.h"
#include "upb/base/upcast.h"
#include "upb/message/compare.h"
#include "upb/reflection/def.h"
#include "upb/util/def_to_proto.h"
// -----------------------------------------------------------------------------
// DescriptorPool
// -----------------------------------------------------------------------------
typedef struct {
PyObject_HEAD;
upb_DefPool* symtab;
PyObject* db; // The DescriptorDatabase underlying this pool. May be NULL.
} PyUpb_DescriptorPool;
PyObject* PyUpb_DescriptorPool_GetDefaultPool(void) {
PyUpb_ModuleState* s = PyUpb_ModuleState_Get();
return s->default_pool;
}
const upb_MessageDef* PyUpb_DescriptorPool_GetFileProtoDef(void) {
PyUpb_ModuleState* s = PyUpb_ModuleState_Get();
if (!s->c_descriptor_symtab) {
s->c_descriptor_symtab = upb_DefPool_New();
}
return google_protobuf_FileDescriptorProto_getmsgdef(s->c_descriptor_symtab);
}
static PyObject* PyUpb_DescriptorPool_DoCreateWithCache(
PyTypeObject* type, PyObject* db, PyUpb_WeakMap* obj_cache) {
PyUpb_DescriptorPool* pool = (void*)PyType_GenericAlloc(type, 0);
pool->symtab = upb_DefPool_New();
pool->db = db;
Py_XINCREF(pool->db);
PyUpb_WeakMap_Add(obj_cache, pool->symtab, &pool->ob_base);
return &pool->ob_base;
}
static PyObject* PyUpb_DescriptorPool_DoCreate(PyTypeObject* type,
PyObject* db) {
return PyUpb_DescriptorPool_DoCreateWithCache(type, db,
PyUpb_ObjCache_Instance());
}
upb_DefPool* PyUpb_DescriptorPool_GetSymtab(PyObject* pool) {
return ((PyUpb_DescriptorPool*)pool)->symtab;
}
static int PyUpb_DescriptorPool_Traverse(PyUpb_DescriptorPool* self,
visitproc visit, void* arg) {
Py_VISIT(self->db);
return 0;
}
static int PyUpb_DescriptorPool_Clear(PyUpb_DescriptorPool* self) {
Py_CLEAR(self->db);
return 0;
}
PyObject* PyUpb_DescriptorPool_Get(const upb_DefPool* symtab) {
PyObject* pool = PyUpb_ObjCache_Get(symtab);
assert(pool);
return pool;
}
static void PyUpb_DescriptorPool_Dealloc(PyUpb_DescriptorPool* self) {
PyObject_GC_UnTrack(self);
PyUpb_DescriptorPool_Clear(self);
upb_DefPool_Free(self->symtab);
PyUpb_ObjCache_Delete(self->symtab);
PyUpb_Dealloc(self);
}
/*
* DescriptorPool.__new__()
*
* Implements:
* DescriptorPool(descriptor_db=None)
*/
static PyObject* PyUpb_DescriptorPool_New(PyTypeObject* type, PyObject* args,
PyObject* kwargs) {
char* kwlist[] = {"descriptor_db", 0};
PyObject* db = NULL;
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O", kwlist, &db)) {
return NULL;
}
if (db == Py_None) db = NULL;
return PyUpb_DescriptorPool_DoCreate(type, db);
}
static PyObject* PyUpb_DescriptorPool_DoAdd(PyObject* _self,
PyObject* file_desc);
static bool PyUpb_DescriptorPool_TryLoadFileProto(PyUpb_DescriptorPool* self,
PyObject* proto) {
if (proto == NULL) {
if (PyErr_ExceptionMatches(PyExc_KeyError)) {
// Expected error: item was simply not found.
PyErr_Clear();
return true; // We didn't accomplish our goal, but we didn't error out.
}
return false;
}
if (proto == Py_None) return true;
PyObject* ret = PyUpb_DescriptorPool_DoAdd((PyObject*)self, proto);
bool ok = ret != NULL;
Py_XDECREF(ret);
return ok;
}
static bool PyUpb_DescriptorPool_TryLoadSymbol(PyUpb_DescriptorPool* self,
PyObject* sym) {
if (!self->db) return false;
PyObject* file_proto =
PyObject_CallMethod(self->db, "FindFileContainingSymbol", "O", sym);
bool ret = PyUpb_DescriptorPool_TryLoadFileProto(self, file_proto);
Py_XDECREF(file_proto);
return ret;
}
static bool PyUpb_DescriptorPool_TryLoadFilename(PyUpb_DescriptorPool* self,
PyObject* filename) {
if (!self->db) return false;
PyObject* file_proto =
PyObject_CallMethod(self->db, "FindFileByName", "O", filename);
bool ret = PyUpb_DescriptorPool_TryLoadFileProto(self, file_proto);
Py_XDECREF(file_proto);
return ret;
}
bool PyUpb_DescriptorPool_CheckNoDatabase(PyObject* _self) { return true; }
static bool PyUpb_DescriptorPool_LoadDependentFiles(
PyUpb_DescriptorPool* self, google_protobuf_FileDescriptorProto* proto) {
size_t n;
const upb_StringView* deps = google_protobuf_FileDescriptorProto_dependency(proto, &n);
for (size_t i = 0; i < n; i++) {
const upb_FileDef* dep = upb_DefPool_FindFileByNameWithSize(
self->symtab, deps[i].data, deps[i].size);
if (!dep) {
PyObject* filename =
PyUnicode_FromStringAndSize(deps[i].data, deps[i].size);
if (!filename) return false;
bool ok = PyUpb_DescriptorPool_TryLoadFilename(self, filename);
Py_DECREF(filename);
if (!ok) return false;
}
}
return true;
}
static PyObject* PyUpb_DescriptorPool_DoAddSerializedFile(
PyObject* _self, PyObject* serialized_pb) {
PyUpb_DescriptorPool* self = (PyUpb_DescriptorPool*)_self;
upb_Arena* arena = upb_Arena_New();
if (!arena) PYUPB_RETURN_OOM;
PyObject* result = NULL;
char* buf;
Py_ssize_t size;
if (PyBytes_AsStringAndSize(serialized_pb, &buf, &size) < 0) {
goto done;
}
google_protobuf_FileDescriptorProto* proto =
google_protobuf_FileDescriptorProto_parse(buf, size, arena);
if (!proto) {
PyErr_SetString(PyExc_TypeError, "Couldn't parse file content!");
goto done;
}
upb_StringView name = google_protobuf_FileDescriptorProto_name(proto);
const upb_FileDef* file =
upb_DefPool_FindFileByNameWithSize(self->symtab, name.data, name.size);
if (file) {
// If the existing file is equal to the new file, then silently ignore the
// duplicate add.
google_protobuf_FileDescriptorProto* existing = upb_FileDef_ToProto(file, arena);
if (!existing) {
PyErr_SetNone(PyExc_MemoryError);
goto done;
}
const upb_MessageDef* m = PyUpb_DescriptorPool_GetFileProtoDef();
const int options = kUpb_CompareOption_IncludeUnknownFields;
if (upb_Message_IsEqualByDef(UPB_UPCAST(proto), UPB_UPCAST(existing), m,
options)) {
result = PyUpb_FileDescriptor_Get(file);
goto done;
}
}
if (self->db) {
if (!PyUpb_DescriptorPool_LoadDependentFiles(self, proto)) goto done;
}
upb_Status status;
upb_Status_Clear(&status);
const upb_FileDef* filedef =
upb_DefPool_AddFile(self->symtab, proto, &status);
if (!filedef) {
PyErr_Format(PyExc_TypeError,
"Couldn't build proto file into descriptor pool: %s",
upb_Status_ErrorMessage(&status));
goto done;
}
result = PyUpb_FileDescriptor_Get(filedef);
done:
upb_Arena_Free(arena);
return result;
}
static PyObject* PyUpb_DescriptorPool_DoAdd(PyObject* _self,
PyObject* file_desc) {
if (!PyUpb_Message_Verify(file_desc)) return NULL;
const upb_MessageDef* m = PyUpb_Message_GetMsgdef(file_desc);
const char* file_proto_name =
PYUPB_DESCRIPTOR_PROTO_PACKAGE ".FileDescriptorProto";
if (strcmp(upb_MessageDef_FullName(m), file_proto_name) != 0) {
return PyErr_Format(PyExc_TypeError, "Can only add FileDescriptorProto");
}
PyObject* subargs = PyTuple_New(0);
if (!subargs) return NULL;
PyObject* serialized =
PyUpb_Message_SerializeToString(file_desc, subargs, NULL);
Py_DECREF(subargs);
if (!serialized) return NULL;
PyObject* ret = PyUpb_DescriptorPool_DoAddSerializedFile(_self, serialized);
Py_DECREF(serialized);
return ret;
}
/*
* PyUpb_DescriptorPool_AddSerializedFile()
*
* Implements:
* DescriptorPool.AddSerializedFile(self, serialized_file_descriptor)
*
* Adds the given serialized FileDescriptorProto to the pool.
*/
static PyObject* PyUpb_DescriptorPool_AddSerializedFile(
PyObject* _self, PyObject* serialized_pb) {
PyUpb_DescriptorPool* self = (PyUpb_DescriptorPool*)_self;
if (self->db) {
PyErr_SetString(
PyExc_ValueError,
"Cannot call AddSerializedFile on a DescriptorPool that uses a "
"DescriptorDatabase. Add your file to the underlying database.");
return false;
}
return PyUpb_DescriptorPool_DoAddSerializedFile(_self, serialized_pb);
}
static PyObject* PyUpb_DescriptorPool_Add(PyObject* _self,
PyObject* file_desc) {
PyUpb_DescriptorPool* self = (PyUpb_DescriptorPool*)_self;
if (self->db) {
PyErr_SetString(
PyExc_ValueError,
"Cannot call Add on a DescriptorPool that uses a DescriptorDatabase. "
"Add your file to the underlying database.");
return false;
}
return PyUpb_DescriptorPool_DoAdd(_self, file_desc);
}
static PyObject* PyUpb_DescriptorPool_SetFeatureSetDefaults(
PyObject* _self, PyObject* defaults) {
if (!PyUpb_Message_Verify(defaults)) {
return PyErr_Format(PyExc_TypeError,
"SetFeatureSetDefaults called with invalid type");
}
const upb_MessageDef* m = PyUpb_Message_GetMsgdef(defaults);
const char* file_proto_name =
PYUPB_DESCRIPTOR_PROTO_PACKAGE ".FeatureSetDefaults";
if (strcmp(upb_MessageDef_FullName(m), file_proto_name) != 0) {
return PyErr_Format(
PyExc_TypeError,
"SetFeatureSetDefaults called with invalid type: got %s, expected %s",
upb_MessageDef_FullName(m), file_proto_name);
}
PyObject* subargs = PyTuple_New(0);
if (!subargs) return NULL;
PyObject* py_serialized =
PyUpb_Message_SerializeToString(defaults, subargs, NULL);
Py_DECREF(subargs);
if (!py_serialized) return NULL;
char* serialized;
Py_ssize_t size;
if (PyBytes_AsStringAndSize(py_serialized, &serialized, &size) < 0) {
goto err;
}
PyUpb_DescriptorPool* self = (PyUpb_DescriptorPool*)_self;
upb_Status status;
if (!upb_DefPool_SetFeatureSetDefaults(self->symtab, serialized, size,
&status)) {
PyErr_SetString(PyExc_ValueError, upb_Status_ErrorMessage(&status));
goto err;
}
Py_DECREF(py_serialized);
Py_RETURN_NONE;
err:
Py_DECREF(py_serialized);
return NULL;
}
/*
* PyUpb_DescriptorPool_FindFileByName()
*
* Implements:
* DescriptorPool.FindFileByName(self, name)
*/
static PyObject* PyUpb_DescriptorPool_FindFileByName(PyObject* _self,
PyObject* arg) {
PyUpb_DescriptorPool* self = (PyUpb_DescriptorPool*)_self;
const char* name = PyUpb_VerifyStrData(arg);
if (!name) return NULL;
const upb_FileDef* file = upb_DefPool_FindFileByName(self->symtab, name);
if (file == NULL && self->db) {
if (!PyUpb_DescriptorPool_TryLoadFilename(self, arg)) return NULL;
file = upb_DefPool_FindFileByName(self->symtab, name);
}
if (file == NULL) {
return PyErr_Format(PyExc_KeyError, "Couldn't find file %.200s", name);
}
return PyUpb_FileDescriptor_Get(file);
}
/*
* PyUpb_DescriptorPool_FindExtensionByName()
*
* Implements:
* DescriptorPool.FindExtensionByName(self, name)
*/
static PyObject* PyUpb_DescriptorPool_FindExtensionByName(PyObject* _self,
PyObject* arg) {
PyUpb_DescriptorPool* self = (PyUpb_DescriptorPool*)_self;
const char* name = PyUpb_VerifyStrData(arg);
if (!name) return NULL;
const upb_FieldDef* field =
upb_DefPool_FindExtensionByName(self->symtab, name);
if (field == NULL && self->db) {
if (!PyUpb_DescriptorPool_TryLoadSymbol(self, arg)) return NULL;
field = upb_DefPool_FindExtensionByName(self->symtab, name);
}
if (field == NULL) {
return PyErr_Format(PyExc_KeyError, "Couldn't find extension %.200s", name);
}
return PyUpb_FieldDescriptor_Get(field);
}
/*
* PyUpb_DescriptorPool_FindMessageTypeByName()
*
* Implements:
* DescriptorPool.FindMessageTypeByName(self, name)
*/
static PyObject* PyUpb_DescriptorPool_FindMessageTypeByName(PyObject* _self,
PyObject* arg) {
PyUpb_DescriptorPool* self = (PyUpb_DescriptorPool*)_self;
const char* name = PyUpb_VerifyStrData(arg);
if (!name) return NULL;
const upb_MessageDef* m = upb_DefPool_FindMessageByName(self->symtab, name);
if (m == NULL && self->db) {
if (!PyUpb_DescriptorPool_TryLoadSymbol(self, arg)) return NULL;
m = upb_DefPool_FindMessageByName(self->symtab, name);
}
if (m == NULL) {
return PyErr_Format(PyExc_KeyError, "Couldn't find message %.200s", name);
}
return PyUpb_Descriptor_Get(m);
}
// Splits a dotted symbol like foo.bar.baz on the last dot. Returns the portion
// after the last dot (baz) and updates `*parent_size` to the length of the
// parent (foo.bar). Returns NULL if no dots were present.
static const char* PyUpb_DescriptorPool_SplitSymbolName(const char* sym,
size_t* parent_size) {
const char* last_dot = strrchr(sym, '.');
if (!last_dot) return NULL;
*parent_size = last_dot - sym;
return last_dot + 1;
}
/*
* PyUpb_DescriptorPool_FindFieldByName()
*
* Implements:
* DescriptorPool.FindFieldByName(self, name)
*/
static PyObject* PyUpb_DescriptorPool_FindFieldByName(PyObject* _self,
PyObject* arg) {
PyUpb_DescriptorPool* self = (PyUpb_DescriptorPool*)_self;
const char* name = PyUpb_VerifyStrData(arg);
if (!name) return NULL;
size_t parent_size;
const char* child = PyUpb_DescriptorPool_SplitSymbolName(name, &parent_size);
const upb_FieldDef* f = NULL;
if (child) {
const upb_MessageDef* parent =
upb_DefPool_FindMessageByNameWithSize(self->symtab, name, parent_size);
if (parent == NULL && self->db) {
if (!PyUpb_DescriptorPool_TryLoadSymbol(self, arg)) return NULL;
parent = upb_DefPool_FindMessageByNameWithSize(self->symtab, name,
parent_size);
}
if (parent) {
f = upb_MessageDef_FindFieldByName(parent, child);
}
}
if (!f) {
return PyErr_Format(PyExc_KeyError, "Couldn't find message %.200s", name);
}
return PyUpb_FieldDescriptor_Get(f);
}
/*
* PyUpb_DescriptorPool_FindEnumTypeByName()
*
* Implements:
* DescriptorPool.FindEnumTypeByName(self, name)
*/
static PyObject* PyUpb_DescriptorPool_FindEnumTypeByName(PyObject* _self,
PyObject* arg) {
PyUpb_DescriptorPool* self = (PyUpb_DescriptorPool*)_self;
const char* name = PyUpb_VerifyStrData(arg);
if (!name) return NULL;
const upb_EnumDef* e = upb_DefPool_FindEnumByName(self->symtab, name);
if (e == NULL && self->db) {
if (!PyUpb_DescriptorPool_TryLoadSymbol(self, arg)) return NULL;
e = upb_DefPool_FindEnumByName(self->symtab, name);
}
if (e == NULL) {
return PyErr_Format(PyExc_KeyError, "Couldn't find enum %.200s", name);
}
return PyUpb_EnumDescriptor_Get(e);
}
/*
* PyUpb_DescriptorPool_FindOneofByName()
*
* Implements:
* DescriptorPool.FindOneofByName(self, name)
*/
static PyObject* PyUpb_DescriptorPool_FindOneofByName(PyObject* _self,
PyObject* arg) {
PyUpb_DescriptorPool* self = (PyUpb_DescriptorPool*)_self;
const char* name = PyUpb_VerifyStrData(arg);
if (!name) return NULL;
size_t parent_size;
const char* child = PyUpb_DescriptorPool_SplitSymbolName(name, &parent_size);
if (child) {
const upb_MessageDef* parent =
upb_DefPool_FindMessageByNameWithSize(self->symtab, name, parent_size);
if (parent == NULL && self->db) {
if (!PyUpb_DescriptorPool_TryLoadSymbol(self, arg)) return NULL;
parent = upb_DefPool_FindMessageByNameWithSize(self->symtab, name,
parent_size);
}
if (parent) {
const upb_OneofDef* o = upb_MessageDef_FindOneofByName(parent, child);
return PyUpb_OneofDescriptor_Get(o);
}
}
return PyErr_Format(PyExc_KeyError, "Couldn't find oneof %.200s", name);
}
static PyObject* PyUpb_DescriptorPool_FindServiceByName(PyObject* _self,
PyObject* arg) {
PyUpb_DescriptorPool* self = (PyUpb_DescriptorPool*)_self;
const char* name = PyUpb_VerifyStrData(arg);
if (!name) return NULL;
const upb_ServiceDef* s = upb_DefPool_FindServiceByName(self->symtab, name);
if (s == NULL && self->db) {
if (!PyUpb_DescriptorPool_TryLoadSymbol(self, arg)) return NULL;
s = upb_DefPool_FindServiceByName(self->symtab, name);
}
if (s == NULL) {
return PyErr_Format(PyExc_KeyError, "Couldn't find service %.200s", name);
}
return PyUpb_ServiceDescriptor_Get(s);
}
static PyObject* PyUpb_DescriptorPool_FindMethodByName(PyObject* _self,
PyObject* arg) {
PyUpb_DescriptorPool* self = (PyUpb_DescriptorPool*)_self;
const char* name = PyUpb_VerifyStrData(arg);
if (!name) return NULL;
size_t parent_size;
const char* child = PyUpb_DescriptorPool_SplitSymbolName(name, &parent_size);
if (!child) goto err;
const upb_ServiceDef* parent =
upb_DefPool_FindServiceByNameWithSize(self->symtab, name, parent_size);
if (parent == NULL && self->db) {
if (!PyUpb_DescriptorPool_TryLoadSymbol(self, arg)) return NULL;
parent =
upb_DefPool_FindServiceByNameWithSize(self->symtab, name, parent_size);
}
if (!parent) goto err;
const upb_MethodDef* m = upb_ServiceDef_FindMethodByName(parent, child);
if (!m) goto err;
return PyUpb_MethodDescriptor_Get(m);
err:
return PyErr_Format(PyExc_KeyError, "Couldn't find method %.200s", name);
}
static PyObject* PyUpb_DescriptorPool_FindFileContainingSymbol(PyObject* _self,
PyObject* arg) {
PyUpb_DescriptorPool* self = (PyUpb_DescriptorPool*)_self;
const char* name = PyUpb_VerifyStrData(arg);
if (!name) return NULL;
const upb_FileDef* f =
upb_DefPool_FindFileContainingSymbol(self->symtab, name);
if (f == NULL && self->db) {
if (!PyUpb_DescriptorPool_TryLoadSymbol(self, arg)) return NULL;
f = upb_DefPool_FindFileContainingSymbol(self->symtab, name);
}
if (f == NULL) {
return PyErr_Format(PyExc_KeyError, "Couldn't find symbol %.200s", name);
}
return PyUpb_FileDescriptor_Get(f);
}
static PyObject* PyUpb_DescriptorPool_FindExtensionByNumber(PyObject* _self,
PyObject* args) {
PyUpb_DescriptorPool* self = (PyUpb_DescriptorPool*)_self;
PyObject* message_descriptor;
int number;
if (!PyArg_ParseTuple(args, "Oi", &message_descriptor, &number)) {
return NULL;
}
const upb_FieldDef* f = upb_DefPool_FindExtensionByNumber(
self->symtab, PyUpb_Descriptor_GetDef(message_descriptor), number);
if (f == NULL) {
return PyErr_Format(PyExc_KeyError, "Couldn't find Extension %d", number);
}
return PyUpb_FieldDescriptor_Get(f);
}
static PyObject* PyUpb_DescriptorPool_FindAllExtensions(PyObject* _self,
PyObject* msg_desc) {
PyUpb_DescriptorPool* self = (PyUpb_DescriptorPool*)_self;
const upb_MessageDef* m = PyUpb_Descriptor_GetDef(msg_desc);
size_t n;
const upb_FieldDef** ext = upb_DefPool_GetAllExtensions(self->symtab, m, &n);
PyObject* ret = PyList_New(n);
if (!ret) goto done;
for (size_t i = 0; i < n; i++) {
PyObject* field = PyUpb_FieldDescriptor_Get(ext[i]);
if (!field) {
Py_DECREF(ret);
ret = NULL;
goto done;
}
PyList_SetItem(ret, i, field);
}
done:
free(ext);
return ret;
}
static PyMethodDef PyUpb_DescriptorPool_Methods[] = {
{"Add", PyUpb_DescriptorPool_Add, METH_O,
"Adds the FileDescriptorProto and its types to this pool."},
{"AddSerializedFile", PyUpb_DescriptorPool_AddSerializedFile, METH_O,
"Adds a serialized FileDescriptorProto to this pool."},
{"SetFeatureSetDefaults", PyUpb_DescriptorPool_SetFeatureSetDefaults,
METH_O, "Sets the default feature mappings used during the build."},
{"FindFileByName", PyUpb_DescriptorPool_FindFileByName, METH_O,
"Searches for a file descriptor by its .proto name."},
{"FindMessageTypeByName", PyUpb_DescriptorPool_FindMessageTypeByName,
METH_O, "Searches for a message descriptor by full name."},
{"FindFieldByName", PyUpb_DescriptorPool_FindFieldByName, METH_O,
"Searches for a field descriptor by full name."},
{"FindExtensionByName", PyUpb_DescriptorPool_FindExtensionByName, METH_O,
"Searches for extension descriptor by full name."},
{"FindEnumTypeByName", PyUpb_DescriptorPool_FindEnumTypeByName, METH_O,
"Searches for enum type descriptor by full name."},
{"FindOneofByName", PyUpb_DescriptorPool_FindOneofByName, METH_O,
"Searches for oneof descriptor by full name."},
{"FindServiceByName", PyUpb_DescriptorPool_FindServiceByName, METH_O,
"Searches for service descriptor by full name."},
{"FindMethodByName", PyUpb_DescriptorPool_FindMethodByName, METH_O,
"Searches for method descriptor by full name."},
{"FindFileContainingSymbol", PyUpb_DescriptorPool_FindFileContainingSymbol,
METH_O, "Gets the FileDescriptor containing the specified symbol."},
{"FindExtensionByNumber", PyUpb_DescriptorPool_FindExtensionByNumber,
METH_VARARGS, "Gets the extension descriptor for the given number."},
{"FindAllExtensions", PyUpb_DescriptorPool_FindAllExtensions, METH_O,
"Gets all known extensions of the given message descriptor."},
{NULL}};
static PyType_Slot PyUpb_DescriptorPool_Slots[] = {
{Py_tp_clear, PyUpb_DescriptorPool_Clear},
{Py_tp_dealloc, PyUpb_DescriptorPool_Dealloc},
{Py_tp_methods, PyUpb_DescriptorPool_Methods},
{Py_tp_new, PyUpb_DescriptorPool_New},
{Py_tp_traverse, PyUpb_DescriptorPool_Traverse},
{0, NULL}};
static PyType_Spec PyUpb_DescriptorPool_Spec = {
PYUPB_MODULE_NAME ".DescriptorPool",
sizeof(PyUpb_DescriptorPool),
0, // tp_itemsize
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
PyUpb_DescriptorPool_Slots,
};
// -----------------------------------------------------------------------------
// Top Level
// -----------------------------------------------------------------------------
bool PyUpb_InitDescriptorPool(PyObject* m) {
PyUpb_ModuleState* state = PyUpb_ModuleState_GetFromModule(m);
PyTypeObject* descriptor_pool_type =
PyUpb_AddClass(m, &PyUpb_DescriptorPool_Spec);
if (!descriptor_pool_type) return false;
state->default_pool = PyUpb_DescriptorPool_DoCreateWithCache(
descriptor_pool_type, NULL, state->obj_cache);
return state->default_pool &&
PyModule_AddObject(m, "default_pool", state->default_pool) == 0;
}