Add sys.argv. Not too many programs consider the possibility that it might not exist...
[collectd.git] / src / python.c
index 86bad3d..16de81d 100644 (file)
@@ -1,3 +1,29 @@
+/**
+ * collectd - src/python.c
+ * Copyright (C) 2009  Sven Trenkel
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *   Sven Trenkel <collectd at semidefinite.de>  
+ **/
+
 #include <Python.h>
 #include <structmember.h>
 
@@ -36,34 +62,32 @@ static char reg_log_doc[] = "register_log(callback[, data][, name]) -> identifie
                "'data' is an optional object that will be passed back to the callback\n"
                "    function every time it is called.\n"
                "'name' is an optional identifier for this callback. The default name\n"
-               "    is 'python.<module>.<name>'. If 'name' contains a '.' it\n"
-               "    replaces both module and name, otherwise it replaces only name.\n"
+               "    is 'python.<module>'.\n"
                "    Every callback needs a unique identifier, so if you want to\n"
-               "    register one function multiple time you need to specify a name\n"
-               "    here.\n"
+               "    register this callback multiple time from the same module you need\n"
+               "    to specify a name here.\n"
                "'identifier' is the full identifier assigned to this callback.\n"
                "\n"
                "The callback function will be called with two or three parameters:\n"
                "severity: An integer that should be compared to the LOG_ constants.\n"
                "message: The text to be logged.\n"
                "data: The optional data parameter passed to the register function.\n"
-               "    If the parameter was obmitted it will be obmitted here, too.";
+               "    If the parameter was omitted it will be omitted here, too.";
 
 static char reg_init_doc[] = "register_init(callback[, data][, name]) -> identifier\n"
                "\n"
                "Register a callback function that will be executed once after the config.\n"
                "file has been read, all plugins heve been loaded and the collectd has\n"
-               "forked into the backgroud.\n"
+               "forked into the background.\n"
                "\n"
                "'callback' is a callable object that will be executed.\n"
                "'data' is an optional object that will be passed back to the callback\n"
                "    function when it is called.\n"
                "'name' is an optional identifier for this callback. The default name\n"
-               "    is 'python.<module>.<name>'. If 'name' contains a '.' it\n"
-               "    replaces both module and name, otherwise it replaces only name.\n"
+               "    is 'python.<module>'.\n"
                "    Every callback needs a unique identifier, so if you want to\n"
-               "    register one function multiple time you need to specify a name\n"
-               "    here.\n"
+               "    register this callback multiple time from the same module you need\n"
+               "    to specify a name here.\n"
                "'identifier' is the full identifier assigned to this callback.\n"
                "\n"
                "The callback function will be called without parameters, except for\n"
@@ -76,15 +100,16 @@ static char reg_config_doc[] = "register_config(callback[, data][, name]) -> ide
                "'data' is an optional object that will be passed back to the callback\n"
                "    function every time it is called.\n"
                "'name' is an optional identifier for this callback. The default name\n"
-               "    is 'python.<module>'. Every callback needs a unique identifier,\n"
-               "    so if you want to register one function multiple time you need to\n"
-               "    specify a name here.\n"
+               "    is 'python.<module>'.\n"
+               "    Every callback needs a unique identifier, so if you want to\n"
+               "    register this callback multiple time from the same module you need\n"
+               "    to specify a name here.\n"
                "'identifier' is the full identifier assigned to this callback.\n"
                "\n"
                "The callback function will be called with one or two parameters:\n"
                "config: A Config object.\n"
                "data: The optional data parameter passed to the register function.\n"
-               "    If the parameter was obmitted it will be obmitted here, too.";
+               "    If the parameter was omitted it will be omitted here, too.";
 
 static char reg_read_doc[] = "register_read(callback[, interval][, data][, name]) -> identifier\n"
                "\n"
