PyAPI: use real module for bpy.types

This is needed to support `typing.get_type_hints`,
which expects each classes module to have a module '__dict__'.
This commit is contained in:
Campbell Barton 2021-02-19 19:08:28 +11:00
parent 80e5697b0b
commit eafcbbb4f7
2 changed files with 53 additions and 71 deletions

View File

@ -90,6 +90,9 @@ BPy_StructRNA *bpy_context_module = NULL; /* for fast access */
static PyObject *pyrna_struct_Subtype(PointerRNA *ptr);
static PyObject *pyrna_prop_collection_values(BPy_PropertyRNA *self);
static PyObject *pyrna_register_class(PyObject *self, PyObject *py_class);
static PyObject *pyrna_unregister_class(PyObject *self, PyObject *py_class);
#define BPY_DOC_ID_PROP_TYPE_NOTE \
" .. note::\n" \
"\n" \
@ -7657,11 +7660,26 @@ PyObject *BPY_rna_doc(void)
}
#endif
/* pyrna_basetype_* - BPy_BaseTypeRNA is just a BPy_PropertyRNA struct with a different type
* the self->ptr and self->prop are always set to the "structs" collection */
/* ---------------getattr-------------------------------------------- */
static PyObject *pyrna_basetype_getattro(BPy_BaseTypeRNA *self, PyObject *pyname)
/* -------------------------------------------------------------------- */
/** \name RNA Types Module `bpy.types`
* \{ */
/**
* This could be a static variable as we only have one `bpy.types` module,
* it just keeps the data isolated to store in the module it's self.
*
* This data doesn't chance one initialized.
*/
struct BPy_TypesModule_State {
/** `RNA_BlenderRNA`. */
PointerRNA ptr;
/** `RNA_BlenderRNA.structs`, exposed as `bpy.types` */
PropertyRNA *prop;
};
static PyObject *bpy_types_module_getattro(PyObject *self, PyObject *pyname)
{
struct BPy_TypesModule_State *state = PyModule_GetState(self);
PointerRNA newptr;
PyObject *ret;
const char *name = PyUnicode_AsUTF8(pyname);
@ -7670,7 +7688,7 @@ static PyObject *pyrna_basetype_getattro(BPy_BaseTypeRNA *self, PyObject *pyname
PyErr_SetString(PyExc_AttributeError, "bpy.types: __getattr__ must be a string");
ret = NULL;
}
else if (RNA_property_collection_lookup_string(&self->ptr, self->prop, name, &newptr)) {
else if (RNA_property_collection_lookup_string(&state->ptr, state->prop, name, &newptr)) {
ret = pyrna_struct_Subtype(&newptr);
if (ret == NULL) {
PyErr_Format(PyExc_RuntimeError,
@ -7692,79 +7710,52 @@ static PyObject *pyrna_basetype_getattro(BPy_BaseTypeRNA *self, PyObject *pyname
return ret;
}
static PyObject *pyrna_basetype_dir(BPy_BaseTypeRNA *self);
static PyObject *pyrna_register_class(PyObject *self, PyObject *py_class);
static PyObject *pyrna_unregister_class(PyObject *self, PyObject *py_class);
static struct PyMethodDef pyrna_basetype_methods[] = {
{"__dir__", (PyCFunction)pyrna_basetype_dir, METH_NOARGS, ""},
{NULL, NULL, 0, NULL},
};
/* Used to call ..._keys() direct, but we need to filter out operator subclasses. */
#if 0
static PyObject *pyrna_basetype_dir(BPy_BaseTypeRNA *self)
{
PyObject *list;
# if 0
PyMethodDef *meth;
# endif
list = pyrna_prop_collection_keys(self); /* Like calling structs.keys(), avoids looping here. */
# if 0 /* For now only contains __dir__. */
for (meth = pyrna_basetype_methods; meth->ml_name; meth++) {
PyList_APPEND(list, PyUnicode_FromString(meth->ml_name));
}
# endif
return list;
}
#else
static PyObject *pyrna_basetype_dir(BPy_BaseTypeRNA *self)
static PyObject *bpy_types_module_dir(PyObject *self)
{
struct BPy_TypesModule_State *state = PyModule_GetState(self);
PyObject *ret = PyList_New(0);
RNA_PROP_BEGIN (&self->ptr, itemptr, self->prop) {
RNA_PROP_BEGIN (&state->ptr, itemptr, state->prop) {
StructRNA *srna = itemptr.data;
PyList_APPEND(ret, PyUnicode_FromString(RNA_struct_identifier(srna)));
}
RNA_PROP_END;
return ret;
}
#endif
static struct PyMethodDef bpy_types_module_methods[] = {
{"__getattr__", (PyCFunction)bpy_types_module_getattro, METH_O, NULL},
{"__dir__", (PyCFunction)bpy_types_module_dir, METH_NOARGS, NULL},
{NULL, NULL, 0, NULL},
};
static PyTypeObject pyrna_basetype_Type = BLANK_PYTHON_TYPE;
PyDoc_STRVAR(bpy_types_module_doc, "Access to internal Blender types");
static struct PyModuleDef bpy_types_module_def = {
PyModuleDef_HEAD_INIT,
"bpy.types", /* m_name */
bpy_types_module_doc, /* m_doc */
sizeof(struct BPy_TypesModule_State), /* m_size */
bpy_types_module_methods, /* m_methods */
NULL, /* m_reload */
NULL, /* m_traverse */
NULL, /* m_clear */
NULL, /* m_free */
};
/**
* Accessed from Python as 'bpy.types'
*/
PyObject *BPY_rna_types(void)
{
BPy_BaseTypeRNA *self;
PyObject *submodule = PyModule_Create(&bpy_types_module_def);
struct BPy_TypesModule_State *state = PyModule_GetState(submodule);
if ((pyrna_basetype_Type.tp_flags & Py_TPFLAGS_READY) == 0) {
pyrna_basetype_Type.tp_name = "RNA_Types";
pyrna_basetype_Type.tp_basicsize = sizeof(BPy_BaseTypeRNA);
pyrna_basetype_Type.tp_getattro = (getattrofunc)pyrna_basetype_getattro;
pyrna_basetype_Type.tp_flags = Py_TPFLAGS_DEFAULT;
pyrna_basetype_Type.tp_methods = pyrna_basetype_methods;
if (PyType_Ready(&pyrna_basetype_Type) < 0) {
return NULL;
}
}
/* Static members for the base class. */
/* Add __name__ since help() expects it. */
PyDict_SetItem(pyrna_basetype_Type.tp_dict, bpy_intern_str___name__, bpy_intern_str_bpy_types);
RNA_blender_rna_pointer_create(&state->ptr);
state->prop = RNA_struct_find_property(&state->ptr, "structs");
/* Internal base types we have no other accessors for. */
{
PyTypeObject *pyrna_types[] = {
static PyTypeObject *pyrna_types[] = {
&pyrna_struct_meta_idprop_Type,
&pyrna_struct_Type,
&pyrna_prop_Type,
@ -7773,23 +7764,17 @@ PyObject *BPY_rna_types(void)
&pyrna_func_Type,
};
PyObject *submodule_dict = PyModule_GetDict(submodule);
for (int i = 0; i < ARRAY_SIZE(pyrna_types); i += 1) {
PyDict_SetItemString(
pyrna_basetype_Type.tp_dict, pyrna_types[i]->tp_name, (PyObject *)pyrna_types[i]);
PyDict_SetItemString(submodule_dict, pyrna_types[i]->tp_name, (PyObject *)pyrna_types[i]);
}
}
self = (BPy_BaseTypeRNA *)PyObject_NEW(BPy_BaseTypeRNA, &pyrna_basetype_Type);
/* Avoid doing this lookup for every getattr. */
RNA_blender_rna_pointer_create(&self->ptr);
self->prop = RNA_struct_find_property(&self->ptr, "structs");
#ifdef USE_WEAKREFS
self->in_weakreflist = NULL;
#endif
return (PyObject *)self;
return submodule;
}
/** \} */
StructRNA *pyrna_struct_as_srna(PyObject *self, const bool parent, const char *error_prefix)
{
BPy_StructRNA *py_srna = NULL;

View File

@ -177,9 +177,6 @@ typedef struct {
FunctionRNA *func;
} BPy_FunctionRNA;
/* cheap trick */
#define BPy_BaseTypeRNA BPy_PropertyRNA
StructRNA *srna_from_self(PyObject *self, const char *error_prefix);
StructRNA *pyrna_struct_as_srna(PyObject *self, const bool parent, const char *error_prefix);