[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [20873] branches/blender2.5/blender/source : Blender/Python API

Campbell Barton ideasman42 at gmail.com
Sun Jun 14 14:53:49 CEST 2009


Revision: 20873
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=20873
Author:   campbellbarton
Date:     2009-06-14 14:53:47 +0200 (Sun, 14 Jun 2009)

Log Message:
-----------
Blender/Python API
Send the full python stack trace to the reporting api,
added BPY_exception_buffer which temporarily overrides sys.stdout and sys.stderr to get the output (uses the io module in py3 StringIO in py2 to avoid writing into a real file), pity the Py/C api has no function to do this.

fix for crash when showing menu's that have no items.

Modified Paths:
--------------
    branches/blender2.5/blender/source/blender/editors/interface/interface_regions.c
    branches/blender2.5/blender/source/blender/editors/space_script/script_edit.c
    branches/blender2.5/blender/source/blender/editors/space_text/text_ops.c
    branches/blender2.5/blender/source/blender/python/BPY_extern.h
    branches/blender2.5/blender/source/blender/python/intern/bpy_interface.c
    branches/blender2.5/blender/source/blender/python/intern/bpy_operator_wrap.c
    branches/blender2.5/blender/source/blender/python/intern/bpy_util.c
    branches/blender2.5/blender/source/blender/python/intern/bpy_util.h
    branches/blender2.5/blender/source/creator/creator.c

Modified: branches/blender2.5/blender/source/blender/editors/interface/interface_regions.c
===================================================================
--- branches/blender2.5/blender/source/blender/editors/interface/interface_regions.c	2009-06-14 10:59:54 UTC (rev 20872)
+++ branches/blender2.5/blender/source/blender/editors/interface/interface_regions.c	2009-06-14 12:53:47 UTC (rev 20873)
@@ -1948,6 +1948,9 @@
 	md= decompose_menu_string(info->instr);
 
 	rows= md->nitems;
+	if(rows<1)
+		rows= 1;
+	
 	columns= 1;
 
 	/* size and location, title slightly bigger for bold */

Modified: branches/blender2.5/blender/source/blender/editors/space_script/script_edit.c
===================================================================
--- branches/blender2.5/blender/source/blender/editors/space_script/script_edit.c	2009-06-14 10:59:54 UTC (rev 20872)
+++ branches/blender2.5/blender/source/blender/editors/space_script/script_edit.c	2009-06-14 12:53:47 UTC (rev 20873)
@@ -62,15 +62,17 @@
 static int run_pyfile_exec(bContext *C, wmOperator *op)
 {
 	ARegion *ar= CTX_wm_region(C);
+	
 
 	char filename[512];
 	RNA_string_get(op->ptr, "filename", filename);
 #ifndef DISABLE_PYTHON
-	BPY_run_python_script(C, filename, NULL);
+	if(BPY_run_python_script(C, filename, NULL, op->reports)) {
+		ED_region_tag_redraw(ar);
+		return OPERATOR_FINISHED;
+	}
 #endif
-	ED_region_tag_redraw(ar);
-
-	return OPERATOR_FINISHED;
+	return OPERATOR_CANCELLED; /* FAIL */
 }
 
 void SCRIPT_OT_python_file_run(wmOperatorType *ot)

Modified: branches/blender2.5/blender/source/blender/editors/space_text/text_ops.c
===================================================================
--- branches/blender2.5/blender/source/blender/editors/space_text/text_ops.c	2009-06-14 10:59:54 UTC (rev 20872)
+++ branches/blender2.5/blender/source/blender/editors/space_text/text_ops.c	2009-06-14 12:53:47 UTC (rev 20873)
@@ -521,7 +521,7 @@
 #else
 	Text *text= CTX_data_edit_text(C);
 
-	if (BPY_run_python_script( C, NULL, text ))
+	if (BPY_run_python_script(C, NULL, text, op->reports))
 		return OPERATOR_FINISHED;
 	
 	/* Dont report error messages while live editing */

Modified: branches/blender2.5/blender/source/blender/python/BPY_extern.h
===================================================================
--- branches/blender2.5/blender/source/blender/python/BPY_extern.h	2009-06-14 10:59:54 UTC (rev 20872)
+++ branches/blender2.5/blender/source/blender/python/BPY_extern.h	2009-06-14 12:53:47 UTC (rev 20873)
@@ -97,7 +97,7 @@
 	int BPY_menu_invoke( struct BPyMenu *pym, short menutype );
 	
 	/* 2.5 UI Scripts */
-	int BPY_run_python_script( struct bContext *C, const char *filename, struct Text *text ); // 2.5 working
+	int BPY_run_python_script( struct bContext *C, const char *filename, struct Text *text, struct ReportList *reports ); // 2.5 working
 	int BPY_run_script_space_draw(struct bContext *C, struct SpaceScript * sc); // 2.5 working
 	void BPY_run_ui_scripts(struct bContext *C, int reload);
 //	int BPY_run_script_space_listener(struct bContext *C, struct SpaceScript * sc, struct ARegion *ar, struct wmNotifier *wmn); // 2.5 working

Modified: branches/blender2.5/blender/source/blender/python/intern/bpy_interface.c
===================================================================
--- branches/blender2.5/blender/source/blender/python/intern/bpy_interface.c	2009-06-14 10:59:54 UTC (rev 20872)
+++ branches/blender2.5/blender/source/blender/python/intern/bpy_interface.c	2009-06-14 12:53:47 UTC (rev 20873)
@@ -150,7 +150,7 @@
 }
 
 /* Can run a file or text block */
