Blender  V3.3
bpy_operator.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
14 #include <Python.h>
15 
16 #include "RNA_types.h"
17 
18 #include "BLI_listbase.h"
19 #include "BLI_utildefines.h"
20 
21 #include "../generic/py_capi_rna.h"
22 #include "../generic/py_capi_utils.h"
23 #include "../generic/python_utildefines.h"
24 #include "BPY_extern.h"
25 #include "bpy_capi_utils.h"
26 #include "bpy_operator.h"
27 #include "bpy_operator_wrap.h"
28 #include "bpy_rna.h" /* for setting argument properties & type method `get_rna_type`. */
29 
30 #include "RNA_access.h"
31 #include "RNA_enum_types.h"
32 #include "RNA_prototypes.h"
33 
34 #include "WM_api.h"
35 #include "WM_types.h"
36 
37 #include "MEM_guardedalloc.h"
38 
39 #include "BLI_ghash.h"
40 
41 #include "BKE_context.h"
42 #include "BKE_report.h"
43 
44 /* so operators called can spawn threads which acquire the GIL */
45 #define BPY_RELEASE_GIL
46 
47 static wmOperatorType *ot_lookup_from_py_string(PyObject *value, const char *py_fn_id)
48 {
49  const char *opname = PyUnicode_AsUTF8(value);
50  if (opname == NULL) {
51  PyErr_Format(PyExc_TypeError, "%s() expects a string argument", py_fn_id);
52  return NULL;
53  }
54 
55  wmOperatorType *ot = WM_operatortype_find(opname, true);
56  if (ot == NULL) {
57  PyErr_Format(PyExc_KeyError, "%s(\"%s\") not found", py_fn_id, opname);
58  return NULL;
59  }
60  return ot;
61 }
62 
63 static void op_context_override_deprecated_warning(const char *action, const char *opname)
64 {
65  if (PyErr_WarnFormat(
66  PyExc_DeprecationWarning,
67  /* Use stack level 2 as this call is wrapped by `release/scripts/modules/bpy/ops.py`,
68  * An extra stack level is needed to show the warning in the authors script. */
69  2,
70  "Passing in context overrides is deprecated in favor of "
71  "Context.temp_override(..), %s \"%s\"",
72  action,
73  opname) < 0) {
74  /* The function has no return value, the exception cannot
75  * be reported to the caller, so just log it. */
76  PyErr_WriteUnraisable(NULL);
77  }
78 }
79 
80 static PyObject *pyop_poll(PyObject *UNUSED(self), PyObject *args)
81 {
83  const char *opname;
84  PyObject *context_dict = NULL; /* optional args */
85  const char *context_str = NULL;
86  PyObject *ret;
87 
89 
90  /* XXX TODO: work out a better solution for passing on context,
91  * could make a tuple from self and pack the name and Context into it. */
93 
94  if (C == NULL) {
95  PyErr_SetString(PyExc_RuntimeError, "Context is None, can't poll any operators");
96  return NULL;
97  }
98 
99  if (!PyArg_ParseTuple(args, "s|Os:_bpy.ops.poll", &opname, &context_dict, &context_str)) {
100  return NULL;
101  }
102 
103  ot = WM_operatortype_find(opname, true);
104 
105  if (ot == NULL) {
106  PyErr_Format(PyExc_AttributeError,
107  "Polling operator \"bpy.ops.%s\" error, "
108  "could not be found",
109  opname);
110  return NULL;
111  }
112 
113  if (context_str) {
114  int context_int = context;
115 
116  if (RNA_enum_value_from_id(rna_enum_operator_context_items, context_str, &context_int) == 0) {
118  PyErr_Format(PyExc_TypeError,
119  "Calling operator \"bpy.ops.%s.poll\" error, "
120  "expected a string enum in (%s)",
121  opname,
122  enum_str);
123  MEM_freeN(enum_str);
124  return NULL;
125  }
126  /* Copy back to the properly typed enum. */
127  context = context_int;
128  }
129 
130  if (ELEM(context_dict, NULL, Py_None)) {
131  context_dict = NULL;
132  }
133  else if (PyDict_Check(context_dict)) {
134  op_context_override_deprecated_warning("polling", opname);
135  }
136  else {
137  PyErr_Format(PyExc_TypeError,
138  "Calling operator \"bpy.ops.%s.poll\" error, "
139  "custom context expected a dict or None, got a %.200s",
140  opname,
141  Py_TYPE(context_dict)->tp_name);
142  return NULL;
143  }
144 
145  struct bContext_PyState context_py_state;
146  if (context_dict != NULL) {
147  CTX_py_state_push(C, &context_py_state, (void *)context_dict);
148  Py_INCREF(context_dict); /* so we don't lose it */
149  }
150 
151  /* main purpose of this function */
152  ret = WM_operator_poll_context((bContext *)C, ot, context) ? Py_True : Py_False;
153 
154  if (context_dict != NULL) {
155  PyObject *context_dict_test = CTX_py_dict_get(C);
156  if (context_dict_test != context_dict) {
157  Py_DECREF(context_dict_test);
158  }
159  /* Restore with original context dict,
160  * probably NULL but need this for nested operator calls. */
161  Py_DECREF(context_dict);
162  CTX_py_state_pop(C, &context_py_state);
163  }
164 
165  return Py_INCREF_RET(ret);
166 }
167 
168 static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args)
169 {
171  int error_val = 0;
172  PointerRNA ptr;
173  int operator_ret = OPERATOR_CANCELLED;
174 
175  const char *opname;
176  const char *context_str = NULL;
177  PyObject *kw = NULL; /* optional args */
178  PyObject *context_dict = NULL; /* optional args */
179 
181  int is_undo = false;
182 
183  /* XXX TODO: work out a better solution for passing on context,
184  * could make a tuple from self and pack the name and Context into it. */
186 
187  if (C == NULL) {
188  PyErr_SetString(PyExc_RuntimeError, "Context is None, can't poll any operators");
189  return NULL;
190  }
191 
192  if (!PyArg_ParseTuple(args,
193  "sO|O!si:_bpy.ops.call",
194  &opname,
195  &context_dict,
196  &PyDict_Type,
197  &kw,
198  &context_str,
199  &is_undo)) {
200  return NULL;
201  }
202 
203  ot = WM_operatortype_find(opname, true);
204 
205  if (ot == NULL) {
206  PyErr_Format(PyExc_AttributeError,
207  "Calling operator \"bpy.ops.%s\" error, "
208  "could not be found",
209  opname);
210  return NULL;
211  }
212 
213  if (!pyrna_write_check()) {
214  PyErr_Format(PyExc_RuntimeError,
215  "Calling operator \"bpy.ops.%s\" error, "
216  "can't modify blend data in this state (drawing/rendering)",
217  opname);
218  return NULL;
219  }
220 
221  if (context_str) {
222  int context_int = context;
223 
224  if (RNA_enum_value_from_id(rna_enum_operator_context_items, context_str, &context_int) == 0) {
226  PyErr_Format(PyExc_TypeError,
227  "Calling operator \"bpy.ops.%s\" error, "
228  "expected a string enum in (%s)",
229  opname,
230  enum_str);
231  MEM_freeN(enum_str);
232  return NULL;
233  }
234  /* Copy back to the properly typed enum. */
235  context = context_int;
236  }
237 
238  if (ELEM(context_dict, NULL, Py_None)) {
239  context_dict = NULL;
240  }
241  else if (PyDict_Check(context_dict)) {
242  op_context_override_deprecated_warning("calling", opname);
243  }
244  else {
245  PyErr_Format(PyExc_TypeError,
246  "Calling operator \"bpy.ops.%s\" error, "
247  "custom context expected a dict or None, got a %.200s",
248  opname,
249  Py_TYPE(context_dict)->tp_name);
250  return NULL;
251  }
252 
258  struct bContext_PyState context_py_state;
259  if (context_dict != NULL) {
260  CTX_py_state_push(C, &context_py_state, (void *)context_dict);
261  Py_INCREF(context_dict); /* so we don't lose it */
262  }
263 
264  if (WM_operator_poll_context((bContext *)C, ot, context) == false) {
265  bool msg_free = false;
266  const char *msg = CTX_wm_operator_poll_msg_get(C, &msg_free);
267  PyErr_Format(PyExc_RuntimeError,
268  "Operator bpy.ops.%.200s.poll() %.200s",
269  opname,
270  msg ? msg : "failed, context is incorrect");
272  if (msg_free) {
273  MEM_freeN((void *)msg);
274  }
275  error_val = -1;
276  }
277  else {
280 
281  if (kw && PyDict_Size(kw)) {
282  error_val = pyrna_pydict_to_props(
283  &ptr, kw, false, "Converting py args to operator properties: ");
284  }
285 
286  if (error_val == 0) {
287  ReportList *reports;
288 
289  reports = MEM_mallocN(sizeof(ReportList), "wmOperatorReportList");
290 
291  /* Own so these don't move into global reports. */
293 
294 #ifdef BPY_RELEASE_GIL
295  /* release GIL, since a thread could be started from an operator
296  * that updates a driver */
297  /* NOTE: I have not seen any examples of code that does this
298  * so it may not be officially supported but seems to work ok. */
299  {
300  PyThreadState *ts = PyEval_SaveThread();
301 #endif
302 
303  operator_ret = WM_operator_call_py(C, ot, context, &ptr, reports, is_undo);
304 
305 #ifdef BPY_RELEASE_GIL
306  /* regain GIL */
307  PyEval_RestoreThread(ts);
308  }
309 #endif
310 
311  error_val = BPy_reports_to_error(reports, PyExc_RuntimeError, false);
312 
313  /* operator output is nice to have in the terminal/console too */
314  if (!BLI_listbase_is_empty(&reports->list)) {
315  BPy_reports_write_stdout(reports, NULL);
316  }
317 
318  BKE_reports_clear(reports);
319  if ((reports->flag & RPT_FREE) == 0) {
320  MEM_freeN(reports);
321  }
322  else {
323  /* The WM is now responsible for running the modal operator,
324  * show reports in the info window. */
325  reports->flag &= ~RPT_OP_HOLD;
326  }
327  }
328 
330 
331 #if 0
332  /* if there is some way to know an operator takes args we should use this */
333  {
334  /* no props */
335  if (kw != NULL) {
336  PyErr_Format(PyExc_AttributeError, "Operator \"%s\" does not take any args", opname);
337  return NULL;
338  }
339 
341  }
342 #endif
343  }
344 
345  if (context_dict != NULL) {
346  PyObject *context_dict_test = CTX_py_dict_get(C);
347  if (context_dict_test != context_dict) {
348  Py_DECREF(context_dict_test);
349  }
350  /* Restore with original context dict,
351  * probably NULL but need this for nested operator calls. */
352  Py_DECREF(context_dict);
353  CTX_py_state_pop(C, &context_py_state);
354  }
355 
356  if (error_val == -1) {
357  return NULL;
358  }
359 
360  /* When calling `bpy.ops.wm.read_factory_settings()` `bpy.data's` main pointer
361  * is freed by clear_globals(), further access will crash blender.
362  * Setting context is not needed in this case, only calling because this
363  * function corrects bpy.data (internal Main pointer) */
365 
366  /* return operator_ret as a bpy enum */
368 }
369 
370 static PyObject *pyop_as_string(PyObject *UNUSED(self), PyObject *args)
371 {
373  PointerRNA ptr;
374 
375  const char *opname;
376  PyObject *kw = NULL; /* optional args */
377  bool all_args = true;
378  bool macro_args = true;
379  int error_val = 0;
380 
381  char *buf = NULL;
382  PyObject *pybuf;
383 
385 
386  if (C == NULL) {
387  PyErr_SetString(PyExc_RuntimeError,
388  "Context is None, can't get the string representation of this object.");
389  return NULL;
390  }
391 
392  if (!PyArg_ParseTuple(args,
393  "s|O!O&O&:_bpy.ops.as_string",
394  &opname,
395  &PyDict_Type,
396  &kw,
398  &all_args,
400  &macro_args)) {
401  return NULL;
402  }
403 
404  ot = WM_operatortype_find(opname, true);
405 
406  if (ot == NULL) {
407  PyErr_Format(PyExc_AttributeError,
408  "_bpy.ops.as_string: operator \"%.200s\" "
409  "could not be found",
410  opname);
411  return NULL;
412  }
413 
414  // WM_operator_properties_create(&ptr, opname);
415  /* Save another lookup */
417 
418  if (kw && PyDict_Size(kw)) {
419  error_val = pyrna_pydict_to_props(
420  &ptr, kw, false, "Converting py args to operator properties: ");
421  }
422 
423  if (error_val == 0) {
424  buf = WM_operator_pystring_ex(C, NULL, all_args, macro_args, ot, &ptr);
425  }
426 
428 
429  if (error_val == -1) {
430  return NULL;
431  }
432 
433  if (buf) {
434  pybuf = PyUnicode_FromString(buf);
435  MEM_freeN(buf);
436  }
437  else {
438  pybuf = PyUnicode_FromString("");
439  }
440 
441  return pybuf;
442 }
443 
444 static PyObject *pyop_dir(PyObject *UNUSED(self))
445 {
446  GHashIterator iter;
447  PyObject *list;
448  int i;
449 
450  WM_operatortype_iter(&iter);
451  list = PyList_New(BLI_ghash_len(iter.gh));
452 
453  for (i = 0; !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter), i++) {
455  PyList_SET_ITEM(list, i, PyUnicode_FromString(ot->idname));
456  }
457 
458  return list;
459 }
460 
461 static PyObject *pyop_getrna_type(PyObject *UNUSED(self), PyObject *value)
462 {
464  if ((ot = ot_lookup_from_py_string(value, "get_rna_type")) == NULL) {
465  return NULL;
466  }
467 
468  PointerRNA ptr;
469  RNA_pointer_create(NULL, &RNA_Struct, ot->srna, &ptr);
471  return (PyObject *)pyrna;
472 }
473 
474 static PyObject *pyop_get_bl_options(PyObject *UNUSED(self), PyObject *value)
475 {
477  if ((ot = ot_lookup_from_py_string(value, "get_bl_options")) == NULL) {
478  return NULL;
479  }
481 }
482 
483 static struct PyMethodDef bpy_ops_methods[] = {
484  {"poll", (PyCFunction)pyop_poll, METH_VARARGS, NULL},
485  {"call", (PyCFunction)pyop_call, METH_VARARGS, NULL},
486  {"as_string", (PyCFunction)pyop_as_string, METH_VARARGS, NULL},
487  {"dir", (PyCFunction)pyop_dir, METH_NOARGS, NULL},
488  {"get_rna_type", (PyCFunction)pyop_getrna_type, METH_O, NULL},
489  {"get_bl_options", (PyCFunction)pyop_get_bl_options, METH_O, NULL},
490  {"macro_define", (PyCFunction)PYOP_wrap_macro_define, METH_VARARGS, NULL},
491  {NULL, NULL, 0, NULL},
492 };
493 
494 static struct PyModuleDef bpy_ops_module = {
495  PyModuleDef_HEAD_INIT,
496  "_bpy.ops",
497  NULL,
498  -1, /* multiple "initialization" just copies the module dict. */
500  NULL,
501  NULL,
502  NULL,
503  NULL,
504 };
505 
506 PyObject *BPY_operator_module(void)
507 {
508  PyObject *submodule;
509 
510  submodule = PyModule_Create(&bpy_ops_module);
511 
512  return submodule;
513 }
void CTX_py_state_push(bContext *C, struct bContext_PyState *pystate, void *value)
Definition: context.c:251
void * CTX_py_dict_get(const bContext *C)
Definition: context.c:242
void CTX_py_state_pop(bContext *C, struct bContext_PyState *pystate)
Definition: context.c:259
const char * CTX_wm_operator_poll_msg_get(struct bContext *C, bool *r_free)
Definition: context.c:1057
void CTX_wm_operator_poll_msg_clear(struct bContext *C)
Definition: context.c:1030
void BKE_reports_clear(ReportList *reports)
Definition: report.c:63
void BKE_reports_init(ReportList *reports, int flag)
Definition: report.c:50
void BLI_ghashIterator_step(GHashIterator *ghi)
Definition: BLI_ghash.c:914
BLI_INLINE void * BLI_ghashIterator_getValue(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.h:302
unsigned int BLI_ghash_len(const GHash *gh) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:705
BLI_INLINE bool BLI_ghashIterator_done(const GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.h:310
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
Definition: BLI_listbase.h:269
#define UNUSED(x)
#define ELEM(...)
void BPY_modules_update(void)
@ OPERATOR_CANCELLED
Read Guarded memory(de)allocation.
#define C
Definition: RandGen.cpp:25
wmOperatorCallContext
Definition: WM_types.h:199
@ WM_OP_EXEC_DEFAULT
Definition: WM_types.h:208
void BPy_reports_write_stdout(const ReportList *reports, const char *header)
short BPy_reports_to_error(ReportList *reports, PyObject *exception, const bool clear)
struct bContext * BPY_context_get(void)
static wmOperatorType * ot_lookup_from_py_string(PyObject *value, const char *py_fn_id)
Definition: bpy_operator.c:47
static PyObject * pyop_getrna_type(PyObject *UNUSED(self), PyObject *value)
Definition: bpy_operator.c:461
static struct PyModuleDef bpy_ops_module
Definition: bpy_operator.c:494
static PyObject * pyop_as_string(PyObject *UNUSED(self), PyObject *args)
Definition: bpy_operator.c:370
static PyObject * pyop_dir(PyObject *UNUSED(self))
Definition: bpy_operator.c:444
static struct PyMethodDef bpy_ops_methods[]
Definition: bpy_operator.c:483
PyObject * BPY_operator_module(void)
Definition: bpy_operator.c:506
static PyObject * pyop_poll(PyObject *UNUSED(self), PyObject *args)
Definition: bpy_operator.c:80
static void op_context_override_deprecated_warning(const char *action, const char *opname)
Definition: bpy_operator.c:63
static PyObject * pyop_call(PyObject *UNUSED(self), PyObject *args)
Definition: bpy_operator.c:168
static PyObject * pyop_get_bl_options(PyObject *UNUSED(self), PyObject *value)
Definition: bpy_operator.c:474
PyObject * PYOP_wrap_macro_define(PyObject *UNUSED(self), PyObject *args)
bool pyrna_write_check(void)
Definition: bpy_rna.c:344
PyObject * pyrna_struct_CreatePyObject(PointerRNA *ptr)
Definition: bpy_rna.c:7505
int pyrna_pydict_to_props(PointerRNA *ptr, PyObject *kw, const bool all_args, const char *error_prefix)
Definition: bpy_rna.c:1453
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
PyObject * pyrna_enum_bitfield_as_set(const EnumPropertyItem *items, int value)
Definition: py_capi_rna.c:170
char * pyrna_enum_repr(const EnumPropertyItem *item)
Definition: py_capi_rna.c:30
int PyC_ParseBool(PyObject *o, void *p)
return ret
void RNA_pointer_create(ID *id, StructRNA *type, void *data, PointerRNA *r_ptr)
Definition: rna_access.c:136
bool RNA_enum_value_from_id(const EnumPropertyItem *item, const char *identifier, int *r_value)
Definition: rna_access.c:5076
const EnumPropertyItem rna_enum_operator_context_items[]
Definition: rna_ui.c:30
const EnumPropertyItem rna_enum_operator_type_flag_items[]
Definition: rna_wm.c:429
const EnumPropertyItem rna_enum_operator_return_items[]
Definition: rna_wm.c:463
GHash * gh
Definition: BLI_ghash.h:45
const char * idname
Definition: WM_types.h:890
struct StructRNA * srna
Definition: WM_types.h:969
bool WM_operator_poll_context(bContext *C, wmOperatorType *ot, short context)
int WM_operator_name_call(bContext *C, const char *opstring, wmOperatorCallContext context, PointerRNA *properties, const wmEvent *event)
int WM_operator_call_py(bContext *C, wmOperatorType *ot, wmOperatorCallContext context, PointerRNA *properties, ReportList *reports, const bool is_undo)
PointerRNA * ptr
Definition: wm_files.c:3480
wmOperatorType * ot
Definition: wm_files.c:3479
void WM_operatortype_iter(GHashIterator *ghi)
wmOperatorType * WM_operatortype_find(const char *idname, bool quiet)
char * WM_operator_pystring_ex(bContext *C, wmOperator *op, const bool all_args, const bool macro_args, wmOperatorType *ot, PointerRNA *opptr)
Definition: wm_operators.c:192
void WM_operator_properties_create_ptr(PointerRNA *ptr, wmOperatorType *ot)
Definition: wm_operators.c:661
void WM_operator_properties_free(PointerRNA *ptr)
Definition: wm_operators.c:783
void WM_operator_properties_sanitize(PointerRNA *ptr, const bool no_context)
Definition: wm_operators.c:701