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