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; }
/* 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; } }