python access to driver namespace, rather then have a textblock defined for drivers allow scripts to add functions directly.

- bpy.app.driver_namespace, read-only dictionary, edit in-place.
- reset on file load and new file.
- on errors the namespace used to be reset, this should not be needed.

simple example.

  def driverFunc(val):
    return val * val
  bpy.app.driver_namespace['driverFunc'] = driverFunc

... now all drivers can access this function.
This commit is contained in:
Campbell Barton 2010-11-27 02:39:51 +00:00
parent 4a804855b2
commit 02cc80691d
7 changed files with 38 additions and 14 deletions

@ -118,7 +118,7 @@ extern "C" {
// int BPY_do_spacehandlers(struct ScrArea *sa, unsigned short event,
// short eventValue, unsigned short space_event);
//
// void BPY_pydriver_update(void);
void BPY_reset_driver(void);
float BPY_eval_driver(struct ChannelDriver *driver);
//
int BPY_eval_button(struct bContext *C, const char *expr, double *value);

@ -159,15 +159,34 @@ static PyObject *bpy_app_tempdir_get(PyObject *UNUSED(self), void *UNUSED(closur
return PyC_UnicodeFromByte(btempdir);
}
PyGetSetDef bpy_app_debug_getset= {"debug", bpy_app_debug_get, bpy_app_debug_set, "Boolean, set when blender is running in debug mode (started with -d)", NULL};
PyGetSetDef bpy_app_tempdir_getset= {"tempdir", bpy_app_tempdir_get, NULL, "String, the temp directory used by blender (read-only)", NULL};
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;
}
PyGetSetDef bpy_app_getsets[]= {
{"debug", bpy_app_debug_get, bpy_app_debug_set, "Boolean, set when blender is running in debug mode (started with -d)", NULL},
{"tempdir", bpy_app_tempdir_get, NULL, "String, the temp directory used by blender (read-only)", NULL},
{"driver_namespace", bpy_app_driver_dict_get, NULL, "Dictionary for drivers namespace, editable in-place, reset on file load (read-only)", NULL},
{NULL, NULL, NULL, NULL, NULL}
};
static void py_struct_seq_getset_init(void)
{
/* tricky dynamic members, not to py-spec! */
PyDict_SetItemString(BlenderAppType.tp_dict, bpy_app_debug_getset.name, PyDescr_NewGetSet(&BlenderAppType, &bpy_app_debug_getset));
PyDict_SetItemString(BlenderAppType.tp_dict, bpy_app_tempdir_getset.name, PyDescr_NewGetSet(&BlenderAppType, &bpy_app_tempdir_getset));
PyGetSetDef *getset;
for(getset= bpy_app_getsets; getset->name; getset++) {
PyDict_SetItemString(BlenderAppType.tp_dict, getset->name, PyDescr_NewGetSet(&BlenderAppType, getset));
}
}
/* end dynamic bpy.app */

@ -28,4 +28,8 @@
PyObject *BPY_app_struct( void );
/* bpy_driver.c */
int bpy_pydriver_create_dict(void);
extern PyObject *bpy_pydriver_Dict;
#endif

@ -40,7 +40,7 @@ PyObject *bpy_pydriver_Dict = NULL;
/* For faster execution we keep a special dictionary for pydrivers, with
* the needed modules and aliases.
*/
static int bpy_pydriver_create_dict(void)
int bpy_pydriver_create_dict(void)
{
PyObject *d, *mod;
@ -103,7 +103,7 @@ static int bpy_pydriver_create_dict(void)
* reloading the Blender text module "pydrivers.py", if available, so
* updates in it reach pydriver evaluation.
*/
void BPY_pydriver_update(void)
void BPY_reset_driver(void)
{
PyGILState_STATE gilstate;
int use_gil= 1; // (PyThreadState_Get()==NULL);
@ -126,12 +126,6 @@ void BPY_pydriver_update(void)
/* error return function for BPY_eval_pydriver */
static float pydriver_error(ChannelDriver *driver)
{
if (bpy_pydriver_Dict) { /* free the global dict used by pydrivers */
PyDict_Clear(bpy_pydriver_Dict);
Py_DECREF(bpy_pydriver_Dict);
bpy_pydriver_Dict = NULL;
}
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);

@ -319,6 +319,7 @@ void WM_read_file(bContext *C, const char *name, ReportList *reports)
#ifdef WITH_PYTHON
/* run any texts that were loaded in and flagged as modules */
BPY_reset_driver();
BPY_load_user_modules(C);
#endif
CTX_wm_window_set(C, NULL); /* exits queues */
@ -410,6 +411,9 @@ int WM_read_homefile(bContext *C, wmOperator *op)
if(CTX_py_init_get(C)) {
/* sync addons, these may have changed from the defaults */
BPY_eval_string(C, "__import__('bpy').utils.addon_reset_all()");
BPY_reset_driver();
BPY_load_user_modules(C);
}
#endif

@ -146,6 +146,8 @@ void WM_init(bContext *C, int argc, char **argv)
#ifdef WITH_PYTHON
BPY_set_context(C); /* necessary evil */
BPY_start_python(argc, argv);
BPY_reset_driver();
BPY_load_user_modules(C);
#else
(void)argc; /* unused */

@ -926,6 +926,7 @@ static int load_file(int UNUSED(argc), char **argv, void *data)
/* WM_read_file() runs normally but since we're in background mode do here */
#ifdef WITH_PYTHON
/* run any texts that were loaded in and flagged as modules */
BPY_reset_driver();
BPY_load_user_modules(C);
#endif