@@ -97,11 +122,10 @@ static char reg_read_doc[] = "register_read(callback[, interval][, data][, name]
                "'data' is an optional object that will be passed back to the callback\n"
                "    function every time it is called.\n"
                "'name' is an optional identifier for this callback. The default name\n"
-               "    is 'python.<module>.<name>'. If 'name' contains a '.' it\n"
-               "    replaces both module and name, otherwise it replaces only name.\n"
+               "    is 'python.<module>'.\n"
                "    Every callback needs a unique identifier, so if you want to\n"
-               "    register one function multiple time you need to specify a name\n"
-               "    here.\n"
+               "    register this callback multiple time from the same module you need\n"
+               "    to specify a name here.\n"
                "'identifier' is the full identifier assigned to this callback.\n"
                "\n"
                "The callback function will be called without parameters, except for\n"
@@ -115,17 +139,16 @@ static char reg_write_doc[] = "register_write(callback[, data][, name]) -> ident
                "'data' is an optional object that will be passed back to the callback\n"
                "    function every time it is called.\n"
                "'name' is an optional identifier for this callback. The default name\n"
-               "    is 'python.<module>.<name>'. If 'name' contains a '.' it\n"
-               "    replaces both module and name, otherwise it replaces only name.\n"
+               "    is 'python.<module>'.\n"
                "    Every callback needs a unique identifier, so if you want to\n"
-               "    register one function multiple time you need to specify a name\n"
-               "    here.\n"
+               "    register this callback multiple time from the same module you need\n"
+               "    to specify a name here.\n"
                "'identifier' is the full identifier assigned to this callback.\n"
                "\n"
                "The callback function will be called with one or two parameters:\n"
                "values: A Values object which is a copy of the dispatched values.\n"
                "data: The optional data parameter passed to the register function.\n"
-               "    If the parameter was obmitted it will be obmitted here, too.";
+               "    If the parameter was omitted it will be omitted here, too.";
 
 static char reg_notification_doc[] = "register_notification(callback[, data][, name]) -> identifier\n"
                "\n"
@@ -135,17 +158,16 @@ static char reg_notification_doc[] = "register_notification(callback[, data][, n
                "'data' is an optional object that will be passed back to the callback\n"
                "    function every time it is called.\n"
                "'name' is an optional identifier for this callback. The default name\n"
-               "    is 'python.<module>.<name>'. If 'name' contains a '.' it\n"
-               "    replaces both module and name, otherwise it replaces only name.\n"
+               "    is 'python.<module>'.\n"
                "    Every callback needs a unique identifier, so if you want to\n"
-               "    register one function multiple time you need to specify a name\n"
-               "    here.\n"
+               "    register this callback multiple time from the same module you need\n"
+               "    to specify a name here.\n"
                "'identifier' is the full identifier assigned to this callback.\n"
                "\n"
                "The callback function will be called with one or two parameters:\n"
                "notification: A copy of the notification that was dispatched.\n"
                "data: The optional data parameter passed to the register function.\n"
-               "    If the parameter was obmitted it will be obmitted here, too.";
+               "    If the parameter was omitted it will be omitted here, too.";
 
 static char reg_flush_doc[] = "register_flush(callback[, data][, name]) -> identifier\n"
                "\n"
@@ -155,16 +177,18 @@ static char reg_flush_doc[] = "register_flush(callback[, data][, name]) -> ident
                "'data' is an optional object that will be passed back to the callback\n"
                "    function every time it is called.\n"
                "'name' is an optional identifier for this callback. The default name\n"
-               "    is 'python.<module>'. Every callback needs a unique identifier,\n"
-               "    so if you want to register one function multiple time you need to\n"
-               "    specify a name here.\n"
+               "    is 'python.<module>'.\n"
+               "    Every callback needs a unique identifier, so if you want to\n"
+               "    register this callback multiple time from the same module you need\n"
+               "    to specify a name here.\n"
                "'identifier' is the full identifier assigned to this callback.\n"
                "\n"
                "The callback function will be called with two or three parameters:\n"
