* PyOperators now parse args using the PyRNA api (wraps ID props internally),
authorCampbell Barton <ideasman42@gmail.com>
Thu, 25 Dec 2008 10:48:36 +0000 (10:48 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Thu, 25 Dec 2008 10:48:36 +0000 (10:48 +0000)
this means it can reuse the function for converting python to RNA types - giving more useful errors.
* Incorrect enum args lists valid values in their exception message (used for PyRNA and PyOperators).
* remove bpy_idprop.c and bpy_idprop.h

PyOperators are not usable since they run outside the UI loop atm.

source/blender/python/intern/bpy_idprop.c [deleted file]
source/blender/python/intern/bpy_idprop.h [deleted file]
source/blender/python/intern/bpy_operator.c
source/blender/python/intern/bpy_rna.c
source/blender/python/intern/bpy_rna.h

diff --git a/source/blender/python/intern/bpy_idprop.c b/source/blender/python/intern/bpy_idprop.c
deleted file mode 100644 (file)
index 4b4bfa6..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-/**
- * $Id: IDProp.c
- *
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * Contributor(s): Joseph Eagar, Campbell Barton
- *
- * ***** END GPL LICENSE BLOCK *****
- */
- #include "DNA_ID.h"
-
-#include "BKE_idprop.h"
-
-#include "bpy_idprop.h"
-#include "bpy_compat.h"
-
-#include "MEM_guardedalloc.h"
-
-#define BSTR_EQ(a, b)  (*(a) == *(b) && !strcmp(a, b))
-
-static PyObject *EXPP_ReturnPyObjError( PyObject * type, char *error_msg )
-{                              /* same as above, just to change its name smoothly */
-       PyErr_SetString( type, error_msg );
-       return NULL;
-}
-
-static int EXPP_ReturnIntError( PyObject * type, char *error_msg )
-{
-       PyErr_SetString( type, error_msg );
-       return -1;
-}
-
-/*returns NULL on success, error string on failure*/
-static char *BPy_IDProperty_Map_ValidateAndCreate(char *name, IDProperty *group, PyObject *ob)
-{
-       IDProperty *prop = NULL;
-       IDPropertyTemplate val = {0};
-       
-       if (PyFloat_Check(ob)) {
-               val.d = PyFloat_AsDouble(ob);
-               prop = IDP_New(IDP_DOUBLE, val, name);
-       } else if (PyLong_Check(ob)) {
-               val.i = (int) PyLong_AsLong(ob);
-               prop = IDP_New(IDP_INT, val, name);
-       } else if (PyUnicode_Check(ob)) {
-               val.str = _PyUnicode_AsString(ob);
-               prop = IDP_New(IDP_STRING, val, name);
-       } else if (PySequence_Check(ob)) {
-               PyObject *item;
-               int i;
-               
-               /*validate sequence and derive type.
-               we assume IDP_INT unless we hit a float
-               number; then we assume it's */
-               val.array.type = IDP_INT;
-               val.array.len = PySequence_Length(ob);
-               for (i=0; i<val.array.len; i++) {
-                       item = PySequence_GetItem(ob, i);
-                       if (PyFloat_Check(item)) val.array.type = IDP_DOUBLE;
-                       else if (!PyLong_Check(item)) return "only floats and ints are allowed in ID property arrays";
-                       Py_XDECREF(item);
-               }
-               
-               prop = IDP_New(IDP_ARRAY, val, name);
-               for (i=0; i<val.array.len; i++) {
-                       item = PySequence_GetItem(ob, i);
-                       if (val.array.type == IDP_INT) {
-                               item = PyNumber_Int(item);
-                               ((int*)prop->data.pointer)[i] = (int)PyLong_AsLong(item);
-                       } else {
-                               item = PyNumber_Float(item);
-                               ((double*)prop->data.pointer)[i] = (float)PyFloat_AsDouble(item);
-                       }
-                       Py_XDECREF(item);
-               }
-       } else if (PyMapping_Check(ob)) {
-               PyObject *keys, *vals, *key, *pval;
-               int i, len;
-               /*yay! we get into recursive stuff now!*/
-               keys = PyMapping_Keys(ob);
-               vals = PyMapping_Values(ob);
-               
-               /*we allocate the group first; if we hit any invalid data,
-                 we can delete it easily enough.*/
-               prop = IDP_New(IDP_GROUP, val, name);
-               len = PyMapping_Length(ob);
-               for (i=0; i<len; i++) {
-                       key = PySequence_GetItem(keys, i);
-                       pval = PySequence_GetItem(vals, i);
-                       if (!PyUnicode_Check(key)) {
-                               IDP_FreeProperty(prop);
-                               MEM_freeN(prop);
-                               Py_XDECREF(keys);
-                               Py_XDECREF(vals);
-                               Py_XDECREF(key);
-                               Py_XDECREF(pval);
-                               return "invalid element in subgroup dict template!";
-                       }
-                       if (BPy_IDProperty_Map_ValidateAndCreate(_PyUnicode_AsString(key), prop, pval)) {
-                               IDP_FreeProperty(prop);
-                               MEM_freeN(prop);
-                               Py_XDECREF(keys);
-                               Py_XDECREF(vals);
-                               Py_XDECREF(key);
-                               Py_XDECREF(pval);
-                               return "invalid element in subgroup dict template!";
-                       }
-                       Py_XDECREF(key);
-                       Py_XDECREF(pval);
-               }
-               Py_XDECREF(keys);
-               Py_XDECREF(vals);
-       } else return "invalid property value";
-       
-       IDP_ReplaceInGroup(group, prop);
-       return NULL;
-}
-
-
-static int BPy_IDGroup_Map_SetItem(IDProperty *prop, PyObject *key, PyObject *val)
-{
-       char *err;
-       
-       if (prop->type  != IDP_GROUP)
-               return EXPP_ReturnIntError( PyExc_TypeError,
-                       "unsubscriptable object");
-                       
-       if (!PyUnicode_Check(key))
-               return EXPP_ReturnIntError( PyExc_TypeError,
-                  "only strings are allowed as subgroup keys" );
-
-       if (val == NULL) {
-               IDProperty *pkey = IDP_GetPropertyFromGroup(prop, _PyUnicode_AsString(key));
-               if (pkey) {
-                       IDP_RemFromGroup(prop, pkey);
-                       IDP_FreeProperty(pkey);
-                       MEM_freeN(pkey);
-                       return 0;
-               } else return EXPP_ReturnIntError( PyExc_RuntimeError, "property not found in group" );
-       }
-       
-       err = BPy_IDProperty_Map_ValidateAndCreate(_PyUnicode_AsString(key), prop, val);
-       if (err) return EXPP_ReturnIntError( PyExc_RuntimeError, err );
-       
-       return 0;
-}
-
-
-PyObject *BPy_IDGroup_Update(IDProperty *prop, PyObject *value)
-{
-       PyObject *pkey, *pval;
-       Py_ssize_t i=0;
-       
-       if (!PyDict_Check(value))
-               return EXPP_ReturnPyObjError( PyExc_TypeError,
-                  "expected an object derived from dict.");
-                  
-       while (PyDict_Next(value, &i, &pkey, &pval)) {
-               BPy_IDGroup_Map_SetItem(prop, pkey, pval);
-               if (PyErr_Occurred()) return NULL;
-       }
-       
-       Py_RETURN_NONE;
-}
\ No newline at end of file
diff --git a/source/blender/python/intern/bpy_idprop.h b/source/blender/python/intern/bpy_idprop.h
deleted file mode 100644 (file)
index c68265a..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/**
- * $Id: IDProp.h
- *
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * Contributor(s): Joseph Eagar
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#include <Python.h>
-
-struct ID;
-struct IDProperty;
-
-PyObject *BPy_IDGroup_Update(IDProperty *prop, PyObject *value);
\ No newline at end of file
index 0da0782c2d1c73a87066c6ae6269861ed5ce9bd7..d6bae190dd2165287330b627acabb6a459094ce2 100644 (file)
@@ -24,8 +24,8 @@
  */
 
 #include "bpy_operator.h"
+#include "bpy_rna.h" /* for setting arg props only - pyrna_py_to_prop() */
 #include "bpy_compat.h"
-#include "bpy_idprop.h"
 
 //#include "blendef.h"
 #include "BLI_dynstr.h"
@@ -90,26 +90,74 @@ static PyObject *pyop_base_getattro( BPy_OperatorBase * self, PyObject *pyname )
 static PyObject * pyop_func_call(BPy_OperatorFunc * self, PyObject *args, PyObject *kw)
 {
        IDProperty *properties = NULL;
+       wmOperatorType *ot;
+
+       int error_val = 0;
+       const char *arg_name= NULL;
+       PyObject *item;
+       
+       PointerRNA ptr;
+       PropertyRNA *prop, *iterprop;
+       CollectionPropertyIterator iter;
+
+
+       if (ot == NULL) {
+               PyErr_SetString( PyExc_SystemError, "Operator could not be found");
+               return NULL;
+       }
 
        if (PyTuple_Size(args)) {
                PyErr_SetString( PyExc_AttributeError, "All operator args must be keywords");
                return NULL;
        }
 
-       if (kw && PyDict_Size(kw) > 0) {
-               IDPropertyTemplate val;
-               val.i = 0; /* silence MSVC warning about uninitialized var when debugging */
+       ot= WM_operatortype_find(self->name);
+       RNA_pointer_create(NULL, NULL, ot->srna, &properties, &ptr);
+
+
+       iterprop= RNA_struct_iterator_property(&ptr);
+       RNA_property_collection_begin(&ptr, iterprop, &iter);
+
+
+       for(; iter.valid; RNA_property_collection_next(&iter)) {
+               prop= iter.ptr.data;
 
-               properties= IDP_New(IDP_GROUP, val, "property");
-               BPy_IDGroup_Update(properties, kw);
+               arg_name= RNA_property_identifier(&iter.ptr, prop);
 
-               if (PyErr_Occurred()) {
+               if (strcmp(arg_name, "rna_type")==0) continue;
+
+               if (kw==NULL) {
+                       PyErr_Format( PyExc_AttributeError, "no args, expected \"%s\"", arg_name ? arg_name : "<UNKNOWN>");
+                       error_val= 1;
+                       break;
+               }
+               
+               item= PyDict_GetItemString(kw, arg_name);
+
+               if (item == NULL) {
+                       PyErr_Format( PyExc_AttributeError, "argument \"%s\" missing", arg_name ? arg_name : "<UNKNOWN>");
+                       error_val = 1; /* pyrna_py_to_prop sets the error */
+                       break;
+               }
+
+               if (pyrna_py_to_prop(&ptr, prop, item)) {
+                       error_val= 1;
+                       break;
+               }
+       }
+
+       RNA_property_collection_end(&iter);
+
+       if (error_val) {
+               if (properties) {
                        IDP_FreeProperty(properties);
                        MEM_freeN(properties);
-                       return NULL;
                }
+
+               return NULL; 
        }
        
+       
        WM_operator_name_call(self->C, self->name, WM_OP_DEFAULT, properties);
 
        if (properties) {
index 356cb40965f42ae5c558b7deb8063aa5cd70f5d1..0b33f11d74d3a572be5eb861bf5370abbbd0b349 100644 (file)
@@ -59,6 +59,27 @@ static long pyrna_struct_hash( BPy_StructRNA * self )
        return (long)self->ptr.data;
 }
 
+static char *pyrna_enum_as_string(PointerRNA *ptr, PropertyRNA *prop)
+{
+       const EnumPropertyItem *item;
+       int totitem, i;
+
+       DynStr *dynstr= BLI_dynstr_new();
+       char *cstring;
+
+       RNA_property_enum_items(ptr, prop, &item, &totitem);
+
+       for (i=0; i<totitem; i++) {
+               if (i<totitem-1)
+                       BLI_dynstr_appendf(dynstr, "'%s', ", item[i].identifier);
+               else
+                       BLI_dynstr_appendf(dynstr, "'%s'", item[i].identifier);
+       }
+       
+       cstring = BLI_dynstr_get_cstring(dynstr);
+       BLI_dynstr_free(dynstr);
+       return cstring;
+}
 
 static PyObject * pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop)
 {
@@ -130,7 +151,7 @@ static PyObject * pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop)
 }
 
 
-static int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, PyObject *value)
+int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, PyObject *value)
 {
        int type = RNA_property_type(ptr, prop);
        int len = RNA_property_array_length(ptr, prop);
@@ -281,14 +302,18 @@ static int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, PyObject *value)
                        char *param = _PyUnicode_AsString(value);
                        
                        if (param==NULL) {
-                               PyErr_SetString(PyExc_TypeError, "expected a string type");
+                               char *enum_str= pyrna_enum_as_string(ptr, prop);
+                               PyErr_Format(PyExc_TypeError, "expected a string enum type in (%s)", enum_str);
+                               MEM_freeN(enum_str);
                                return -1;
                        } else {
                                int val;
                                if (RNA_property_enum_value(ptr, prop, param, &val)) {
                                        RNA_property_enum_set(ptr, prop, val);
                                } else {
-                                       PyErr_Format(PyExc_AttributeError, "enum \"%s\" not found", param);
+                                       char *enum_str= pyrna_enum_as_string(ptr, prop);
+                                       PyErr_Format(PyExc_AttributeError, "enum \"%s\" not found in (%s)", param, enum_str);
+                                       MEM_freeN(enum_str);
                                        return -1;
                                }
                        }