-int BPY_run_python_script( bContext *C, const char *fn, struct Text *text )
+int BPY_run_python_script( bContext *C, const char *fn, struct Text *text, struct ReportList *reports)
 {
 	PyObject *py_dict, *py_result;
 	PyGILState_STATE gilstate;
@@ -178,7 +178,7 @@
 			MEM_freeN( buf );
 
 			if( PyErr_Occurred(  ) ) {
-				PyErr_Print(); PyErr_Clear();
+				BPy_errors_to_report(reports);
 				BPY_free_compiled_text( text );
 				PyGILState_Release(gilstate);
 				return 0;
@@ -194,7 +194,7 @@
 	}
 	
 	if (!py_result) {
-		PyErr_Print(); PyErr_Clear();
+		BPy_errors_to_report(reports);
 	} else {
 		Py_DECREF( py_result );
 	}
@@ -221,7 +221,7 @@
 	script = sc->script;
 
 	if( err ) {
-		PyErr_Print(); PyErr_Clear();
+		BPy_errors_to_report(NULL); // TODO, reports
 		script->flags = 0;	/* mark script struct for deletion */
 		SCRIPT_SET_NULL(script);
 		script->scriptname[0] = '\0';
@@ -250,7 +250,7 @@
 		return 0;
 	
 	if (sc->script->py_draw==NULL && sc->script->scriptname[0] != '\0')
-		BPY_run_python_script(C, sc->script->scriptname, NULL);
+		BPY_run_python_script(C, sc->script->scriptname, NULL, NULL);
 		
 	if (sc->script->py_draw==NULL)
 		return 0;
@@ -329,7 +329,7 @@
 	}
 	
 	if (!py_result) {
-		PyErr_Print(); PyErr_Clear();
+		BPy_errors_to_report(NULL); // TODO - reports
 	} else
 		Py_DECREF( py_result );
 	
@@ -410,7 +410,7 @@
 			if(mod) {
 				Py_DECREF(mod); /* could be NULL from reloading */
 			} else {
-				PyErr_Print(); PyErr_Clear();
+				BPy_errors_to_report(NULL); // TODO - reports
 				fprintf(stderr, "unable to import \"%s\"  %s/%s\n", path, dirname, de->d_name);
 			}
 		}
@@ -530,7 +530,7 @@
 	driver->flag |= DRIVER_FLAG_INVALID; /* py expression failed */
 	fprintf(stderr, "\nError in Driver: The following Python expression failed:\n\t'%s'\n\n", driver->expression);
 	
-	PyErr_Print(); PyErr_Clear();
+	BPy_errors_to_report(NULL); // TODO - reports
 
 	return 0.0f;
 }
@@ -589,7 +589,7 @@
 			}
 			
 			fprintf(stderr, "\tBPY_pydriver_eval() - couldn't add variable '%s' to namespace \n", dtar->name);
-			PyErr_Print(); PyErr_Clear();
+			BPy_errors_to_report(NULL); // TODO - reports
 		}
 	}
 	

Modified: branches/blender2.5/blender/source/blender/python/intern/bpy_operator_wrap.c
===================================================================
--- branches/blender2.5/blender/source/blender/python/intern/bpy_operator_wrap.c	2009-06-14 10:59:54 UTC (rev 20872)
+++ branches/blender2.5/blender/source/blender/python/intern/bpy_operator_wrap.c	2009-06-14 12:53:47 UTC (rev 20873)
@@ -137,54 +137,6 @@
 	return dict;
 }
 