-               "timeout: ???.\n"
-               "id: ???.\n"
+               "timeout: Indicates that only data older than 'timeout' seconds is to\n"
+               "    be flushed.\n"
+               "id: Specifies which values are to be flushed.\n"
                "data: The optional data parameter passed to the register function.\n"
-               "    If the parameter was obmitted it will be obmitted here, too.";
+               "    If the parameter was omitted it will be omitted here, too.";
 
 static char reg_shutdown_doc[] = "register_shutdown(callback[, data][, name]) -> identifier\n"
                "\n"
@@ -174,11 +198,10 @@ static char reg_shutdown_doc[] = "register_shutdown(callback[, data][, name]) ->
                "'data' is an optional object that will be passed back to the callback\n"
                "    function if it is called.\n"
                "'name' is an optional identifier for this callback. The default name\n"
-               "    is 'python.<module>.<name>'. If 'name' contains a '.' it\n"
-               "    replaces both module and name, otherwise it replaces only name.\n"
+               "    is 'python.<module>'.\n"
                "    Every callback needs a unique identifier, so if you want to\n"
-               "    register one function multiple time you need to specify a name\n"
-               "    here.\n"
+               "    register this callback multiple time from the same module you need\n"
+               "    to specify a name here.\n"
                "'identifier' is the full identifier assigned to this callback.\n"
                "\n"
                "The callback function will be called with no parameters except for\n"
