fix to allow [#24009] to be fixed.
WM_operator_poll() could fail in cases WM_operator_name_call() would succeed because calling the operator would setup the context before calling poll. this would result in python raising an invalid error or menu items being greyed out. now python can also check with an operator context: bpy.ops.object.editmode_toggle.poll('INVOKE_SCREEN')
This commit is contained in:
@@ -46,12 +46,15 @@ static PyObject *pyop_poll(PyObject *UNUSED(self), PyObject *args)
|
||||
char *opname;
|
||||
PyObject *context_dict= NULL; /* optional args */
|
||||
PyObject *context_dict_back;
|
||||
char *context_str= NULL;
|
||||
PyObject *ret;
|
||||
|
||||
int context= WM_OP_EXEC_DEFAULT;
|
||||
|
||||
// XXX Todo, work out a better solution for passing on context, could make a tuple from self and pack the name and Context into it...
|
||||
bContext *C = BPy_GetContext();
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s|O:_bpy.ops.poll", &opname, &context_dict))
|
||||
if (!PyArg_ParseTuple(args, "s|Os:_bpy.ops.poll", &opname, &context_dict, &context_str))
|
||||
return NULL;
|
||||
|
||||
ot= WM_operatortype_find(opname, TRUE);
|
||||
@@ -61,6 +64,15 @@ static PyObject *pyop_poll(PyObject *UNUSED(self), PyObject *args)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(context_str) {
|
||||
if(RNA_enum_value_from_id(operator_context_items, context_str, &context)==0) {
|
||||
char *enum_str= BPy_enum_as_string(operator_context_items);
|
||||
PyErr_Format(PyExc_TypeError, "Calling operator \"bpy.ops.%s.poll\" error, expected a string enum in (%.200s)", opname, enum_str);
|
||||
MEM_freeN(enum_str);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if(!PyDict_Check(context_dict))
|
||||
context_dict= NULL;
|
||||
|
||||
@@ -70,7 +82,7 @@ static PyObject *pyop_poll(PyObject *UNUSED(self), PyObject *args)
|
||||
Py_XINCREF(context_dict); /* so we done loose it */
|
||||
|
||||
/* main purpose of thsi function */
|
||||
ret= WM_operator_poll((bContext*)C, ot) ? Py_True : Py_False;
|
||||
ret= WM_operator_poll_context((bContext*)C, ot, context) ? Py_True : Py_False;
|
||||
|
||||
/* restore with original context dict, probably NULL but need this for nested operator calls */
|
||||
Py_XDECREF(context_dict);
|
||||
@@ -126,7 +138,7 @@ static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args)
|
||||
CTX_py_dict_set(C, (void *)context_dict);
|
||||
Py_XINCREF(context_dict); /* so we done loose it */
|
||||
|
||||
if(WM_operator_poll((bContext*)C, ot) == FALSE) {
|
||||
if(WM_operator_poll_context((bContext*)C, ot, context) == FALSE) {
|
||||
const char *msg= CTX_wm_operator_poll_msg_get(C);
|
||||
PyErr_Format( PyExc_SystemError, "Operator bpy.ops.%.200s.poll() %s", opname, msg ? msg : "failed, context is incorrect");
|
||||
CTX_wm_operator_poll_msg_set(C, NULL); /* better set to NULL else it could be used again */
|
||||
|
Reference in New Issue
Block a user