@@ -608,23 +633,10 @@ PyObject *pyrna_struct_to_docstring(BPy_StructRNA *self)
                        }
                        case PROP_ENUM:
                        {
-                               const EnumPropertyItem *item;
-                               int totitem;
-                               
+                               char *enum_str= pyrna_enum_as_string(&iter.ptr, prop);
                                BLI_dynstr_appendf(dynstr, "@ivar %s: %s%s\n", identifier, desc, readonly);
-                               
-                               BLI_dynstr_appendf(dynstr, "@type %s: enum in [", identifier);
-                               
-                               RNA_property_enum_items(&iter.ptr, prop, &item, &totitem);
-                               
-                               for (i=0; i<totitem; i++) {
-                                       BLI_dynstr_append(dynstr, item[i].identifier);
-                                       if (i<totitem-1) {
-                                               BLI_dynstr_append(dynstr, ", ");
-                                       }
-                               }
-                               
-                               BLI_dynstr_append(dynstr, "]\n");
+                               BLI_dynstr_appendf(dynstr, "@type %s: enum in [%s]\n", identifier, enum_str);
+                               MEM_freeN(enum_str);
                                break;
                        }
                        case PROP_POINTER:
index 94f97a565a44b802aeedc688d84bc8bee2766e7f..f707ebb774b87eb5d1cfd5b98e8aad78174b1a33 100644 (file)
@@ -49,4 +49,7 @@ PyObject *BPY_rna_doc( void );
 PyObject *pyrna_struct_CreatePyObject( PointerRNA *ptr );
 PyObject *pyrna_prop_CreatePyObject( PointerRNA *ptr, PropertyRNA *prop );
 
+/* operators also need this to set args */
+int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, PyObject *value);
+
 #endif