@@ -211,11 +234,11 @@ static void cpy_destroy_user_data(void *data) {
 /* 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, int short_name) {
-       const char *module;
-       PyObject *mod = NULL, *n = NULL;
+static void cpy_build_name(char *buf, size_t size, PyObject *callback, const char *name) {
+       const char *module = NULL;
+       PyObject *mod = NULL;
        
-       if (name != NULL && (strchr(name, '.') != NULL || short_name)) {
+       if (name != NULL) {
                snprintf(buf, size, "python.%s", name);
                return;
        }
@@ -223,31 +246,17 @@ static void cpy_build_name(char *buf, size_t size, PyObject *callback, const cha
        mod = PyObject_GetAttrString(callback, "__module__"); /* New reference. */
        if (mod != NULL)
                module = PyString_AsString(mod);
-       else
-               module = "collectd";
        
-       if (short_name) {
+       if (module != NULL) {
                snprintf(buf, size, "python.%s", module);
                Py_XDECREF(mod);
+               PyErr_Clear();
                return;
        }
-       
-       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);
+       
+       snprintf(buf, size, "python.%p", callback);
+       PyErr_Clear();
 }
 
 static void cpy_log_exception(const char *context) {
@@ -268,7 +277,9 @@ static void cpy_log_exception(const char *context) {
                typename = "NamelessException";
        if (message == NULL)
                message = "N/A";
+       Py_BEGIN_ALLOW_THREADS
        ERROR("Unhandled python exception in %s: %s: %s", context, typename, message);
+       Py_END_ALLOW_THREADS
        Py_XDECREF(tn);
        Py_XDECREF(m);
        if (!cpy_format_exception) {
@@ -291,10 +302,11 @@ static void cpy_log_exception(const char *context) {
                
                line = PyList_GET_ITEM(list, i); /* Borrowed reference. */
                s = strdup(PyString_AsString(line));
-               Py_DECREF(line);
                if (s[strlen(s) - 1] == '\n')
                        s[strlen(s) - 1] = 0;
+               Py_BEGIN_ALLOW_THREADS
                ERROR("%s", s);
+               Py_END_ALLOW_THREADS
                free(s);
        }
        Py_XDECREF(list);
@@ -313,6 +325,8 @@ static int cpy_read_callback(user_data_t *data) {
                        Py_DECREF(ret);
                }
        CPY_RELEASE_THREADS
+       if (ret == NULL)
+               return 1;
        return 0;
 }
 
@@ -346,20 +360,25 @@ static int cpy_write_callback(const data_set_t *ds, const value_list_t *value_li
                                else
                                        PyList_SetItem(list, i, PyLong_FromUnsignedLongLong(value_list->values[i].absolute));
                        } else {
+                               Py_BEGIN_ALLOW_THREADS
                                ERROR("cpy_write_callback: Unknown value type %d.", ds->ds->type);
+                               Py_END_ALLOW_THREADS
                                Py_DECREF(list);
                                CPY_RETURN_FROM_THREADS 0;
                        }
                        if (PyErr_Occurred() != NULL) {
                                cpy_log_exception("value building for write callback");
+                               Py_DECREF(list);
                                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);
+               v = PyObject_CallFunction((void *) &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); /* New reference. */
                Py_DECREF(list);
                ret = PyObject_CallFunctionObjArgs(c->callback, v, c->data, (void *) 0); /* New reference. */
+               Py_XDECREF(v);
                if (ret == NULL) {
                        cpy_log_exception("write callback");
                } else {
@@ -374,10 +393,11 @@ static int cpy_notification_callback(const notification_t *notification, user_da
        PyObject *ret, *n;
 
        CPY_LOCK_THREADS
-               n = PyObject_CallFunction((PyObject *) &NotificationType, "ssssssdi", notification->type, notification->message,
+               n = PyObject_CallFunction((void *) &NotificationType, "ssssssdi", notification->type, notification->message,
                                notification->plugin_instance, notification->type_instance, notification->plugin,
-                               notification->host, (double) notification->time, notification->severity);
+                               notification->host, (double) notification->time, notification->severity); /* New reference. */
                ret = PyObject_CallFunctionObjArgs(c->callback, n, c->data, (void *) 0); /* New reference. */
+               Py_XDECREF(n);
                if (ret == NULL) {
                        cpy_log_exception("notification callback");
                } else {
@@ -402,6 +422,8 @@ static void cpy_log_callback(int severity, const char *message, user_data_t *dat
                /* Do we really want to trigger a log callback because a log callback failed?
                 * Probably not. */
                PyErr_Print();
+               /* In case someone wanted to be clever, replaced stderr and failed at that. */
+               PyErr_Clear();
        } else {
                Py_DECREF(ret);
        }
@@ -426,7 +448,7 @@ static void cpy_flush_callback(int timeout, const char *id, user_data_t *data) {
        CPY_RELEASE_THREADS
 }
 
-static PyObject *cpy_register_generic(cpy_callback_t **list_head, PyObject *args, PyObject *kwds, int short_name) {
+static PyObject *cpy_register_generic(cpy_callback_t **list_head, PyObject *args, PyObject *kwds) {
        char buf[512];
        cpy_callback_t *c;
        const char *name = NULL;
@@ -438,7 +460,7 @@ static PyObject *cpy_register_generic(cpy_callback_t **list_head, PyObject *args
                PyErr_SetString(PyExc_TypeError, "callback needs a be a callable object.");
                return NULL;
        }
-       cpy_build_name(buf, sizeof(buf), callback, name, short_name);
+       cpy_build_name(buf, sizeof(buf), callback, name);
 
        Py_INCREF(callback);
        Py_XINCREF(data);
@@ -465,16 +487,16 @@ static PyObject *cpy_flush(cpy_callback_t **list_head, PyObject *args, PyObject
 }
 
 static PyObject *cpy_register_config(PyObject *self, PyObject *args, PyObject *kwds) {
-       return cpy_register_generic(&cpy_config_callbacks, args, kwds, 1);
+       return cpy_register_generic(&cpy_config_callbacks, args, kwds);
 }
 
 static PyObject *cpy_register_init(PyObject *self, PyObject *args, PyObject *kwds) {
-       return cpy_register_generic(&cpy_init_callbacks, args, kwds, 0);
+       return cpy_register_generic(&cpy_init_callbacks, args, 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, int short_name) {
+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;
@@ -488,7 +510,7 @@ static PyObject *cpy_register_generic_userdata(void *reg, void *handler, PyObjec
                PyErr_SetString(PyExc_TypeError, "callback needs a be a callable object.");
                return NULL;
        }
-       cpy_build_name(buf, sizeof(buf), callback, name, short_name);
+       cpy_build_name(buf, sizeof(buf), callback, name);
        
        Py_INCREF(callback);
        Py_XINCREF(data);
@@ -519,7 +541,7 @@ static PyObject *cpy_register_read(PyObject *self, PyObject *args, PyObject *kwd
                PyErr_SetString(PyExc_TypeError, "callback needs a be a callable object.");
                return NULL;
        }
-       cpy_build_name(buf, sizeof(buf), callback, name, 0);
+       cpy_build_name(buf, sizeof(buf), callback, name);
        
        Py_INCREF(callback);
        Py_XINCREF(data);
@@ -538,23 +560,27 @@ static PyObject *cpy_register_read(PyObject *self, PyObject *args, PyObject *kwd
 }
 
 static PyObject *cpy_register_log(PyObject *self, PyObject *args, PyObject *kwds) {
-       return cpy_register_generic_userdata(plugin_register_log, cpy_log_callback, args, kwds, 0);
+       return cpy_register_generic_userdata((void *) plugin_register_log,
+                       (void *) 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, 0);
+       return cpy_register_generic_userdata((void *) plugin_register_write,
+                       (void *) cpy_write_callback, args, kwds);
 }
 
 static PyObject *cpy_register_notification(PyObject *self, PyObject *args, PyObject *kwds) {
-       return cpy_register_generic_userdata(plugin_register_notification, cpy_notification_callback, args, kwds, 0);
+       return cpy_register_generic_userdata((void *) plugin_register_notification,
+                       (void *) cpy_notification_callback, args, kwds);
 }
 
 static PyObject *cpy_register_flush(PyObject *self, PyObject *args, PyObject *kwds) {
-       return cpy_register_generic_userdata(plugin_register_flush, cpy_flush_callback, args, kwds, 1);
+       return cpy_register_generic_userdata((void *) plugin_register_flush,
+                       (void *) cpy_flush_callback, args, kwds);
 }
 
 static PyObject *cpy_register_shutdown(PyObject *self, PyObject *args, PyObject *kwds) {
-       return cpy_register_generic(&cpy_shutdown_callbacks, args, kwds, 0);
+       return cpy_register_generic(&cpy_shutdown_callbacks, args, kwds);
 }
 
 static PyObject *cpy_error(PyObject *self, PyObject *args) {
@@ -597,24 +623,32 @@ static PyObject *cpy_debug(PyObject *self, PyObject *args) {
 #ifdef COLLECT_DEBUG
        const char *text;
        if (PyArg_ParseTuple(args, "s", &text) == 0) return NULL;
+       Py_BEGIN_ALLOW_THREADS
        plugin_log(LOG_DEBUG, "%s", text);
+       Py_END_ALLOW_THREADS
 #endif
        Py_RETURN_NONE;
 }
 
-static PyObject *cpy_unregister_generic(cpy_callback_t **list_head, PyObject *arg, const char *desc, int short_name) {
+static PyObject *cpy_unregister_generic(cpy_callback_t **list_head, PyObject *arg, const char *desc) {
        char buf[512];
        const char *name;
        cpy_callback_t *prev = NULL, *tmp;
 
-       if (PyString_Check(arg)) {
+       if (PyUnicode_Check(arg)) {
+               arg = PyUnicode_AsEncodedString(arg, NULL, NULL);
+               if (arg == NULL)
+                       return NULL;
+               name = PyString_AsString(arg);
+               Py_DECREF(arg);
+       } else if (PyString_Check(arg)) {
                name = PyString_AsString(arg);
        } else {
                if (!PyCallable_Check(arg)) {
                        PyErr_SetString(PyExc_TypeError, "This function needs a string or a callable object as its only parameter.");
                        return NULL;
                }
-               cpy_build_name(buf, sizeof(buf), arg, NULL, short_name);
+               cpy_build_name(buf, sizeof(buf), arg, NULL);
                name = buf;
        }
        for (tmp = *list_head; tmp; prev = tmp, tmp = tmp->next)
@@ -625,7 +659,7 @@ static PyObject *cpy_unregister_generic(cpy_callback_t **list_head, PyObject *ar
                PyErr_Format(PyExc_RuntimeError, "Unable to unregister %s callback '%s'.", desc, name);
                return NULL;
        }
-       /* Yes, this is actually save. To call this function the calles has to
+       /* Yes, this is actually save. To call this function the caller has to
         * hold the GIL. Well, save as long as there is only one GIL anyway ... */
        if (prev == NULL)
                *list_head = tmp->next;
@@ -637,18 +671,24 @@ static PyObject *cpy_unregister_generic(cpy_callback_t **list_head, PyObject *ar
 
 typedef int cpy_unregister_function_t(const char *name);
 
-static PyObject *cpy_unregister_generic_userdata(cpy_unregister_function_t *unreg, PyObject *arg, const char *desc, int short_name) {
+static PyObject *cpy_unregister_generic_userdata(cpy_unregister_function_t *unreg, PyObject *arg, const char *desc) {
        char buf[512];
        const char *name;
 
-       if (PyString_Check(arg)) {
+       if (PyUnicode_Check(arg)) {
+               arg = PyUnicode_AsEncodedString(arg, NULL, NULL);
+               if (arg == NULL)
+                       return NULL;
+               name = PyString_AsString(arg);
+               Py_DECREF(arg);
+       } else if (PyString_Check(arg)) {
                name = PyString_AsString(arg);
        } else {
                if (!PyCallable_Check(arg)) {
                        PyErr_SetString(PyExc_TypeError, "This function needs a string or a callable object as its only parameter.");
                        return NULL;
                }
-               cpy_build_name(buf, sizeof(buf), arg, NULL, short_name);
+               cpy_build_name(buf, sizeof(buf), arg, NULL);
                name = buf;
        }
        if (unreg(name) == 0)
@@ -658,35 +698,35 @@ static PyObject *cpy_unregister_generic_userdata(cpy_unregister_function_t *unre
 }
 
 static PyObject *cpy_unregister_log(PyObject *self, PyObject *arg) {
-       return cpy_unregister_generic_userdata(plugin_unregister_log, arg, "log", 0);
+       return cpy_unregister_generic_userdata(plugin_unregister_log, arg, "log");
 }
 
 static PyObject *cpy_unregister_init(PyObject *self, PyObject *arg) {
-       return cpy_unregister_generic(&cpy_init_callbacks, arg, "init", 0);
+       return cpy_unregister_generic(&cpy_init_callbacks, arg, "init");
 }
 
 static PyObject *cpy_unregister_config(PyObject *self, PyObject *arg) {
-       return cpy_unregister_generic(&cpy_config_callbacks, arg, "config", 1);
+       return cpy_unregister_generic(&cpy_config_callbacks, arg, "config");
 }
 
 static PyObject *cpy_unregister_read(PyObject *self, PyObject *arg) {
-       return cpy_unregister_generic_userdata(plugin_unregister_read, arg, "read", 0);
+       return cpy_unregister_generic_userdata(plugin_unregister_read, arg, "read");
 }
 
 static PyObject *cpy_unregister_write(PyObject *self, PyObject *arg) {
-       return cpy_unregister_generic_userdata(plugin_unregister_write, arg, "write", 0);
+       return cpy_unregister_generic_userdata(plugin_unregister_write, arg, "write");
 }
 
 static PyObject *cpy_unregister_notification(PyObject *self, PyObject *arg) {
-       return cpy_unregister_generic_userdata(plugin_unregister_notification, arg, "notification", 0);
+       return cpy_unregister_generic_userdata(plugin_unregister_notification, arg, "notification");
 }
 
 static PyObject *cpy_unregister_flush(PyObject *self, PyObject *arg) {
-       return cpy_unregister_generic_userdata(plugin_unregister_flush, arg, "flush", 1);
+       return cpy_unregister_generic_userdata(plugin_unregister_flush, arg, "flush");
 }
 
 static PyObject *cpy_unregister_shutdown(PyObject *self, PyObject *arg) {
-       return cpy_unregister_generic(&cpy_shutdown_callbacks, arg, "shutdown", 0);
+       return cpy_unregister_generic(&cpy_shutdown_callbacks, arg, "shutdown");
 }
 
 static PyMethodDef cpy_methods[] = {
@@ -792,6 +832,11 @@ static int cpy_init(void) {
        static pthread_t thread;
        sigset_t sigset;
        
+       if (!Py_IsInitialized()) {
+               WARNING("python: Plugin loaded but not configured.");
+               plugin_unregister_shutdown("python");
+               return 0;
+       }
        PyEval_InitThreads();
        /* Now it's finally OK to use python threads. */
        for (c = cpy_init_callbacks; c; c = c->next) {
@@ -832,7 +877,7 @@ static PyObject *cpy_oconfig_to_pyconfig(oconfig_item_t *ci, PyObject *parent) {
                }
        }
        
-       item = PyObject_CallFunction((PyObject *) &ConfigType, "sONO", ci->key, parent, values, Py_None);
+       item = PyObject_CallFunction((void *) &ConfigType, "sONO", ci->key, parent, values, Py_None);
        if (item == NULL)
                return NULL;
        children = PyTuple_New(ci->children_num); /* New reference. */
@@ -847,6 +892,7 @@ static PyObject *cpy_oconfig_to_pyconfig(oconfig_item_t *ci, PyObject *parent) {
 
 static int cpy_config(oconfig_item_t *ci) {
        int i;
+       char *argv = "";
        PyObject *sys, *tb;
        PyObject *sys_path;
        PyObject *module;
@@ -876,10 +922,13 @@ static int cpy_config(oconfig_item_t *ci) {
                cpy_log_exception("python initialization");
                return 1;
        }
+       PySys_SetArgv(1, &argv);
+       PyList_SetSlice(sys_path, 0, 1, NULL);
+
        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_AddObject(module, "Notification", (PyObject *) &NotificationType); /* Steals a reference. */
+       PyModule_AddObject(module, "Config", (void *) &ConfigType); /* Steals a reference. */
+       PyModule_AddObject(module, "Values", (void *) &ValuesType); /* Steals a reference. */
+       PyModule_AddObject(module, "Notification", (void *) &NotificationType); /* Steals a reference. */
        PyModule_AddIntConstant(module, "LOG_DEBUG", LOG_DEBUG);
        PyModule_AddIntConstant(module, "LOG_INFO", LOG_INFO);
        PyModule_AddIntConstant(module, "LOG_NOTICE", LOG_NOTICE);
@@ -895,6 +944,12 @@ static int cpy_config(oconfig_item_t *ci) {
                        if (item->values_num != 1 || item->values[0].type != OCONFIG_TYPE_BOOLEAN)
                                continue;
                        do_interactive = item->values[0].value.boolean;
+               } else if (strcasecmp(item->key, "Encoding") == 0) {
+                       if (item->values_num != 1 || item->values[0].type != OCONFIG_TYPE_STRING)
+                               continue;
+                       /* Why is this even necessary? And undocumented? */
+                       if (PyUnicode_SetDefaultEncoding(item->values[0].value.string))
+                               cpy_log_exception("setting default encoding");
                } else if (strcasecmp(item->key, "LogTraces") == 0) {
                        if (item->values_num != 1 || item->values[0].type != OCONFIG_TYPE_BOOLEAN)
                                continue;