New C/Py api utility function PyC_Err_Format_Prefix() which raises an error with...
authorCampbell Barton <ideasman42@gmail.com>
Thu, 15 Sep 2011 10:43:55 +0000 (10:43 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Thu, 15 Sep 2011 10:43:55 +0000 (10:43 +0000)
Use this to raise errors when assigning a string property fails even though the value to assign *is* a string.

Before:
  TypeError: bpy_struct: item.attr= val: Object.name expected a string type, not str

After:
  TypeError: bpy_struct: item.attr= val: Object.name error assigning string, UnicodeEncodeError('utf-8' codec can't encode character '\udce9' in position 23: surrogates not allowed)

source/blender/python/generic/py_capi_utils.c
source/blender/python/generic/py_capi_utils.h
source/blender/python/intern/bpy_rna.c

index a1571dc..d5bd44f 100644 (file)
@@ -208,6 +208,44 @@ PyObject *PyC_Object_GetAttrStringArgs(PyObject *o, Py_ssize_t n, ...)
        return item;
 }
 
+/* similar to PyErr_Format(),
+ *
+ * implimentation - we cant actually preprend the existing exception,
+ * because it could have _any_ argiments given to it, so instead we get its
+ * __str__ output and raise our own exception including it.
+ */
+PyObject *PyC_Err_Format_Prefix(PyObject *exception_type_prefix, const char *format, ...)
+{
+       PyObject *error_value_prefix;
+       va_list args;
+
+       va_start(args, format);
+       error_value_prefix= PyUnicode_FromFormatV(format, args); /* can fail and be NULL */
+       va_end(args);
+
+       if(PyErr_Occurred()) {
+               PyObject *error_type, *error_value, *error_traceback;
+               PyErr_Fetch(&error_type, &error_value, &error_traceback);
+               PyErr_Format(exception_type_prefix,
+                            "%S, %.200s(%S)",
+                            error_value_prefix,
+                            Py_TYPE(error_value)->tp_name,
+                            error_value
+                            );
+       }
+       else {
+               PyErr_SetObject(exception_type_prefix,
+                               error_value_prefix
+                               );
+       }
+
+       Py_XDECREF(error_value_prefix);
+
+       /* dumb to always return NULL but matches PyErr_Format */
+       return NULL;
+}
+
+
 /* returns the exception string as a new PyUnicode object, depends on external traceback module */
 #if 0
 
index 96c93ab..03a8637 100644 (file)
@@ -34,6 +34,7 @@ void                  PyC_ObSpit(const char *name, PyObject *var);
 void                   PyC_LineSpit(void);
 PyObject *             PyC_ExceptionBuffer(void);
 PyObject *             PyC_Object_GetAttrStringArgs(PyObject *o, Py_ssize_t n, ...);
+PyObject *             PyC_Err_Format_Prefix(PyObject *exception_type_prefix, const char *format, ...);
 void                   PyC_FileAndNum(const char **filename, int *lineno);
 int                            PyC_AsArray(void *array, PyObject *value, const int length, const PyTypeObject *type, const short is_double, const char *error_prefix);
 
index 4c382ef..a63cee4 100644 (file)
@@ -1525,10 +1525,22 @@ static int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyOb
 #endif // USE_STRING_COERCE
 
                        if (param==NULL) {
-                               PyErr_Format(PyExc_TypeError,
-                                            "%.200s %.200s.%.200s expected a string type, not %.200s",
-                                            error_prefix, RNA_struct_identifier(ptr->type),
-                                            RNA_property_identifier(prop), Py_TYPE(value)->tp_name);
+                               if(PyUnicode_Check(value)) {
+                                       /* there was an error assigning a string type,
+                                        * rather than setting a new error, prefix the existing one
+                                        */
+                                       PyC_Err_Format_Prefix(PyExc_TypeError,
+                                                             "%.200s %.200s.%.200s error assigning string",
+                                                                                 error_prefix, RNA_struct_identifier(ptr->type),
+                                                                                 RNA_property_identifier(prop));
+                               }
+                               else {
+                                       PyErr_Format(PyExc_TypeError,
+                                                                "%.200s %.200s.%.200s expected a string type, not %.200s",
+                                                                error_prefix, RNA_struct_identifier(ptr->type),
+                                                                RNA_property_identifier(prop), Py_TYPE(value)->tp_name);
+                               }
+
                                return -1;
                        }
                        else {
@@ -6427,14 +6439,11 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param
                         * no line number since the func has finished calling on error,
                         * re-raise the exception with more info since it would be slow to
                         * create prefix on every call (when there are no errors) */
-                       if(err == -1 && PyErr_Occurred()) {
-                               PyObject *error_type, *error_value, *error_traceback;
-                               PyErr_Fetch(&error_type, &error_value, &error_traceback);
-
-                               PyErr_Format(error_type,
-                                            "class %.200s, function %.200s: incompatible return value%S",
-                                            RNA_struct_identifier(ptr->type), RNA_function_identifier(func),
-                                            error_value);
+                       if(err == -1) {
+                               PyC_Err_Format_Prefix(PyExc_RuntimeError,
+                                                     "class %.200s, function %.200s: incompatible return value ",
+                                                             RNA_struct_identifier(ptr->type), RNA_function_identifier(func)
+                                                     );
                        }
                }
                else if (ret_len > 1) {