Blender V5.0
bmesh_py_ops.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2012 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
11
12#include <Python.h>
13
14#include "BLI_dynstr.h"
15
16#include "MEM_guardedalloc.h"
17
18#include "bmesh.hh"
19
20#include "bmesh_py_ops.hh" /* own include */
21#include "bmesh_py_ops_call.hh"
22
23/* bmesh operator 'bmesh.ops.*' callable types
24 * ******************************************* */
25
27{
28 return PyUnicode_FromFormat("<%.200s bmesh.ops.%.200s()>", Py_TYPE(self)->tp_name, self->opname);
29}
30
31/* methods
32 * ======= */
33
34/* __doc__
35 * ------- */
36
37static char *bmp_slots_as_args(const BMOSlotType slot_types[BMO_OP_MAX_SLOTS], const bool is_out)
38{
39 DynStr *dyn_str = BLI_dynstr_new();
40 char *ret;
41 bool quoted;
42 bool set;
43
44 int i = 0;
45
46 while (*slot_types[i].name) {
47 quoted = false;
48 set = false;
49 /* Cut off `.out` by using a string size argument. */
50 const int name_len = is_out ? (strchr(slot_types[i].name, '.') - slot_types[i].name) :
51 sizeof(slot_types[i].name);
52 const char *value = "<Unknown>";
53 switch (slot_types[i].type) {
55 value = "False";
56 break;
57 case BMO_OP_SLOT_INT:
58 if (slot_types[i].subtype.intg == BMO_OP_SLOT_SUBTYPE_INT_ENUM) {
59 value = slot_types[i].enum_flags[0].identifier;
60 quoted = true;
61 }
62 else if (slot_types[i].subtype.intg == BMO_OP_SLOT_SUBTYPE_INT_FLAG) {
63 value = "";
64 set = true;
65 }
66 else {
67 value = "0";
68 }
69 break;
70 case BMO_OP_SLOT_FLT:
71 value = "0.0";
72 break;
73 case BMO_OP_SLOT_PTR:
74 value = "None";
75 break;
76 case BMO_OP_SLOT_MAT:
77 value = "Matrix()";
78 break;
79 case BMO_OP_SLOT_VEC:
80 value = "Vector()";
81 break;
83 value = (slot_types[i].subtype.elem & BMO_OP_SLOT_SUBTYPE_ELEM_IS_SINGLE) ? "None" : "[]";
84 break;
86 value = "{}";
87 break;
88 }
89 BLI_dynstr_appendf(dyn_str,
90 i ? ", %.*s=%s%s%s%s%s" : "%.*s=%s%s%s%s%s",
91 name_len,
92 slot_types[i].name,
93 set ? "{" : "",
94 quoted ? "'" : "",
95 value,
96 quoted ? "'" : "",
97 set ? "}" : "");
98 i++;
99 }
100
101 ret = BLI_dynstr_get_cstring(dyn_str);
102 BLI_dynstr_free(dyn_str);
103 return ret;
104}
105
106static PyObject *bpy_bmesh_op_doc_get(BPy_BMeshOpFunc *self, void * /*closure*/)
107{
108 PyObject *ret;
109 char *slot_in;
110 char *slot_out;
111 int i;
112
113 i = BMO_opcode_from_opname(self->opname);
114
115 slot_in = bmp_slots_as_args(bmo_opdefines[i]->slot_types_in, false);
116 slot_out = bmp_slots_as_args(bmo_opdefines[i]->slot_types_out, true);
117
118 ret = PyUnicode_FromFormat("%.200s bmesh.ops.%.200s(bmesh, %s)\n -> dict(%s)",
119 Py_TYPE(self)->tp_name,
120 self->opname,
121 slot_in,
122 slot_out);
123
124 MEM_freeN(slot_in);
125 MEM_freeN(slot_out);
126
127 return ret;
128}
129
130static PyGetSetDef bpy_bmesh_op_getseters[] = {
131 {"__doc__", (getter)bpy_bmesh_op_doc_get, (setter) nullptr, nullptr, nullptr},
132 {nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
133};
134
135/* Types
136 * ===== */
137
138static PyTypeObject bmesh_op_Type = {
139 /*ob_base*/ PyVarObject_HEAD_INIT(nullptr, 0)
140 /*tp_name*/ "BMeshOpFunc",
141 /*tp_basicsize*/ sizeof(BPy_BMeshOpFunc),
142 /*tp_itemsize*/ 0,
143 /*tp_dealloc*/ nullptr,
144 /*tp_vectorcall_offset*/ 0,
145 /*tp_getattr*/ nullptr,
146 /*tp_setattr*/ nullptr,
147 /*tp_as_async*/ nullptr,
148 /*tp_repr*/ (reprfunc)bpy_bmesh_op_repr,
149 /*tp_as_number*/ nullptr,
150 /*tp_as_sequence*/ nullptr,
151 /*tp_as_mapping*/ nullptr,
152 /*tp_hash*/ nullptr,
153 /*tp_call*/ (ternaryfunc)BPy_BMO_call,
154 /*tp_str*/ nullptr,
155 /*tp_getattro*/ nullptr,
156 /*tp_setattro*/ nullptr,
157 /*tp_as_buffer*/ nullptr,
158 /*tp_flags*/ Py_TPFLAGS_DEFAULT,
159 /*tp_doc*/ nullptr,
160 /*tp_traverse*/ nullptr,
161 /*tp_clear*/ nullptr,
162 /*tp_richcompare*/ nullptr,
163 /*tp_weaklistoffset*/ 0,
164 /*tp_iter*/ nullptr,
165 /*tp_iternext*/ nullptr,
166 /*tp_methods*/ nullptr,
167 /*tp_members*/ nullptr,
168 /*tp_getset*/ bpy_bmesh_op_getseters,
169 /*tp_base*/ nullptr,
170 /*tp_dict*/ nullptr,
171 /*tp_descr_get*/ nullptr,
172 /*tp_descr_set*/ nullptr,
173 /*tp_dictoffset*/ 0,
174 /*tp_init*/ nullptr,
175 /*tp_alloc*/ nullptr,
176 /*tp_new*/ nullptr,
177 /*tp_free*/ nullptr,
178 /*tp_is_gc*/ nullptr,
179 /*tp_bases*/ nullptr,
180 /*tp_mro*/ nullptr,
181 /*tp_cache*/ nullptr,
182 /*tp_subclasses*/ nullptr,
183 /*tp_weaklist*/ nullptr,
184 /*tp_del*/ nullptr,
185 /*tp_version_tag*/ 0,
186 /*tp_finalize*/ nullptr,
187 /*tp_vectorcall*/ nullptr,
188};
189
190/* bmesh module 'bmesh.ops'
191 * ************************ */
192
193static PyObject *bpy_bmesh_op_CreatePyObject(const char *opname)
194{
196
197 self->opname = opname;
198
199 return (PyObject *)self;
200}
201
202static PyObject *bpy_bmesh_ops_module_getattro(PyObject * /*self*/, PyObject *pyname)
203{
204 const char *opname = PyUnicode_AsUTF8(pyname);
205
206 if (BMO_opcode_from_opname(opname) != -1) {
207 return bpy_bmesh_op_CreatePyObject(opname);
208 }
209
210 PyErr_Format(PyExc_AttributeError, "BMeshOpsModule: operator \"%.200s\" doesn't exist", opname);
211 return nullptr;
212}
213
214static PyObject *bpy_bmesh_ops_module_dir(PyObject * /*self*/)
215{
216 const uint tot = bmo_opdefines_total;
217 uint i;
218 PyObject *ret;
219
220 ret = PyList_New(bmo_opdefines_total);
221
222 for (i = 0; i < tot; i++) {
223 PyList_SET_ITEM(ret, i, PyUnicode_FromString(bmo_opdefines[i]->opname));
224 }
225
226 return ret;
227}
228
229#ifdef __GNUC__
230# ifdef __clang__
231# pragma clang diagnostic push
232# pragma clang diagnostic ignored "-Wcast-function-type"
233# else
234# pragma GCC diagnostic push
235# pragma GCC diagnostic ignored "-Wcast-function-type"
236# endif
237#endif
238
239static PyMethodDef BPy_BM_ops_methods[] = {
240 {"__getattr__", (PyCFunction)bpy_bmesh_ops_module_getattro, METH_O, nullptr},
241 {"__dir__", (PyCFunction)bpy_bmesh_ops_module_dir, METH_NOARGS, nullptr},
242 {nullptr, nullptr, 0, nullptr},
243};
244
245#ifdef __GNUC__
246# ifdef __clang__
247# pragma clang diagnostic pop
248# else
249# pragma GCC diagnostic pop
250# endif
251#endif
252
254 /* Wrap. */
255 BPy_BM_ops_doc,
256 "Access to BMesh operators.");
257static PyModuleDef BPy_BM_ops_module_def = {
258 /*m_base*/ PyModuleDef_HEAD_INIT,
259 /*m_name*/ "bmesh.ops",
260 /*m_doc*/ BPy_BM_ops_doc,
261 /*m_size*/ 0,
262 /*m_methods*/ BPy_BM_ops_methods,
263 /*m_slots*/ nullptr,
264 /*m_traverse*/ nullptr,
265 /*m_clear*/ nullptr,
266 /*m_free*/ nullptr,
267};
268
270{
271 PyObject *submodule = PyModule_Create(&BPy_BM_ops_module_def);
272
273 if (PyType_Ready(&bmesh_op_Type) < 0) {
274 return nullptr;
275 }
276
277 return submodule;
278}
A dynamically sized string ADT.
char * BLI_dynstr_get_cstring(const DynStr *ds) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
DynStr * BLI_dynstr_new(void) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition BLI_dynstr.cc:37
void BLI_dynstr_free(DynStr *ds) ATTR_NONNULL()
void BLI_dynstr_appendf(DynStr *__restrict ds, const char *__restrict format,...) ATTR_PRINTF_FORMAT(2
unsigned int uint
Read Guarded memory(de)allocation.
const int bmo_opdefines_total
const BMOpDefine * bmo_opdefines[]
@ BMO_OP_SLOT_SUBTYPE_ELEM_IS_SINGLE
@ BMO_OP_SLOT_ELEMENT_BUF
@ BMO_OP_SLOT_PTR
@ BMO_OP_SLOT_BOOL
@ BMO_OP_SLOT_FLT
@ BMO_OP_SLOT_INT
@ BMO_OP_SLOT_VEC
@ BMO_OP_SLOT_MAPPING
@ BMO_OP_SLOT_MAT
int BMO_opcode_from_opname(const char *opname)
@ BMO_OP_SLOT_SUBTYPE_INT_FLAG
@ BMO_OP_SLOT_SUBTYPE_INT_ENUM
#define BMO_OP_MAX_SLOTS
static PyObject * bpy_bmesh_ops_module_getattro(PyObject *, PyObject *pyname)
static PyObject * bpy_bmesh_op_repr(BPy_BMeshOpFunc *self)
PyDoc_STRVAR(BPy_BM_ops_doc, "Access to BMesh operators.")
static PyObject * bpy_bmesh_op_CreatePyObject(const char *opname)
static char * bmp_slots_as_args(const BMOSlotType slot_types[BMO_OP_MAX_SLOTS], const bool is_out)
static PyMethodDef BPy_BM_ops_methods[]
static PyModuleDef BPy_BM_ops_module_def
static PyGetSetDef bpy_bmesh_op_getseters[]
static PyObject * bpy_bmesh_ops_module_dir(PyObject *)
PyObject * BPyInit_bmesh_ops()
static PyObject * bpy_bmesh_op_doc_get(BPy_BMeshOpFunc *self, void *)
static PyTypeObject bmesh_op_Type
PyObject * BPy_BMO_call(BPy_BMeshOpFunc *self, PyObject *args, PyObject *kw)
PyObject * self
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
const char * name
return ret
i
Definition text_draw.cc:230