PyRNA
authorCampbell Barton <ideasman42@gmail.com>
Fri, 5 Jun 2009 12:48:58 +0000 (12:48 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Fri, 5 Jun 2009 12:48:58 +0000 (12:48 +0000)
- Support for python to convert a PyObject into a collection (uses a list of dicts - quite verbose :/)
- Operators can now take collection args when called from python.
- Support for printing operators that use collections (macro recording).
- Added RNA_pointer_as_string which prints all pointer prop values as a python dict.

Example that can run in the in test.py (F7 key)
bpy.ops.VIEW3D_OT_select_lasso(path=[{"loc":(0, 0), "time":0}, {"loc":(1000, 0), "time":0}, {"loc":(1000, 1000), "time":0}], type='SELECT')

for some reason lasso locations always print as 0,0. Need to look into why this is.

source/blender/makesrna/RNA_access.h
source/blender/makesrna/intern/rna_access.c
source/blender/python/intern/bpy_operator.c
source/blender/python/intern/bpy_operator.h
source/blender/python/intern/bpy_operator_wrap.c
source/blender/python/intern/bpy_rna.c
source/blender/python/intern/bpy_rna.h
source/blender/python/intern/bpy_ui.c

index 70490259832ec457b3688ab68f2a13ef81aaeaa6..4df5aa6710406ab6604a224a7e029ba2954c8a23 100644 (file)
@@ -536,6 +536,7 @@ int RNA_property_is_set(PointerRNA *ptr, const char *name);
 
 /* python compatible string representation of this property, (must be freed!) */
 char *RNA_property_as_string(PointerRNA *ptr, PropertyRNA *prop);
+char *RNA_pointer_as_string(PointerRNA *ptr);
 
 /* Function */
 
index cf52c5fb1ec62d800fa70611818010fbe54d0fdc..91b46e8e3d7541c26de1f8b4865cbd9495a8f01b 100644 (file)
@@ -2185,6 +2185,47 @@ int RNA_property_is_set(PointerRNA *ptr, const char *name)
 
 /* string representation of a property, python
  * compatible but can be used for display too*/
+char *RNA_pointer_as_string(PointerRNA *ptr)
+{
+       DynStr *dynstr= BLI_dynstr_new();
+       char *cstring;
+       
+       PropertyRNA *prop, *iterprop;
+       CollectionPropertyIterator iter;
+       const char *propname;
+       int first_time = 1;
+       
+       BLI_dynstr_append(dynstr, "{");
+       
+       iterprop= RNA_struct_iterator_property(ptr->type);
+       RNA_property_collection_begin(ptr, iterprop, &iter);
+
+       for(; iter.valid; RNA_property_collection_next(&iter)) {
+               prop= iter.ptr.data;
+               propname = RNA_property_identifier(prop);
+               
+               if(strcmp(propname, "rna_type")==0)
+                       continue;
+               
+               if(first_time==0)
+                       BLI_dynstr_append(dynstr, ", ");
+               first_time= 0;
+               
+               cstring = RNA_property_as_string(&iter.ptr, prop);
+               BLI_dynstr_appendf(dynstr, "\"%s\":%s", propname, cstring);
+               MEM_freeN(cstring);
+               first_time= 0;
+       }
+
+       RNA_property_collection_end(&iter);
+       BLI_dynstr_append(dynstr, "}"); 
+       
+       
+       cstring = BLI_dynstr_get_cstring(dynstr);
+       BLI_dynstr_free(dynstr);
+       return cstring;
+}
+
 char *RNA_property_as_string(PointerRNA *ptr, PropertyRNA *prop)
 {
        int type = RNA_property_type(prop);
@@ -2262,8 +2303,28 @@ char *RNA_property_as_string(PointerRNA *ptr, PropertyRNA *prop)
                break;
        }
        case PROP_COLLECTION:
-               BLI_dynstr_append(dynstr, "'<COLLECTION>'"); /* TODO */
+       {
+               int first_time = 1;
+               CollectionPropertyIterator collect_iter;
+               BLI_dynstr_append(dynstr, "[");
+               
+               for(RNA_property_collection_begin(ptr, prop, &collect_iter); collect_iter.valid; RNA_property_collection_next(&collect_iter)) {
+                       PointerRNA itemptr= collect_iter.ptr;
+                       
+                       if(first_time==0)
+                               BLI_dynstr_append(dynstr, ", ");
+                       first_time= 0;
+                       
+                       /* now get every prop of the collection */
+                       cstring= RNA_pointer_as_string(&itemptr);
+                       BLI_dynstr_append(dynstr, cstring);
+                       MEM_freeN(cstring);
+               }
+               
+               RNA_property_collection_end(&collect_iter);
+               BLI_dynstr_append(dynstr, "]");
                break;
+       }
        default:
                BLI_dynstr_append(dynstr, "'<UNKNOWN TYPE>'"); /* TODO */
                break;
index b03540fb765c8647e17e4a707f44b4f5dcdb871d..004cf2fb7c7e7ebfeae584eca30e98c48ae9830d 100644 (file)
 
 extern ListBase global_ops; /* evil, temp use */
 
-
-
-/* This function is only used by operators right now
- * Its used for taking keyword args and filling in property values */
-int PYOP_props_from_dict(PointerRNA *ptr, PyObject *kw)
-{
-       int error_val = 0;
-       int totkw;
-       const char *arg_name= NULL;
-       PyObject *item;
-
-       PropertyRNA *prop, *iterprop;
-       CollectionPropertyIterator iter;
-
-       iterprop= RNA_struct_iterator_property(ptr->type);
-       RNA_property_collection_begin(ptr, iterprop, &iter);
-
-       totkw = kw ? PyDict_Size(kw):0;
-
-       for(; iter.valid; RNA_property_collection_next(&iter)) {
-               prop= iter.ptr.data;
-
-               arg_name= RNA_property_identifier(prop);
-
-               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, NULL, item)) {
-                       error_val= -1;
-                       break;
-               }
-
-               totkw--;
-       }
-
-       RNA_property_collection_end(&iter);
-
-       if (error_val==0 && totkw > 0) { /* some keywords were given that were not used :/ */
-               PyObject *key, *value;
-               Py_ssize_t pos = 0;
-
-               while (PyDict_Next(kw, &pos, &key, &value)) {
-                       arg_name= _PyUnicode_AsString(key);
-                       if (RNA_struct_find_property(ptr, arg_name) == NULL) break;
-                       arg_name= NULL;
-               }
-
-               PyErr_Format( PyExc_AttributeError, "argument \"%s\" unrecognized", arg_name ? arg_name : "<UNKNOWN>");
-               error_val = -1;
-       }
-
-       return error_val;
-}
-
 static PyObject *pyop_base_dir(PyObject *self);
 static PyObject *pyop_base_rna(PyObject *self, PyObject *pyname);
 static struct PyMethodDef pyop_base_methods[] = {
@@ -148,7 +81,7 @@ static PyObject *pyop_base_call( PyObject * self, PyObject * args,  PyObject * k
        
        WM_operator_properties_create(&ptr, opname);
        
-       error_val= PYOP_props_from_dict(&ptr, kw);
+       error_val= pyrna_pydict_to_props(&ptr, kw, "Converting py args to operator properties: ");
        
        if (error_val==0) {
                ReportList reports;
index c4741f936bfb5d81cf28e2b9a83af91d3a452f2e..46ea144fd4de006a59505293bdc7db6ee84d2649 100644 (file)
@@ -42,7 +42,4 @@ typedef struct {
 
 PyObject *BPY_operator_module(void);
 
-/* fill in properties from a python dict */
-int PYOP_props_from_dict(PointerRNA *ptr, PyObject *kw);
-
 #endif
index 43d62b3005fd84329503cae26dee1f870ada5afd..bf92db832afb6c3e7a58d7bb7f8c3c08e7f8eb35 100644 (file)
@@ -272,7 +272,7 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve
                 * thrown away anyway
                 *
                 * If we ever want to do this and use the props again,
-                * it can be done with - PYOP_props_from_dict(op->ptr, kw)
+                * it can be done with - pyrna_pydict_to_props(op->ptr, kw, "")
                 */
                
                Py_DECREF(ret);
index c1778faa1cdb87a024ef6a1f63cc3b24f37f84d2..d9a0d9408c70ab5ca4499af91f22c32f4c51f638 100644 (file)
@@ -204,6 +204,71 @@ PyObject * pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop)
        return ret;
 }
 
+/* This function is only used by operators right now
+ * Its used for taking keyword args and filling in property values */
+int pyrna_pydict_to_props(PointerRNA *ptr, PyObject *kw, const char *error_prefix)
+{
+       int error_val = 0;
+       int totkw;
+       const char *arg_name= NULL;
+       PyObject *item;
+
+       PropertyRNA *prop, *iterprop;
+       CollectionPropertyIterator iter;
+
+       iterprop= RNA_struct_iterator_property(ptr->type);
+       RNA_property_collection_begin(ptr, iterprop, &iter);
+
+       totkw = kw ? PyDict_Size(kw):0;
+
+       for(; iter.valid; RNA_property_collection_next(&iter)) {
+               prop= iter.ptr.data;
+
+               arg_name= RNA_property_identifier(prop);
+
+               if (strcmp(arg_name, "rna_type")==0) continue;
+
+               if (kw==NULL) {
+                       PyErr_Format( PyExc_AttributeError, "%s: no keywords, expected \"%s\"", error_prefix, arg_name ? arg_name : "<UNKNOWN>");
+                       error_val= -1;
+                       break;
+               }
+
+               item= PyDict_GetItemString(kw, arg_name);
+
+               if (item == NULL) {
+                       PyErr_Format( PyExc_AttributeError, "%s: keyword \"%s\" missing", error_prefix, arg_name ? arg_name : "<UNKNOWN>");
+                       error_val = -1; /* pyrna_py_to_prop sets the error */
+                       break;
+               }
+
+               if (pyrna_py_to_prop(ptr, prop, NULL, item)) {
+                       error_val= -1;
+                       break;
+               }
+
+               totkw--;
+       }
+
+       RNA_property_collection_end(&iter);
+
+       if (error_val==0 && totkw > 0) { /* some keywords were given that were not used :/ */
+               PyObject *key, *value;
+               Py_ssize_t pos = 0;
+
+               while (PyDict_Next(kw, &pos, &key, &value)) {
+                       arg_name= _PyUnicode_AsString(key);
+                       if (RNA_struct_find_property(ptr, arg_name) == NULL) break;
+                       arg_name= NULL;
+               }
+
+               PyErr_Format( PyExc_AttributeError, "%s: keyword \"%s\" unrecognized", error_prefix, arg_name ? arg_name : "<UNKNOWN>");
+               error_val = -1;
+       }
+
+       return error_val;
+}
+
 static PyObject * pyrna_func_call(PyObject * self, PyObject *args, PyObject *kw);
 
 PyObject *pyrna_func_to_py(PointerRNA *ptr, FunctionRNA *func)
@@ -447,9 +512,36 @@ int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *v
                        break;
                }
                case PROP_COLLECTION:
-                       PyErr_SetString(PyExc_AttributeError, "cant convert collections yet");
-                       return -1;
+               {
+                       int seq_len, i;
+                       PyObject *item;
+                       PointerRNA itemptr;
+                       
+                       /* convert a sequence of dict's into a collection */
+                       if(!PySequence_Check(value)) {
+                               PyErr_SetString(PyExc_TypeError, "expected a sequence of dicts for an RNA collection");
+                               return -1;
+                       }
+                       
+                       seq_len = PySequence_Length(value);
+                       for(i=0; i<seq_len; i++) {
+                               item= PySequence_GetItem(value, i);
+                               if(item==NULL || PyDict_Check(item)==0) {
+                                       PyErr_SetString(PyExc_TypeError, "expected a sequence of dicts for an RNA collection");
+                                       Py_XDECREF(item);
+                                       return -1;
+                               }
+                               
+                               RNA_property_collection_add(ptr, prop, &itemptr);
+                               if(pyrna_pydict_to_props(&itemptr, item, "Converting a python list to an RNA collection")==-1) {
+                                       Py_DECREF(item);
+                                       return -1;
+                               }
+                               Py_DECREF(item);
+                       }
+                       
                        break;
+               }
                default:
                        PyErr_SetString(PyExc_AttributeError, "unknown property type (pyrna_py_to_prop)");
                        return -1;
index a97d450fb2f01d00b1ff7e1c5d5d22e2fe010521..a2a3015912b09bb576a4a1bbcc215fc24dcefdf2 100644 (file)
@@ -69,6 +69,7 @@ PyObject *pyrna_prop_CreatePyObject( PointerRNA *ptr, PropertyRNA *prop );
 
 /* operators also need this to set args */
 int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *value);
