Ejemplo n.º 1
0
static PyObject *bpy_app_driver_dict_get(PyObject *UNUSED(self), void *UNUSED(closure))
{
	if (bpy_pydriver_Dict == NULL)
		if (bpy_pydriver_create_dict() != 0) {
			PyErr_SetString(PyExc_RuntimeError, "bpy.app.driver_namespace failed to create dictionary");
			return NULL;
	}

	Py_INCREF(bpy_pydriver_Dict);
	return bpy_pydriver_Dict;
}
Ejemplo n.º 2
0
/* This evals py driver expressions, 'expr' is a Python expression that
 * should evaluate to a float number, which is returned.
 *
 * note: PyGILState_Ensure() isnt always called because python can call the
 * bake operator which intern starts a thread which calls scene update which
 * does a driver update. to avoid a deadlock check PyThreadState_Get() if PyGILState_Ensure() is needed.
 */
float BPY_driver_exec(ChannelDriver *driver)
{
	PyObject *driver_vars=NULL;
	PyObject *retval= NULL;
	PyObject *expr_vars; /* speed up by pre-hashing string & avoids re-converting unicode strings for every execution */
	PyObject *expr_code;
	PyGILState_STATE gilstate;
	int use_gil;

	DriverVar *dvar;
	double result = 0.0; /* default return */
	char *expr = NULL;
	short targets_ok= 1;
	int i;

	/* get the py expression to be evaluated */
	expr = driver->expression;
	if ((expr == NULL) || (expr[0]=='\0'))
		return 0.0f;

	if(!(G.f & G_SCRIPT_AUTOEXEC)) {
		printf("skipping driver '%s', automatic scripts are disabled\n", driver->expression);
		return 0.0f;
	}

	use_gil= 1; //(PyThreadState_Get()==NULL);

	if(use_gil)
		gilstate = PyGILState_Ensure();

	/* init global dictionary for py-driver evaluation settings */
	if (!bpy_pydriver_Dict) {
		if (bpy_pydriver_create_dict() != 0) {
			fprintf(stderr, "Pydriver error: couldn't create Python dictionary");
			if(use_gil)
				PyGILState_Release(gilstate);
			return 0.0f;
		}
	}

	if(driver->expr_comp==NULL)
		driver->flag |= DRIVER_FLAG_RECOMPILE;

	/* compile the expression first if it hasn't been compiled or needs to be rebuilt */
	if(driver->flag & DRIVER_FLAG_RECOMPILE) {
		Py_XDECREF(driver->expr_comp);
		driver->expr_comp= PyTuple_New(2);

		expr_code= Py_CompileString(expr, "<bpy driver>", Py_eval_input);
		PyTuple_SET_ITEM(((PyObject *)driver->expr_comp), 0, expr_code);

		driver->flag &= ~DRIVER_FLAG_RECOMPILE;
		driver->flag |= DRIVER_FLAG_RENAMEVAR; /* maybe this can be removed but for now best keep until were sure */
	}
	else {
		expr_code= PyTuple_GET_ITEM(((PyObject *)driver->expr_comp), 0);
	}

	if(driver->flag & DRIVER_FLAG_RENAMEVAR) {
		/* may not be set */
		expr_vars= PyTuple_GET_ITEM(((PyObject *)driver->expr_comp), 1);
		Py_XDECREF(expr_vars);

		/* intern the arg names so creating the namespace for every run is faster */
		expr_vars= PyTuple_New(BLI_countlist(&driver->variables));
		PyTuple_SET_ITEM(((PyObject *)driver->expr_comp), 1, expr_vars);

		for (dvar= driver->variables.first, i=0; dvar; dvar= dvar->next) {
			PyTuple_SET_ITEM(expr_vars, i++, PyUnicode_InternFromString(dvar->name));
		}
		
		driver->flag &= ~DRIVER_FLAG_RENAMEVAR;
	}
	else {
		expr_vars= PyTuple_GET_ITEM(((PyObject *)driver->expr_comp), 1);
	}

	/* add target values to a dict that will be used as '__locals__' dict */
	driver_vars = PyDict_New(); // XXX do we need to decref this?
	for (dvar= driver->variables.first, i=0; dvar; dvar= dvar->next) {
		PyObject *driver_arg = NULL;
		float tval = 0.0f;
		
		/* try to get variable value */
		tval= driver_get_variable_value(driver, dvar);
		driver_arg= PyFloat_FromDouble((double)tval);
		
		/* try to add to dictionary */
		/* if (PyDict_SetItemString(driver_vars, dvar->name, driver_arg)) { */
		if (PyDict_SetItem(driver_vars, PyTuple_GET_ITEM(expr_vars, i++), driver_arg) < 0) { /* use string interning for faster namespace creation */
			/* this target failed - bad name */
			if (targets_ok) {
				/* first one - print some extra info for easier identification */
				fprintf(stderr, "\nBPY_driver_eval() - Error while evaluating PyDriver:\n");
				targets_ok= 0;
			}
			
			fprintf(stderr, "\tBPY_driver_eval() - couldn't add variable '%s' to namespace\n", dvar->name);
			// BPy_errors_to_report(NULL); // TODO - reports
			PyErr_Print();
			PyErr_Clear();
		}
	}

#if 0 // slow, with this can avoid all Py_CompileString above.
	/* execute expression to get a value */
	retval = PyRun_String(expr, Py_eval_input, bpy_pydriver_Dict, driver_vars);
#else
	/* evaluate the compiled expression */
	if (expr_code)
		retval= PyEval_EvalCode((void *)expr_code, bpy_pydriver_Dict, driver_vars);
#endif

	/* decref the driver vars first...  */
	Py_DECREF(driver_vars);

	/* process the result */
	if (retval == NULL) {
		pydriver_error(driver);
	} else if((result= PyFloat_AsDouble(retval)) == -1.0 && PyErr_Occurred()) {
		pydriver_error(driver);
		Py_DECREF(retval);
		result = 0.0;
	}
	else {
		/* all fine, make sure the "invalid expression" flag is cleared */
		driver->flag &= ~DRIVER_FLAG_INVALID;
		Py_DECREF(retval);
	}

	if(use_gil)
		PyGILState_Release(gilstate);
    
	if(finite(result)) {
		return (float)result;
	}
	else {
		fprintf(stderr, "\tBPY_driver_eval() - driver '%s' evaluates to '%f'\n", dvar->name, result);
		return 0.0f;
	}
}