-/* TODO - a whole traceback would be ideal */
-static void pyop_error_report(ReportList *reports)
-{
-	const char *string;
-	PyObject *exception, *v, *tb;
-	PyErr_Fetch(&exception, &v, &tb);
-	if (exception == NULL)
-		return;
-	
-	/* get the string from the exception */
-	if(v==NULL) {
-		string= "py exception not set";
-	}
-	else if(string = _PyUnicode_AsString(v)) {
-		/* do nothing */
-	}
-	else { /* a valid PyObject but not a string, try get its string value */
-		PyObject *repr;
-		
-		Py_INCREF(v); /* incase clearing the error below somehow frees this */
-		PyErr_Clear();
-		
-		repr= PyObject_Repr(v);
-		
-		if(repr==NULL) {
-			PyErr_Clear();
-			string= "py exception found but can't be converted";
-		}
-		else {
-			string = _PyUnicode_AsString(repr);
-			Py_DECREF(repr);
-			
-			if(string==NULL) { /* unlikely to happen */
-				PyErr_Clear();
-				string= "py exception found but can't be converted";
-			}
-		}
-		
-		Py_DECREF(v); /* finished dealing with v, PyErr_Clear isnt called anymore so can decref it */
-	}
-	/* done getting the string */
-	
-	/* Now we know v != NULL too */
-	BKE_report(reports, RPT_ERROR, string);
-	
-	PyErr_Print();
-}
-
 static struct BPY_flag_def pyop_ret_flags[] = {
 	{"RUNNING_MODAL", OPERATOR_RUNNING_MODAL},
 	{"CANCELLED", OPERATOR_CANCELLED},
@@ -291,13 +243,13 @@
 	}
 	
 	if (ret == NULL) { /* covers py_class_instance failing too */
-		pyop_error_report(op->reports);
+		BPy_errors_to_report(op->reports);
 	}
 	else {
 		if (mode==PYOP_POLL) {
 			if (PyBool_Check(ret) == 0) {
 				PyErr_SetString(PyExc_ValueError, "Python poll function return value ");
-				pyop_error_report(op->reports);
+				BPy_errors_to_report(op->reports);
 			}
 			else {
 				ret_flag= ret==Py_True ? 1:0;
@@ -305,7 +257,7 @@
 			
 		} else if (BPY_flag_from_seq(pyop_ret_flags, ret, &ret_flag) == -1) {
 			 /* the returned value could not be converted into a flag */
-			pyop_error_report(op->reports);
+			BPy_errors_to_report(op->reports);
 			
 		}
 		/* there is no need to copy the py keyword dict modified by

Modified: branches/blender2.5/blender/source/blender/python/intern/bpy_util.c
===================================================================
--- branches/blender2.5/blender/source/blender/python/intern/bpy_util.c	2009-06-14 10:59:54 UTC (rev 20872)
+++ branches/blender2.5/blender/source/blender/python/intern/bpy_util.c	2009-06-14 12:53:47 UTC (rev 20873)
@@ -168,6 +168,12 @@
 		PyObject_Print(var, stderr, 0);
 		fprintf(stderr, " ref:%d ", var->ob_refcnt);
 		fprintf(stderr, " ptr:%ld", (long)var);
+		
+		fprintf(stderr, " type:");
+		if(Py_TYPE(var))
+			fprintf(stderr, "%s", Py_TYPE(var)->tp_name);
+		else
+			fprintf(stderr, "<NIL>");
 	}
 	fprintf(stderr, "\n");
 }
@@ -329,6 +335,72 @@
 	return 0;
 }
 
+
+
+/* returns the exception string as a new PyUnicode object, depends on external StringIO module */
+PyObject *BPY_exception_buffer(void)
+{
+	PyObject *stdout_backup = PySys_GetObject("stdout"); /* borrowed */
+	PyObject *stderr_backup = PySys_GetObject("stderr"); /* borrowed */
+	PyObject *string_io = NULL;
+	PyObject *string_io_buf = NULL;
+	PyObject *string_io_mod;
+	PyObject *string_io_getvalue;
+	
+	PyObject *error_type, *error_value, *error_traceback;
+	
+	if (!PyErr_Occurred())
+		return NULL;
+	
+	PyErr_Fetch(&error_type, &error_value, &error_traceback);
+	
+	PyErr_Clear();
+	
+	/* import StringIO / io
+	 * string_io = StringIO.StringIO()
+	 */
+	
+#if PY_VERSION_HEX < 0x03000000
+	if(! (string_io_mod= PyImport_ImportModule("StringIO")) ) {
+#else
+	if(! (string_io_mod= PyImport_ImportModule("io")) ) {
+#endif
+		return NULL;
+	} else if (! (string_io = PyObject_CallMethod(string_io_mod, "StringIO", NULL))) {
+		Py_DECREF(string_io_mod);
+		return NULL;
+	} else if (! (string_io_getvalue= PyObject_GetAttrString(string_io, "getvalue"))) {
+		Py_DECREF(string_io_mod);
+		Py_DECREF(string_io);
+		return NULL;
+	}
+	
+	Py_INCREF(stdout_backup); // since these were borrowed we dont want them freed when replaced.
+	Py_INCREF(stderr_backup);
+	
+	PySys_SetObject("stdout", string_io); // both of these are free'd when restoring
+	PySys_SetObject("stderr", string_io);
+	
+	PyErr_Restore(error_type, error_value, error_traceback);
+	PyErr_Print(); /* print the error */
+	PyErr_Clear();
+	
+	string_io_buf = PyObject_CallObject(string_io_getvalue, NULL);
+	

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list