diff --git a/src/python.c b/src/python.c
index 1fda642de3683803242eee0185db118f9b31b3d9..a68e374cd5bd688aee19ace1b6dbd8f8cdad954e 100644 (file)
--- a/src/python.c
+++ b/src/python.c
#include <Python.h>
#include <structmember.h>
#include <Python.h>
#include <structmember.h>
+#if HAVE_PTHREAD_H
+# include <pthread.h>
+#endif
+
#include "collectd.h"
#include "common.h"
#include "collectd.h"
#include "common.h"
+#include "cpython.h"
+
typedef struct cpy_callback_s {
char *name;
PyObject *callback;
typedef struct cpy_callback_s {
char *name;
PyObject *callback;
struct cpy_callback_s *next;
} cpy_callback_t;
struct cpy_callback_s *next;
} cpy_callback_t;
+static int do_interactive = 0;
+
/* This is our global thread state. Python saves some stuff in thread-local
* storage. So if we allow the interpreter to run in the background
* (the scriptwriters might have created some threads from python), we have
/* This is our global thread state. Python saves some stuff in thread-local
* storage. So if we allow the interpreter to run in the background
* (the scriptwriters might have created some threads from python), we have
static PyThreadState *state;
static PyThreadState *state;
-/* Serves the same purpose as PyEval_ThreadsInitialized but doesn't require
- * Python 2.4. */
-
-static int cpy_have_threads;
-
-/* These two macros are basicly Py_BEGIN_ALLOW_THREADS and Py_BEGIN_ALLOW_THREADS
- * from the other direction. If a Python thread calls a C function
- * Py_BEGIN_ALLOW_THREADS is used to allow other python threads to run because
- * we don't intend to call any Python functions.
- *
- * These two macros are used whenever a C thread intends to call some Python
- * function, usually because some registered callback was triggered.
- * Just like Py_BEGIN_ALLOW_THREADS it opens a block so these macros have to be
- * used in pairs. They aquire the GIL, create a new Python thread state and swap
- * the current thread state with the new one. This means this thread is now allowed
- * to execute Python code. */
-
-#define CPY_LOCK_THREADS {\
- PyGILState_STATE gil_state;\
- if (cpy_have_threads)\
- gil_state = PyGILState_Ensure();
-
-#define CPY_RELEASE_THREADS \
- if (cpy_have_threads)\
- PyGILState_Release(gil_state);\
-}
-
-
static cpy_callback_t *cpy_config_callbacks;
static cpy_callback_t *cpy_init_callbacks;
static cpy_callback_t *cpy_shutdown_callbacks;
static cpy_callback_t *cpy_config_callbacks;
static cpy_callback_t *cpy_init_callbacks;
static cpy_callback_t *cpy_shutdown_callbacks;
free(c);
}
free(c);
}
+/* You must hold the GIL to call this function!
+ * But if you managed to extract the callback parameter then you probably already do. */
+
+static void cpy_build_name(char *buf, size_t size, PyObject *callback, const char *name) {
+ const char *module;
+ PyObject *mod = NULL, *n = NULL;
+
+ if (name != NULL && strchr(name, '.') != NULL) {
+ snprintf(buf, size, "python.%s", name);
+ return;
+ }
+
+ mod = PyObject_GetAttrString(callback, "__module__"); /* New reference. */
+ if (mod != NULL)
+ module = PyString_AsString(mod);
+ else
+ module = "collectd";
+ if (name != NULL) {
+ snprintf(buf, size, "python.%s.%s", module, name);
+ Py_XDECREF(mod);
+ return;
+ }
+
+ n = PyObject_GetAttrString(callback, "__name__"); /* New reference. */
+ if (n != NULL)
+ name = PyString_AsString(n);
+
+ if (name != NULL)
+ snprintf(buf, size, "python.%s.%s", module, name);
+ else
+ snprintf(buf, size, "python.%s.%p", module, callback);
+ Py_XDECREF(mod);
+ Py_XDECREF(n);
+}
+
+static int cpy_read_callback(user_data_t *data) {
+ cpy_callback_t *c = data->data;
+ PyObject *ret;
+
+ CPY_LOCK_THREADS
+ ret = PyObject_CallFunctionObjArgs(c->callback, c->data, (void *) 0); /* New reference. */
+ if (ret == NULL) {
+ /* FIXME */
+ PyErr_Print();
+ } else {
+ Py_DECREF(ret);
+ }
+ CPY_RELEASE_THREADS
+ return 0;
+}
+
+static int cpy_write_callback(const data_set_t *ds, const value_list_t *value_list, user_data_t *data) {
+ int i;
+ cpy_callback_t *c = data->data;
+ PyObject *ret, *v, *list;
+
+ CPY_LOCK_THREADS
+ list = PyList_New(value_list->values_len); /* New reference. */
+ if (list == NULL) {
+ PyErr_Print();
+ CPY_RETURN_FROM_THREADS 0;
+ }
+ for (i = 0; i < value_list->values_len; ++i) {
+ if (ds->ds->type == DS_TYPE_COUNTER) {
+ if ((long) value_list->values[i].counter == value_list->values[i].counter)
+ PyList_SetItem(list, i, PyInt_FromLong(value_list->values[i].counter));
+ else
+ PyList_SetItem(list, i, PyLong_FromUnsignedLongLong(value_list->values[i].counter));
+ } else if (ds->ds->type == DS_TYPE_GAUGE) {
+ PyList_SetItem(list, i, PyFloat_FromDouble(value_list->values[i].gauge));
+ } else if (ds->ds->type == DS_TYPE_DERIVE) {
+ if ((long) value_list->values[i].derive == value_list->values[i].derive)
+ PyList_SetItem(list, i, PyInt_FromLong(value_list->values[i].derive));
+ else
+ PyList_SetItem(list, i, PyLong_FromLongLong(value_list->values[i].derive));
+ } else if (ds->ds->type == DS_TYPE_ABSOLUTE) {
+ if ((long) value_list->values[i].absolute == value_list->values[i].absolute)
+ PyList_SetItem(list, i, PyInt_FromLong(value_list->values[i].absolute));
+ else
+ PyList_SetItem(list, i, PyLong_FromUnsignedLongLong(value_list->values[i].absolute));
+ } else {
+ ERROR("cpy_write_callback: Unknown value type %d.", ds->ds->type);
+ Py_DECREF(list);
+ CPY_RETURN_FROM_THREADS 0;
+ }
+ if (PyErr_Occurred() != NULL) {
+ PyErr_Print();
+ CPY_RETURN_FROM_THREADS 0;
+ }
+ }
+ v = PyObject_CallFunction((PyObject *) &ValuesType, "sOssssdi", value_list->type, list,
+ value_list->plugin_instance, value_list->type_instance, value_list->plugin,
+ value_list->host, (double) value_list->time, value_list->interval);
+ Py_DECREF(list);
+ ret = PyObject_CallFunctionObjArgs(c->callback, v, c->data, (void *) 0); /* New reference. */
+ if (ret == NULL) {
+ /* FIXME */
+ PyErr_Print();
+ } else {
+ Py_DECREF(ret);
+ }
+ CPY_RELEASE_THREADS
+ return 0;
+}
+
static void cpy_log_callback(int severity, const char *message, user_data_t *data) {
cpy_callback_t * c = data->data;
PyObject *ret;
static void cpy_log_callback(int severity, const char *message, user_data_t *data) {
cpy_callback_t * c = data->data;
PyObject *ret;
@@ -77,134 +162,10 @@ static void cpy_log_callback(int severity, const char *message, user_data_t *dat
CPY_RELEASE_THREADS
}
CPY_RELEASE_THREADS
}
-typedef struct {
- PyObject_HEAD /* No semicolon! */
- PyObject *parent;
- PyObject *key;
- PyObject *values;
- PyObject *children;
-} Config;
-
-static void Config_dealloc(PyObject *s) {
- Config *self = (Config *) s;
-
- Py_XDECREF(self->parent);
- Py_XDECREF(self->key);
- Py_XDECREF(self->values);
- Py_XDECREF(self->children);
- self->ob_type->tp_free(s);
-}
-
-static PyObject *Config_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
- Config *self;
-
- self = (Config *) type->tp_alloc(type, 0);
- if (self == NULL)
- return NULL;
-
- self->parent = NULL;
- self->key = NULL;
- self->values = NULL;
- self->children = NULL;
- return (PyObject *) self;
-}
-
-static int Config_init(PyObject *s, PyObject *args, PyObject *kwds) {
- PyObject *key = NULL, *parent = NULL, *values = NULL, *children = NULL, *tmp;
- Config *self = (Config *) s;
- static char *kwlist[] = {"key", "parent", "values", "children", NULL};
-
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "S|OOO", kwlist,
- &key, &parent, &values, &children))
- return -1;
-
- if (values == NULL) {
- values = PyTuple_New(0);
- PyErr_Clear();
- }
- if (children == NULL) {
- children = PyTuple_New(0);
- PyErr_Clear();
- }
- tmp = self->key;
- Py_INCREF(key);
- self->key = key;
- Py_XDECREF(tmp);
- if (parent != NULL) {
- tmp = self->parent;
- Py_INCREF(parent);
- self->parent = parent;
- Py_XDECREF(tmp);
- }
- if (values != NULL) {
- tmp = self->values;
- Py_INCREF(values);
- self->values = values;
- Py_XDECREF(tmp);
- }
- if (children != NULL) {
- tmp = self->children;
- Py_INCREF(children);
- self->children = children;
- Py_XDECREF(tmp);
- }
- return 0;
-}
-
-static PyMemberDef Config_members[] = {
- {"Parent", T_OBJECT, offsetof(Config, parent), 0, "Parent node"},
- {"Key", T_OBJECT_EX, offsetof(Config, key), 0, "Keyword of this node"},
- {"Values", T_OBJECT_EX, offsetof(Config, values), 0, "Values after the key"},
- {"Children", T_OBJECT_EX, offsetof(Config, children), 0, "Childnodes of this node"},
- {NULL}
-};
-
-static PyTypeObject ConfigType = {
- PyObject_HEAD_INIT(NULL)
- 0, /* Always 0 */
- "collectd.Config", /* tp_name */
- sizeof(Config), /* tp_basicsize */
- 0, /* Will be filled in later */
- Config_dealloc, /* tp_dealloc */
- 0, /* tp_print */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_compare */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
- "Cool help text later", /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- 0, /* tp_methods */
- Config_members, /* tp_members */
- 0, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- Config_init, /* tp_init */
- 0, /* tp_alloc */
- Config_new /* tp_new */
-};
-
static PyObject *cpy_register_generic(cpy_callback_t **list_head, PyObject *args, PyObject *kwds) {
cpy_callback_t *c;
const char *name = NULL;
static PyObject *cpy_register_generic(cpy_callback_t **list_head, PyObject *args, PyObject *kwds) {
cpy_callback_t *c;
const char *name = NULL;
- PyObject *callback = NULL, *data = NULL;
+ PyObject *callback = NULL, *data = NULL, *mod = NULL;
static char *kwlist[] = {"callback", "data", "name", NULL};
if (PyArg_ParseTupleAndKeywords(args, kwds, "O|Oz", kwlist, &callback, &data, &name) == 0) return NULL;
static char *kwlist[] = {"callback", "data", "name", NULL};
if (PyArg_ParseTupleAndKeywords(args, kwds, "O|Oz", kwlist, &callback, &data, &name) == 0) return NULL;
@@ -213,11 +174,10 @@ static PyObject *cpy_register_generic(cpy_callback_t **list_head, PyObject *args
return NULL;
}
if (name == NULL) {
return NULL;
}
if (name == NULL) {
- PyObject *mod;
-
- mod = PyObject_GetAttrString(callback, "__module__");
+ mod = PyObject_GetAttrString(callback, "__module__"); /* New reference. */
if (mod != NULL) name = PyString_AsString(mod);
if (name == NULL) {
if (mod != NULL) name = PyString_AsString(mod);
if (name == NULL) {
+ Py_XDECREF(mod);
PyErr_SetString(PyExc_ValueError, "No module name specified and "
"callback function does not have a \"__module__\" attribute.");
return NULL;
PyErr_SetString(PyExc_ValueError, "No module name specified and "
"callback function does not have a \"__module__\" attribute.");
return NULL;
@@ -231,6 +191,7 @@ static PyObject *cpy_register_generic(cpy_callback_t **list_head, PyObject *args
c->data = data;
c->next = *list_head;
*list_head = c;
c->data = data;
c->next = *list_head;
*list_head = c;
+ Py_XDECREF(mod);
Py_RETURN_NONE;
}
Py_RETURN_NONE;
}
@@ -242,7 +203,11 @@ static PyObject *cpy_register_init(PyObject *self, PyObject *args, PyObject *kwd
return cpy_register_generic(&cpy_init_callbacks, args, kwds);
}
return cpy_register_generic(&cpy_init_callbacks, args, kwds);
}
-static PyObject *cpy_register_log(PyObject *self, PyObject *args, PyObject *kwds) {
+typedef int reg_function_t(const char *name, void *callback, void *data);
+
+static PyObject *cpy_register_generic_userdata(void *reg, void *handler, PyObject *args, PyObject *kwds) {
+ char buf[512];
+ reg_function_t *register_function = (reg_function_t *) reg;
cpy_callback_t *c = NULL;
user_data_t *user_data = NULL;
const char *name = NULL;
cpy_callback_t *c = NULL;
user_data_t *user_data = NULL;
const char *name = NULL;
@@ -254,29 +219,61 @@ static PyObject *cpy_register_log(PyObject *self, PyObject *args, PyObject *kwds
PyErr_SetString(PyExc_TypeError, "callback needs a be a callable object.");
return NULL;
}
PyErr_SetString(PyExc_TypeError, "callback needs a be a callable object.");
return NULL;
}
- if (name == NULL) {
- PyObject *mod;
-
- mod = PyObject_GetAttrString(callback, "__module__");
- if (mod != NULL) name = PyString_AsString(mod);
- if (name == NULL) {
- PyErr_SetString(PyExc_ValueError, "No module name specified and "
- "callback function does not have a \"__module__\" attribute.");
- return NULL;
- }
+ cpy_build_name(buf, sizeof(buf), callback, name);
+
+ Py_INCREF(callback);
+ Py_XINCREF(data);
+ c = malloc(sizeof(*c));
+ c->name = strdup(buf);
+ c->callback = callback;
+ c->data = data;
+ c->next = NULL;
+ user_data = malloc(sizeof(*user_data));
+ user_data->free_func = cpy_destroy_user_data;
+ user_data->data = c;
+ register_function(buf, handler, user_data);
+ return PyString_FromString(buf);
+}
+
+static PyObject *cpy_register_read(PyObject *self, PyObject *args, PyObject *kwds) {
+ char buf[512];
+ cpy_callback_t *c = NULL;
+ user_data_t *user_data = NULL;
+ double interval = 0;
+ const char *name = NULL;
+ PyObject *callback = NULL, *data = NULL;
+ struct timespec ts;
+ static char *kwlist[] = {"callback", "interval", "data", "name", NULL};
+
+ if (PyArg_ParseTupleAndKeywords(args, kwds, "O|dOz", kwlist, &callback, &interval, &data, &name) == 0) return NULL;
+ if (PyCallable_Check(callback) == 0) {
+ PyErr_SetString(PyExc_TypeError, "callback needs a be a callable object.");
+ return NULL;
}
}
+ cpy_build_name(buf, sizeof(buf), callback, name);
+
Py_INCREF(callback);
Py_XINCREF(data);
c = malloc(sizeof(*c));
Py_INCREF(callback);
Py_XINCREF(data);
c = malloc(sizeof(*c));
- c->name = strdup(name);
+ c->name = strdup(buf);
c->callback = callback;
c->data = data;
c->next = NULL;
user_data = malloc(sizeof(*user_data));
user_data->free_func = cpy_destroy_user_data;
user_data->data = c;
c->callback = callback;
c->data = data;
c->next = NULL;
user_data = malloc(sizeof(*user_data));
user_data->free_func = cpy_destroy_user_data;
user_data->data = c;
- plugin_register_log(name, cpy_log_callback, user_data);
- Py_RETURN_NONE;
+ ts.tv_sec = interval;
+ ts.tv_nsec = (interval - ts.tv_sec) * 1000000000;
+ plugin_register_complex_read(buf, cpy_read_callback, &ts, user_data);
+ return PyString_FromString(buf);
+}
+
+static PyObject *cpy_register_log(PyObject *self, PyObject *args, PyObject *kwds) {
+ return cpy_register_generic_userdata(plugin_register_log, cpy_log_callback, args, kwds);
+}
+
+static PyObject *cpy_register_write(PyObject *self, PyObject *args, PyObject *kwds) {
+ return cpy_register_generic_userdata(plugin_register_write, cpy_write_callback, args, kwds);
}
static PyObject *cpy_register_shutdown(PyObject *self, PyObject *args, PyObject *kwds) {
}
static PyObject *cpy_register_shutdown(PyObject *self, PyObject *args, PyObject *kwds) {
}
static PyMethodDef cpy_methods[] = {
}
static PyMethodDef cpy_methods[] = {
- {"Debug", cpy_Debug, METH_VARARGS, "This is an unhelpful text."},
- {"Info", cpy_Info, METH_VARARGS, "This is an unhelpful text."},
- {"Notice", cpy_Notice, METH_VARARGS, "This is an unhelpful text."},
- {"Warning", cpy_Warning, METH_VARARGS, "This is an unhelpful text."},
- {"Error", cpy_Error, METH_VARARGS, "This is an unhelpful text."},
+ {"debug", cpy_Debug, METH_VARARGS, "This is an unhelpful text."},
+ {"info", cpy_Info, METH_VARARGS, "This is an unhelpful text."},
+ {"notice", cpy_Notice, METH_VARARGS, "This is an unhelpful text."},
+ {"warning", cpy_Warning, METH_VARARGS, "This is an unhelpful text."},
+ {"error", cpy_Error, METH_VARARGS, "This is an unhelpful text."},
{"register_log", (PyCFunction) cpy_register_log, METH_VARARGS | METH_KEYWORDS, "This is an unhelpful text."},
{"register_init", (PyCFunction) cpy_register_init, METH_VARARGS | METH_KEYWORDS, "This is an unhelpful text."},
{"register_config", (PyCFunction) cpy_register_config, METH_VARARGS | METH_KEYWORDS, "This is an unhelpful text."},
{"register_log", (PyCFunction) cpy_register_log, METH_VARARGS | METH_KEYWORDS, "This is an unhelpful text."},
{"register_init", (PyCFunction) cpy_register_init, METH_VARARGS | METH_KEYWORDS, "This is an unhelpful text."},
{"register_config", (PyCFunction) cpy_register_config, METH_VARARGS | METH_KEYWORDS, "This is an unhelpful text."},
+ {"register_read", (PyCFunction) cpy_register_read, METH_VARARGS | METH_KEYWORDS, "This is an unhelpful text."},
+ {"register_write", (PyCFunction) cpy_register_write, METH_VARARGS | METH_KEYWORDS, "This is an unhelpful text."},
{"register_shutdown", (PyCFunction) cpy_register_shutdown, METH_VARARGS | METH_KEYWORDS, "This is an unhelpful text."},
{0, 0, 0, 0}
};
{"register_shutdown", (PyCFunction) cpy_register_shutdown, METH_VARARGS | METH_KEYWORDS, "This is an unhelpful text."},
{0, 0, 0, 0}
};
PyEval_RestoreThread(state);
for (c = cpy_shutdown_callbacks; c; c = c->next) {
PyEval_RestoreThread(state);
for (c = cpy_shutdown_callbacks; c; c = c->next) {
- if (c->data == NULL)
- ret = PyObject_CallObject(c->callback, NULL); /* New reference. */
- else
- ret = PyObject_CallFunctionObjArgs(c->callback, c->data, (void *) 0); /* New reference. */
+ ret = PyObject_CallFunctionObjArgs(c->callback, c->data, (void *) 0); /* New reference. */
if (ret == NULL)
PyErr_Print(); /* FIXME */
else
if (ret == NULL)
PyErr_Print(); /* FIXME */
else
return 0;
}
return 0;
}
+static void *cpy_interactive(void *data) {
+ CPY_LOCK_THREADS
+ if (PyImport_ImportModule("readline") == NULL) {
+ /* This interactive session will suck. */
+ PyErr_Print(); /* FIXME */
+ }
+ PyRun_InteractiveLoop(stdin, "<stdin>");
+ CPY_RELEASE_THREADS
+ NOTICE("python: Interactive interpreter exited, stopping collectd ...");
+ raise(SIGINT);
+ return NULL;
+}
+
static int cpy_init(void) {
cpy_callback_t *c;
PyObject *ret;
static int cpy_init(void) {
cpy_callback_t *c;
PyObject *ret;
+ static pthread_t thread;
PyEval_InitThreads();
PyEval_InitThreads();
- cpy_have_threads = 1;
/* Now it's finally OK to use python threads. */
for (c = cpy_init_callbacks; c; c = c->next) {
/* Now it's finally OK to use python threads. */
for (c = cpy_init_callbacks; c; c = c->next) {
- if (c->data == NULL)
- ret = PyObject_CallObject(c->callback, NULL); /* New reference. */
- else
- ret = PyObject_CallFunctionObjArgs(c->callback, c->data, (void *) 0); /* New reference. */
+ ret = PyObject_CallFunctionObjArgs(c->callback, c->data, (void *) 0); /* New reference. */
if (ret == NULL)
PyErr_Print(); /* FIXME */
else
Py_DECREF(ret);
}
state = PyEval_SaveThread();
if (ret == NULL)
PyErr_Print(); /* FIXME */
else
Py_DECREF(ret);
}
state = PyEval_SaveThread();
+ if (do_interactive) {
+ if (pthread_create(&thread, NULL, cpy_interactive, NULL)) {
+ ERROR("python: Error creating thread for interactive interpreter.");
+ }
+ }
+
return 0;
}
return 0;
}
Py_Initialize();
PyType_Ready(&ConfigType);
Py_Initialize();
PyType_Ready(&ConfigType);
+ PyType_Ready(&ValuesType);
sys = PyImport_ImportModule("sys"); /* New reference. */
if (sys == NULL) {
ERROR("python module: Unable to import \"sys\" module.");
sys = PyImport_ImportModule("sys"); /* New reference. */
if (sys == NULL) {
ERROR("python module: Unable to import \"sys\" module.");
}
module = Py_InitModule("collectd", cpy_methods); /* Borrowed reference. */
PyModule_AddObject(module, "Config", (PyObject *) &ConfigType); /* Steals a reference. */
}
module = Py_InitModule("collectd", cpy_methods); /* Borrowed reference. */
PyModule_AddObject(module, "Config", (PyObject *) &ConfigType); /* Steals a reference. */
+ PyModule_AddObject(module, "Values", (PyObject *) &ValuesType); /* Steals a reference. */
PyModule_AddIntConstant(module, "LOG_DEBUG", LOG_DEBUG);
PyModule_AddIntConstant(module, "LOG_INFO", LOG_INFO);
PyModule_AddIntConstant(module, "LOG_NOTICE", LOG_NOTICE);
PyModule_AddIntConstant(module, "LOG_DEBUG", LOG_DEBUG);
PyModule_AddIntConstant(module, "LOG_INFO", LOG_INFO);
PyModule_AddIntConstant(module, "LOG_NOTICE", LOG_NOTICE);
for (i = 0; i < ci->children_num; ++i) {
oconfig_item_t *item = ci->children + i;
for (i = 0; i < ci->children_num; ++i) {
oconfig_item_t *item = ci->children + i;
- if (strcasecmp(item->key, "ModulePath") == 0) {
+ if (strcasecmp(item->key, "Interactive") == 0) {
+ if (item->values_num != 1 || item->values[0].type != OCONFIG_TYPE_BOOLEAN ||
+ !item->values[0].value.boolean)
+ continue;
+ do_interactive = 1;
+ } else if (strcasecmp(item->key, "ModulePath") == 0) {
char *dir = NULL;
PyObject *dir_object;
char *dir = NULL;
PyObject *dir_object;