Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCampbell Barton <ideasman42@gmail.com>2009-07-17 06:31:28 +0400
committerCampbell Barton <ideasman42@gmail.com>2009-07-17 06:31:28 +0400
commit70f6255433fcb1f5551199ef7a285a9ab80a3318 (patch)
tree1471a4451ee14d5b29ed37e2dc86300b01180698 /source/blender/python/intern
parentc6c853d88a9c5ff12b7a56e4bdaca1757f160997 (diff)
bpy rna
Calling rna functions with invalid keywords, too many keywords and too many args would fail silently - now raise an error with invalid keywords and a list of valid ones, raise an error when too many args are given. - calling rna functions would alloc a ParameterList each time, changed to use a stack variable (2 pointers and an int). - store the number of parameters ParameterList - python exception types were wrong in many cases, (using attribute error rather then type error) - fixes to small errors in python UI scripts.
Diffstat (limited to 'source/blender/python/intern')
-rw-r--r--source/blender/python/intern/bpy_rna.c145
1 files changed, 112 insertions, 33 deletions
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index 9ce9ec8e838..34269db7f94 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -367,7 +367,7 @@ PyObject * pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop)
ret = pyrna_prop_CreatePyObject(ptr, prop);
break;
default:
- PyErr_Format(PyExc_AttributeError, "RNA Error: unknown type \"%d\" (pyrna_prop_to_py)", type);
+ PyErr_Format(PyExc_TypeError, "RNA Error: unknown type \"%d\" (pyrna_prop_to_py)", type);
ret = NULL;
break;
}
@@ -392,7 +392,7 @@ int pyrna_pydict_to_props(PointerRNA *ptr, PyObject *kw, const char *error_prefi
if (strcmp(arg_name, "rna_type")==0) continue;
if (kw==NULL) {
- PyErr_Format( PyExc_AttributeError, "%.200s: no keywords, expected \"%.200s\"", error_prefix, arg_name ? arg_name : "<UNKNOWN>");
+ PyErr_Format( PyExc_TypeError, "%.200s: no keywords, expected \"%.200s\"", error_prefix, arg_name ? arg_name : "<UNKNOWN>");
error_val= -1;
break;
}
@@ -400,7 +400,7 @@ int pyrna_pydict_to_props(PointerRNA *ptr, PyObject *kw, const char *error_prefi
item= PyDict_GetItemString(kw, arg_name);
if (item == NULL) {
- PyErr_Format( PyExc_AttributeError, "%.200s: keyword \"%.200s\" missing", error_prefix, arg_name ? arg_name : "<UNKNOWN>");
+ PyErr_Format( PyExc_TypeError, "%.200s: keyword \"%.200s\" missing", error_prefix, arg_name ? arg_name : "<UNKNOWN>");
error_val = -1; /* pyrna_py_to_prop sets the error */
break;
}
@@ -424,7 +424,7 @@ int pyrna_pydict_to_props(PointerRNA *ptr, PyObject *kw, const char *error_prefi
arg_name= NULL;
}
- PyErr_Format( PyExc_AttributeError, "%.200s: keyword \"%.200s\" unrecognized", error_prefix, arg_name ? arg_name : "<UNKNOWN>");
+ PyErr_Format( PyExc_TypeError, "%.200s: keyword \"%.200s\" unrecognized", error_prefix, arg_name ? arg_name : "<UNKNOWN>");
error_val = -1;
}
@@ -482,7 +482,7 @@ int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *v
/* done getting the length */
if (py_len != len) {
- PyErr_Format(PyExc_AttributeError, "python sequence length %d did not match the RNA array length %d.", py_len, len);
+ PyErr_Format(PyExc_TypeError, "python sequence length %d did not match the RNA array length %d.", py_len, len);
return -1;
}
@@ -647,7 +647,7 @@ int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *v
else RNA_property_enum_set(ptr, prop, val);
} else {
char *enum_str= pyrna_enum_as_string(ptr, prop);
- PyErr_Format(PyExc_AttributeError, "enum \"%.200s\" not found in (%.200s)", param, enum_str);
+ PyErr_Format(PyExc_TypeError, "enum \"%.200s\" not found in (%.200s)", param, enum_str);
MEM_freeN(enum_str);
return -1;
}
@@ -1807,7 +1807,7 @@ PyObject *pyrna_param_to_py(PointerRNA *ptr, PropertyRNA *prop, void *data)
PyTuple_SET_ITEM(ret, a, PyFloat_FromDouble( ((float*)data)[a] ));
break;
default:
- PyErr_Format(PyExc_AttributeError, "RNA Error: unknown array type \"%d\" (pyrna_param_to_py)", type);
+ PyErr_Format(PyExc_TypeError, "RNA Error: unknown array type \"%d\" (pyrna_param_to_py)", type);
ret = NULL;
break;
}
@@ -1889,7 +1889,7 @@ PyObject *pyrna_param_to_py(PointerRNA *ptr, PropertyRNA *prop, void *data)
break;
}
default:
- PyErr_Format(PyExc_AttributeError, "RNA Error: unknown type \"%d\" (pyrna_param_to_py)", type);
+ PyErr_Format(PyExc_TypeError, "RNA Error: unknown type \"%d\" (pyrna_param_to_py)", type);
ret = NULL;
break;
}
@@ -1904,25 +1904,31 @@ static PyObject * pyrna_func_call(PyObject * self, PyObject *args, PyObject *kw)
FunctionRNA *self_func= PyCObject_AsVoidPtr(PyTuple_GET_ITEM(self, 1));
PointerRNA funcptr;
- ParameterList *parms;
+ ParameterList parms;
ParameterIterator iter;
PropertyRNA *pret, *parm;
PyObject *ret, *item;
- int i, tlen, flag, err= 0;
- const char *tid, *fid, *pid;
+ int i, args_len, parms_len, flag, err= 0, kw_tot= 0;
+ const char *parm_id;
void *retdata= NULL;
/* setup */
RNA_pointer_create(NULL, &RNA_Function, self_func, &funcptr);
pret= RNA_function_return(self_func);
- tlen= PyTuple_GET_SIZE(args);
+ args_len= PyTuple_GET_SIZE(args);
- parms= RNA_parameter_list_create(self_ptr, self_func);
- RNA_parameter_list_begin(parms, &iter);
+ RNA_parameter_list_create(&parms, self_ptr, self_func);
+ RNA_parameter_list_begin(&parms, &iter);
+ parms_len = RNA_parameter_list_size(&parms);
+
+ if(args_len + (kw ? PyDict_Size(kw):0) > parms_len) {
+ PyErr_Format(PyExc_TypeError, "%.200s.%.200s(): takes at most %d arguments, got %d", RNA_struct_identifier(self_ptr->type), RNA_function_identifier(self_func), parms_len, args_len);
+ err= -1;
+ }
/* parse function parameters */
- for (i= 0; iter.valid; RNA_parameter_list_next(&iter)) {
+ for (i= 0; iter.valid && err==0; RNA_parameter_list_next(&iter)) {
parm= iter.parm;
if (parm==pret) {
@@ -1930,27 +1936,27 @@ static PyObject * pyrna_func_call(PyObject * self, PyObject *args, PyObject *kw)
continue;
}
- pid= RNA_property_identifier(parm);
+ parm_id= RNA_property_identifier(parm);
flag= RNA_property_flag(parm);
item= NULL;
- if ((i < tlen) && (flag & PROP_REQUIRED)) {
+ if ((i < args_len) && (flag & PROP_REQUIRED)) {
item= PyTuple_GET_ITEM(args, i);
i++;
}
- else if (kw != NULL)
- item= PyDict_GetItemString(kw, pid); /* borrow ref */
+ else if (kw != NULL) {
+ item= PyDict_GetItemString(kw, parm_id); /* borrow ref */
+ if(item)
+ kw_tot++; /* make sure invalid keywords are not given */
+ }
if (item==NULL) {
if(flag & PROP_REQUIRED) {
- tid= RNA_struct_identifier(self_ptr->type);
- fid= RNA_function_identifier(self_func);
-
- PyErr_Format(PyExc_AttributeError, "%.200s.%.200s(): required parameter \"%.200s\" not specified", tid, fid, pid);
+ PyErr_Format(PyExc_TypeError, "%.200s.%.200s(): required parameter \"%.200s\" not specified", RNA_struct_identifier(self_ptr->type), RNA_function_identifier(self_func), parm_id);
err= -1;
break;
}
- else
+ else /* PyDict_GetItemString wont raise an error */
continue;
}
@@ -1960,6 +1966,73 @@ static PyObject * pyrna_func_call(PyObject * self, PyObject *args, PyObject *kw)
break;
}
+
+ /* Check if we gave args that dont exist in the function
+ * printing the error is slow but it should only happen when developing.
+ * the if below is quick, checking if it passed less keyword args then we gave */
+ if(kw && (PyDict_Size(kw) > kw_tot)) {
+ PyObject *key, *value;
+ Py_ssize_t pos = 0;
+
+ DynStr *bad_args= BLI_dynstr_new();
+ DynStr *good_args= BLI_dynstr_new();
+
+ char *arg_name, *bad_args_str, *good_args_str;
+ int found= 0, first=1;
+
+ while (PyDict_Next(kw, &pos, &key, &value)) {
+
+ arg_name= _PyUnicode_AsString(key);
+ found= 0;
+
+ if(arg_name==NULL) { /* unlikely the argname is not a string but ignore if it is*/
+ PyErr_Clear();
+ }
+ else {
+ /* Search for arg_name */
+ RNA_parameter_list_begin(&parms, &iter);
+ for(; iter.valid; RNA_parameter_list_next(&iter)) {
+ parm= iter.parm;
+ if (strcmp(arg_name, RNA_property_identifier(parm))==0) {
+ found= 1;
+ break;
+ }
+ }
+
+ RNA_parameter_list_end(&iter);
+
+ if(!found) {
+ BLI_dynstr_appendf(bad_args, first ? "%s" : ", %s", arg_name);
+ first= 0;
+ }
+ }
+ }
+
+ /* list good args */
+ first= 1;
+
+ RNA_parameter_list_begin(&parms, &iter);
+ for(; iter.valid; RNA_parameter_list_next(&iter)) {
+ parm= iter.parm;
+ BLI_dynstr_appendf(good_args, first ? "%s" : ", %s", RNA_property_identifier(parm));
+ first= 0;
+ }
+ RNA_parameter_list_end(&iter);
+
+
+ bad_args_str= BLI_dynstr_get_cstring(bad_args);
+ good_args_str= BLI_dynstr_get_cstring(good_args);
+
+ PyErr_Format(PyExc_TypeError, "%.200s.%.200s(): was called with invalid keyword arguments(s) (%s), expected (%s)", RNA_struct_identifier(self_ptr->type), RNA_function_identifier(self_func), bad_args_str, good_args_str);
+
+ BLI_dynstr_free(bad_args);
+ BLI_dynstr_free(good_args);
+ MEM_freeN(bad_args_str);
+ MEM_freeN(good_args_str);
+
+ err= -1;
+ }
+
ret= NULL;
if (err==0) {
/* call function */
@@ -1967,20 +2040,26 @@ static PyObject * pyrna_func_call(PyObject * self, PyObject *args, PyObject *kw)
bContext *C= BPy_GetContext();
BKE_reports_init(&reports, RPT_STORE);
- RNA_function_call(C, &reports, self_ptr, self_func, parms);
+ RNA_function_call(C, &reports, self_ptr, self_func, &parms);
err= (BPy_reports_to_error(&reports))? -1: 0;
BKE_reports_clear(&reports);
/* return value */
- if(err==0)
- if(pret)
+ if(err==0) {
+ if(pret) {
ret= pyrna_param_to_py(&funcptr, pret, retdata);
+
+ /* possible there is an error in conversion */
+ if(ret==NULL)
+ err= -1;
+ }
+ }
}
/* cleanup */
RNA_parameter_list_end(&iter);
- RNA_parameter_list_free(parms);
+ RNA_parameter_list_free(&parms);
if (ret)
return ret;
@@ -2387,7 +2466,7 @@ static PyObject *pyrna_basetype_getattro( BPy_BaseTypeRNA * self, PyObject *pyna
return ret;
}
else { /* Override the error */
- PyErr_Format(PyExc_AttributeError, "bpy.types.%.200s not a valid RNA_Struct", _PyUnicode_AsString(pyname));
+ PyErr_Format(PyExc_AttributeError, "bpy.types.%.200s RNA_Struct does not exist", _PyUnicode_AsString(pyname));
return NULL;
}
}
@@ -2629,7 +2708,7 @@ static int bpy_class_validate(PointerRNA *dummyptr, void *py_data, int *have_fun
if (base_class) {
if (!PyObject_IsSubclass(py_class, base_class)) {
PyObject *name= PyObject_GetAttrString(base_class, "__name__");
- PyErr_Format( PyExc_AttributeError, "expected %.200s subclass of class \"%.200s\"", class_type, name ? _PyUnicode_AsString(name):"<UNKNOWN>");
+ PyErr_Format( PyExc_TypeError, "expected %.200s subclass of class \"%.200s\"", class_type, name ? _PyUnicode_AsString(name):"<UNKNOWN>");
Py_XDECREF(name);
return -1;
}
@@ -2667,7 +2746,7 @@ static int bpy_class_validate(PointerRNA *dummyptr, void *py_data, int *have_fun
fitem= item; /* py 3.x */
if (PyFunction_Check(fitem)==0) {
- PyErr_Format( PyExc_AttributeError, "expected %.200s class \"%.200s\" attribute to be a function", class_type, RNA_function_identifier(func));
+ PyErr_Format( PyExc_TypeError, "expected %.200s class \"%.200s\" attribute to be a function", class_type, RNA_function_identifier(func));
return -1;
}
@@ -2795,12 +2874,12 @@ static int bpy_class_call(PointerRNA *ptr, FunctionRNA *func, ParameterList *par
}
else {
Py_DECREF(py_class_instance);
- PyErr_Format(PyExc_AttributeError, "could not find function %.200s in %.200s to execute callback.", RNA_function_identifier(func), RNA_struct_identifier(ptr->type));
+ PyErr_Format(PyExc_TypeError, "could not find function %.200s in %.200s to execute callback.", RNA_function_identifier(func), RNA_struct_identifier(ptr->type));
err= -1;
}
}
else {
- PyErr_Format(PyExc_AttributeError, "could not create instance of %.200s to call callback function %.200s.", RNA_struct_identifier(ptr->type), RNA_function_identifier(func));
+ PyErr_Format(PyExc_RuntimeError, "could not create instance of %.200s to call callback function %.200s.", RNA_struct_identifier(ptr->type), RNA_function_identifier(func));
err= -1;
}