+int pyrna_pydict_to_props(PointerRNA *ptr, PyObject *kw, const char *error_prefix);
 PyObject * pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop);
 
 /* functions for setting up new props - experemental */
index bbfb04719d84f0fcfcb5f1585eaa40e2dc762684..c15315ca350ce9f54d6b9e022eab473438744779 100644 (file)
@@ -78,7 +78,7 @@ static PyObject *Method_defButO( PyObject * self, PyObject * args )
        
        /* Optional python doctionary used to set python properties, just like how keyword args are used */
        if (py_keywords && PyDict_Size(py_keywords)) {
-               if (PYOP_props_from_dict(uiButGetOperatorPtrRNA(but), py_keywords) == -1)
+               if (pyrna_pydict_to_props(uiButGetOperatorPtrRNA(but), py_keywords, "") == -1)
                        return NULL;
        }
        
@@ -296,7 +296,7 @@ static PyObject *Method_registerKey( PyObject * self, PyObject * args )
        
        /* Optional python doctionary used to set python properties, just like how keyword args are used */
        if (py_keywords && PyDict_Size(py_keywords)) {
-               if (PYOP_props_from_dict(km->ptr, py_keywords) == -1)
+               if (pyrna_pydict_to_props(km->ptr, py_keywords, "Registering keybinding") == -1)
                        return NULL;
        }