Merge remote branch 'trenkel/st/python'
authorFlorian Forster <octo@leeloo.lan.home.verplant.org>
Thu, 22 Apr 2010 08:45:58 +0000 (10:45 +0200)
committerFlorian Forster <octo@leeloo.lan.home.verplant.org>
Thu, 22 Apr 2010 08:45:58 +0000 (10:45 +0200)
contrib/python/getsigchld.py [new file with mode: 0644]
src/collectd-python.pod
src/cpython.h
src/python.c
src/pyvalues.c

diff --git a/contrib/python/getsigchld.py b/contrib/python/getsigchld.py
new file mode 100644 (file)
index 0000000..557adc0
--- /dev/null
@@ -0,0 +1,21 @@
+#!/usr/bin/python
+
+###############################################################################
+#         WARNING! Importing this script will break the exec plugin!          #
+###############################################################################
+# Use this if you want to create new processes from your python scripts.      #
+# Normally you will get a OSError exception when the new process terminates   #
+# because collectd will ignore the SIGCHLD python is waiting for.             #
+# This script will restore the default SIGCHLD behavior so python scripts can #
+# create new processes without errors.                                        #
+###############################################################################
+#         WARNING! Importing this script will break the exec plugin!          #
+###############################################################################
+
+import signal
+import collectd
+
+def init():
+       signal.signal(signal.SIGCHLD, signal.SIG_DFL)
+
+collectd.register_init(init)
index 335f6a9..36d2be3 100644 (file)
@@ -105,6 +105,15 @@ environment variable, e.g. I<export PAGER=less> before starting collectd.
 Depending on your version of python this might or might not result in an
 B<OSError> exception which can be ignored.
 
+If you really need to spawn new processes from python you can register an init
+callback and reset the action for SIGCHLD to the default behavior. Please note
+that this I<will> break the exec plugin. Do not even load the exec plugin if
+you intend to do this!
+
+There is an example script located in B<contrib/python/getsigchld.py>  to do
+this. If you import this from I<collectd.conf> SIGCHLD will be handled
+normally and spawning processes from python will work as intended.
+
 =back
 
 =item E<lt>B<Module> I<Name>E<gt> block
@@ -231,6 +240,28 @@ collectd you're done.
 The following complex types are used to pass values between the Python plugin
 and collectd:
 
+=head2 Signed
+
+The Signed class is just a long. It has all its methods and behaves exactly
+like any other long object. It is used to indicate if an integer was or should
+be stored as a signed or unsigned integer object.
+
+ class Signed(long)
+
+This is a long by another name. Use it in meta data dicts
+to choose the way it is stored in the meta data.
+
+=head2 Unsigned
+
+The Unsigned class is just a long. It has all its methods and behaves exactly
+like any other long object. It is used to indicate if an integer was or should
+be stored as a signed or unsigned integer object.
+
+ class Unsigned(long)
+
+This is a long by another name. Use it in meta data dicts
+to choose the way it is stored in the meta data.
+
 =head2 Config
 
 The Config class is an object which keeps the information provided in the
@@ -394,6 +425,15 @@ If the sequence does not have the correct size upon dispatch a I<RuntimeError>
 exception will be raised. If the content of the sequence is not a number, a
 I<TypeError> exception will be raised.
 
+=item meta
+These are the meta data for this Value object.
+It has to be a dictionary of numbers, strings or bools. All keys must be
+strings. I<int> and <long> objects will be dispatched as signed integers unless
+they are between 2**63 and 2**64-1, which will result in a unsigned integer.
+You can force one of these storage classes by using the classes
+B<collectd.Signed> and B<collectd.Unsigned>. A meta object received by a write
+callback will always contain B<Signed> or B<Unsigned> objects.
+
 =back
 
 =head2 Notification
index 3e80cb0..2a14ce0 100644 (file)
  *   Sven Trenkel <collectd at semidefinite.de>  
  **/
 
+/* Some python versions don't include this by default. */
+
+#include <longintrepr.h>
+
 /* 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
@@ -155,7 +159,9 @@ static inline PyObject *cpy_string_to_unicode_or_bytes(const char *buf) {
 #endif 
 }
 
- /* Python object declarations. */
+void cpy_log_exception(const char *context);
+
+/* Python object declarations. */
 
 typedef struct {
        PyObject_HEAD        /* No semicolon! */
@@ -164,7 +170,6 @@ typedef struct {
        PyObject *values;    /* Sequence */
        PyObject *children;  /* Sequence */
 } Config;
-
 PyTypeObject ConfigType;
 
 typedef struct {
@@ -176,15 +181,14 @@ typedef struct {
        char type[DATA_MAX_NAME_LEN];
        char type_instance[DATA_MAX_NAME_LEN];
 } PluginData;
-
 PyTypeObject PluginDataType;
 
 typedef struct {
        PluginData data;
        PyObject *values;    /* Sequence */
+       PyObject *meta;      /* dict */
        int interval;
 } Values;
-
 PyTypeObject ValuesType;
 
 typedef struct {
@@ -192,5 +196,10 @@ typedef struct {
        int severity;
        char message[NOTIF_MAX_MSG_LEN];
 } Notification;
-
 PyTypeObject NotificationType;
+
+typedef PyLongObject Signed;
+PyTypeObject SignedType;
+
+typedef PyLongObject Unsigned;
+PyTypeObject UnsignedType;
index 2f4f01e..4d44977 100644 (file)
@@ -259,7 +259,7 @@ static void cpy_build_name(char *buf, size_t size, PyObject *callback, const cha
        PyErr_Clear();
 }
 
-static void cpy_log_exception(const char *context) {
+void cpy_log_exception(const char *context) {
        int l = 0, i;
        const char *typename = NULL, *message = NULL;
        PyObject *type, *value, *traceback, *tn, *m, *list;
@@ -335,7 +335,7 @@ static int cpy_read_callback(user_data_t *data) {
 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, *list;
+       PyObject *ret, *list, *temp, *dict = NULL;
        Values *v;
 
        CPY_LOCK_THREADS
@@ -374,6 +374,60 @@ static int cpy_write_callback(const data_set_t *ds, const value_list_t *value_li
                                CPY_RETURN_FROM_THREADS 0;
                        }
                }
+               dict = PyDict_New();
+               if (value_list->meta) {
+                       int i, num;
+                       char **table;
+                       meta_data_t *meta = value_list->meta;
+
+                       num = meta_data_toc(meta, &table);
+                       for (i = 0; i < num; ++i) {
+                               int type;
+                               char *string;
+                               int64_t si;
+                               uint64_t ui;
+                               double d;
+                               _Bool b;
+                               
+                               type = meta_data_type(meta, table[i]);
+                               if (type == MD_TYPE_STRING) {
+                                       if (meta_data_get_string(meta, table[i], &string))
+                                               continue;
+                                       temp = cpy_string_to_unicode_or_bytes(string);
+                                       free(string);
+                                       PyDict_SetItemString(dict, table[i], temp);
+                                       Py_XDECREF(temp);
+                               } else if (type == MD_TYPE_SIGNED_INT) {
+                                       if (meta_data_get_signed_int(meta, table[i], &si))
+                                               continue;
+                                       temp = PyObject_CallFunctionObjArgs((void *) &SignedType, PyLong_FromLongLong(si), (void *) 0);
+                                       PyDict_SetItemString(dict, table[i], temp);
+                                       Py_XDECREF(temp);
+                               } else if (type == MD_TYPE_UNSIGNED_INT) {
+                                       if (meta_data_get_unsigned_int(meta, table[i], &ui))
+                                               continue;
+                                       temp = PyObject_CallFunctionObjArgs((void *) &UnsignedType, PyLong_FromUnsignedLongLong(ui), (void *) 0);
+                                       PyDict_SetItemString(dict, table[i], temp);
+                                       Py_XDECREF(temp);
+                               } else if (type == MD_TYPE_DOUBLE) {
+                                       if (meta_data_get_double(meta, table[i], &d))
+                                               continue;
+                                       temp = PyFloat_FromDouble(d);
+                                       PyDict_SetItemString(dict, table[i], temp);
+                                       Py_XDECREF(temp);
+                               } else if (type == MD_TYPE_BOOLEAN) {
+                                       if (meta_data_get_boolean(meta, table[i], &b))
+                                               continue;
+                                       if (b)
+                                               temp = Py_True;
+                                       else
+                                               temp = Py_False;
+                                       PyDict_SetItemString(dict, table[i], temp);
+                               }
+                               free(table[i]);
+                       }
+                       free(table);
+               }
                v = PyObject_New(Values, (void *) &ValuesType);
                sstrncpy(v->data.host, value_list->host, sizeof(v->data.host));
                sstrncpy(v->data.type, value_list->type, sizeof(v->data.type));
@@ -383,6 +437,7 @@ static int cpy_write_callback(const data_set_t *ds, const value_list_t *value_li
                v->data.time = value_list->time;
                v->interval = value_list->interval;
                v->values = list;
+               v->meta = dict;
                ret = PyObject_CallFunctionObjArgs(c->callback, v, c->data, (void *) 0); /* New reference. */
                if (ret == NULL) {
                        cpy_log_exception("write callback");
@@ -936,6 +991,10 @@ static int cpy_config(oconfig_item_t *ci) {
        PyType_Ready(&ValuesType);
        NotificationType.tp_base = &PluginDataType;
        PyType_Ready(&NotificationType);
+       SignedType.tp_base = &PyLong_Type;
+       PyType_Ready(&SignedType);
+       UnsignedType.tp_base = &PyLong_Type;
+       PyType_Ready(&UnsignedType);
        sys = PyImport_ImportModule("sys"); /* New reference. */
        if (sys == NULL) {
                cpy_log_exception("python initialization");
@@ -955,6 +1014,8 @@ static int cpy_config(oconfig_item_t *ci) {
        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_AddObject(module, "Signed", (void *) &SignedType); /* Steals a reference. */
+       PyModule_AddObject(module, "Unsigned", (void *) &UnsignedType); /* Steals a reference. */
        PyModule_AddIntConstant(module, "LOG_DEBUG", LOG_DEBUG);
        PyModule_AddIntConstant(module, "LOG_INFO", LOG_INFO);
        PyModule_AddIntConstant(module, "LOG_NOTICE", LOG_NOTICE);
index a632dc1..60462ad 100644 (file)
@@ -308,6 +308,14 @@ static char values_doc[] = "These are the actual values that get dispatched to c
                "exception will be raised. If the content of the sequence is not a number,\n"
                "a TypeError exception will be raised.";
 
+static char meta_doc[] = "These are the meta data for this Value object.\n"
+               "It has to be a dictionary of numbers, strings or bools. All keys must be\n"
+               "strings. int and long objects will be dispatched as signed integers unless\n"
+               "they are between 2**63 and 2**64-1, which will result in a unsigned integer.\n"
+               "You can force one of these storage classes by using the classes\n"
+               "collectd.Signed and collectd.Unsigned. A meta object received by a write\n"
+               "callback will always contain Signed or Unsigned objects.";
+
 static char dispatch_doc[] = "dispatch([type][, values][, plugin_instance][, type_instance]"
                "[, plugin][, host][, time][, interval]) -> None.  Dispatch a value list.\n"
                "\n"
@@ -336,6 +344,7 @@ static PyObject *Values_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
                return NULL;
        
        self->values = PyList_New(0);
+       self->meta = PyDict_New();
        self->interval = 0;
        return (PyObject *) self;
 }
@@ -344,14 +353,14 @@ static int Values_init(PyObject *s, PyObject *args, PyObject *kwds) {
        Values *self = (Values *) s;
        int interval = 0;
        double time = 0;
-       PyObject *values = NULL, *tmp;
+       PyObject *values = NULL, *meta = NULL, *tmp;
        const char *type = "", *plugin_instance = "", *type_instance = "", *plugin = "", *host = "";
        static char *kwlist[] = {"type", "values", "plugin_instance", "type_instance",
-                       "plugin", "host", "time", "interval", NULL};
+                       "plugin", "host", "time", "interval", "meta", NULL};
        
-       if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etOetetetetdi", kwlist,
+       if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etOetetetetdiO", kwlist,
                        NULL, &type, &values, NULL, &plugin_instance, NULL, &type_instance,
-                       NULL, &plugin, NULL, &host, &time, &interval))
+                       NULL, &plugin, NULL, &host, &time, &interval, &meta))
                return -1;
        
        if (type[0] != 0 && plugin_get_ds(type) == NULL) {
@@ -373,21 +382,109 @@ static int Values_init(PyObject *s, PyObject *args, PyObject *kwds) {
                Py_INCREF(values);
        }
        
+       if (meta == NULL) {
+               meta = PyDict_New();
+               PyErr_Clear();
+       } else {
+               Py_INCREF(meta);
+       }
+       
        tmp = self->values;
        self->values = values;
        Py_XDECREF(tmp);
        
+       tmp = self->meta;
+       self->meta = meta;
+       Py_XDECREF(tmp);
+
        self->interval = interval;
        return 0;
 }
 
+static meta_data_t *cpy_build_meta(PyObject *meta) {
+       int i, s;
+       meta_data_t *m = NULL;
+       PyObject *l;
+       
+       if (!meta)
+               return NULL;
+
+       m = meta_data_create();
+       l = PyDict_Items(meta);
+       s = PyList_Size(l);
+       for (i = 0; i < s; ++i) {
+               const char *string, *keystring;
+               PyObject *key, *value, *item, *tmp;
+               
+               item = PyList_GET_ITEM(l, i);
+               key = PyTuple_GET_ITEM(item, 0);
+               Py_INCREF(key);
+               keystring = cpy_unicode_or_bytes_to_string(&key);
+               if (!keystring) {
+                       PyErr_Clear();
+                       Py_XDECREF(key);
+                       continue;
+               }
+               value = PyTuple_GET_ITEM(item, 1);
+               Py_INCREF(value);
+               if (value == Py_True) {
+                       meta_data_add_boolean(m, keystring, 1);
+               } else if (value == Py_False) {
+                       meta_data_add_boolean(m, keystring, 0);
+               } else if (PyFloat_Check(value)) {
+                       meta_data_add_double(m, keystring, PyFloat_AsDouble(value));
+               } else if (PyObject_TypeCheck(value, &SignedType)) {
+                       long long int lli;
+                       lli = PyLong_AsLongLong(value);
+                       if (!PyErr_Occurred() && (lli == (int64_t) lli))
+                               meta_data_add_signed_int(m, keystring, lli);
+               } else if (PyObject_TypeCheck(value, &UnsignedType)) {
+                       long long unsigned llu;
+                       llu = PyLong_AsUnsignedLongLong(value);
+                       if (!PyErr_Occurred() && (llu == (uint64_t) llu))
+                               meta_data_add_unsigned_int(m, keystring, llu);
+               } else if (PyNumber_Check(value)) {
+                       long long int lli;
+                       long long unsigned llu;
+                       tmp = PyNumber_Long(value);
+                       lli = PyLong_AsLongLong(tmp);
+                       if (!PyErr_Occurred() && (lli == (int64_t) lli)) {
+                               meta_data_add_signed_int(m, keystring, lli);
+                       } else {
+                               PyErr_Clear();
+                               llu = PyLong_AsUnsignedLongLong(tmp);
+                               if (!PyErr_Occurred() && (llu == (uint64_t) llu))
+                                       meta_data_add_unsigned_int(m, keystring, llu);
+                       }
+                       Py_XDECREF(tmp);
+               } else {
+                       string = cpy_unicode_or_bytes_to_string(&value);
+                       if (string) {
+                               meta_data_add_string(m, keystring, string);
+                       } else {
+                               PyErr_Clear();
+                               tmp = PyObject_Str(value);
+                               string = cpy_unicode_or_bytes_to_string(&tmp);
+                               if (string)
+                                       meta_data_add_string(m, keystring, string);
+                               Py_XDECREF(tmp);
+                       }
+               }
+               if (PyErr_Occurred())
+                       cpy_log_exception("building meta data");
+               Py_XDECREF(value);
+               Py_DECREF(key);
+       }
+       return m;
+}
+
 static PyObject *Values_dispatch(Values *self, PyObject *args, PyObject *kwds) {
        int i, ret;
        const data_set_t *ds;
        int size;
        value_t *value;
        value_list_t value_list = VALUE_LIST_INIT;
-       PyObject *values = self->values;
+       PyObject *values = self->values, *meta = self->meta;
        double time = self->data.time;
        int interval = self->interval;
        const char *host = self->data.host;
@@ -397,10 +494,10 @@ static PyObject *Values_dispatch(Values *self, PyObject *args, PyObject *kwds) {
        const char *type_instance = self->data.type_instance;
        
        static char *kwlist[] = {"type", "values", "plugin_instance", "type_instance",
-                       "plugin", "host", "time", "interval", NULL};
-       if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etOetetetetdi", kwlist,
+                       "plugin", "host", "time", "interval", "meta", NULL};
+       if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etOetetetetdiO", kwlist,
                        NULL, &type, &values, NULL, &plugin_instance, NULL, &type_instance,
-                       NULL, &plugin, NULL, &host, &time, &interval))
+                       NULL, &plugin, NULL, &host, &time, &interval, &meta))
                return NULL;
 
        if (type[0] == 0) {
@@ -416,6 +513,10 @@ static PyObject *Values_dispatch(Values *self, PyObject *args, PyObject *kwds) {
                PyErr_Format(PyExc_TypeError, "values must be list or tuple");
                return NULL;
        }
+       if (meta != NULL && meta != Py_None && !PyDict_Check(meta)) {
+               PyErr_Format(PyExc_TypeError, "meta must be a dict");
+               return NULL;
+       }
        size = (int) PySequence_Length(values);
        if (size != ds->ds_num) {
                PyErr_Format(PyExc_RuntimeError, "type %s needs %d values, got %i", type, ds->ds_num, size);
@@ -456,6 +557,7 @@ static PyObject *Values_dispatch(Values *self, PyObject *args, PyObject *kwds) {
                }
        }
        value_list.values = value;
+       value_list.meta = cpy_build_meta(meta);
        value_list.values_len = size;
        value_list.time = time;
        value_list.interval = interval;
@@ -464,7 +566,6 @@ static PyObject *Values_dispatch(Values *self, PyObject *args, PyObject *kwds) {
        sstrncpy(value_list.plugin_instance, plugin_instance, sizeof(value_list.plugin_instance));
        sstrncpy(value_list.type, type, sizeof(value_list.type));
        sstrncpy(value_list.type_instance, type_instance, sizeof(value_list.type_instance));
-       value_list.meta = NULL;
        if (value_list.host[0] == 0)
                sstrncpy(value_list.host, hostname_g, sizeof(value_list.host));
        if (value_list.plugin[0] == 0)
@@ -486,7 +587,7 @@ static PyObject *Values_write(Values *self, PyObject *args, PyObject *kwds) {
        int size;
        value_t *value;
        value_list_t value_list = VALUE_LIST_INIT;
-       PyObject *values = self->values;
+       PyObject *values = self->values, *meta = self->meta;
        double time = self->data.time;
        int interval = self->interval;
        const char *host = self->data.host;
@@ -497,10 +598,10 @@ static PyObject *Values_write(Values *self, PyObject *args, PyObject *kwds) {
        const char *dest = NULL;
        
        static char *kwlist[] = {"destination", "type", "values", "plugin_instance", "type_instance",
-                       "plugin", "host", "time", "interval", NULL};
-       if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etOetetetetdi", kwlist,
+                       "plugin", "host", "time", "interval", "meta", NULL};
+       if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etOetetetetdiO", kwlist,
                        NULL, &type, &values, NULL, &plugin_instance, NULL, &type_instance,
-                       NULL, &plugin, NULL, &host, &time, &interval))
+                       NULL, &plugin, NULL, &host, &time, &interval, &meta))
                return NULL;
 
        if (type[0] == 0) {
@@ -564,7 +665,7 @@ static PyObject *Values_write(Values *self, PyObject *args, PyObject *kwds) {
        sstrncpy(value_list.plugin_instance, plugin_instance, sizeof(value_list.plugin_instance));
        sstrncpy(value_list.type, type, sizeof(value_list.type));
        sstrncpy(value_list.type_instance, type_instance, sizeof(value_list.type_instance));
-       value_list.meta = NULL;
+       value_list.meta = cpy_build_meta(meta);;
        if (value_list.host[0] == 0)
                sstrncpy(value_list.host, hostname_g, sizeof(value_list.host));
        if (value_list.plugin[0] == 0)
@@ -582,17 +683,19 @@ static PyObject *Values_write(Values *self, PyObject *args, PyObject *kwds) {
 
 static PyObject *Values_repr(PyObject *s) {
        PyObject *ret, *tmp;
-       static PyObject *l_interval = NULL, *l_values = NULL, *l_closing = NULL;
+       static PyObject *l_interval = NULL, *l_values = NULL, *l_meta = NULL, *l_closing = NULL;
        Values *self = (Values *) s;
        
        if (l_interval == NULL)
                l_interval = cpy_string_to_unicode_or_bytes(",interval=");
        if (l_values == NULL)
                l_values = cpy_string_to_unicode_or_bytes(",values=");
+       if (l_meta == NULL)
+               l_meta = cpy_string_to_unicode_or_bytes(",meta=");
        if (l_closing == NULL)
                l_closing = cpy_string_to_unicode_or_bytes(")");
        
-       if (l_interval == NULL || l_values == NULL || l_closing == NULL)
+       if (l_interval == NULL || l_values == NULL || l_meta == NULL || l_closing == NULL)
                return NULL;
        
        ret = cpy_common_repr(s);
@@ -602,11 +705,16 @@ static PyObject *Values_repr(PyObject *s) {
                CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
                CPY_STRCAT_AND_DEL(&ret, tmp);
        }
-       if (self->values != NULL && PySequence_Length(self->values) > 0) {
+       if (self->values && (!PyList_Check(self->values) || PySequence_Length(self->values) > 0)) {
                CPY_STRCAT(&ret, l_values);
                tmp = PyObject_Repr(self->values);
                CPY_STRCAT_AND_DEL(&ret, tmp);
        }
+       if (self->meta && (!PyDict_Check(self->meta) || PyDict_Size(self->meta) > 0)) {
+               CPY_STRCAT(&ret, l_meta);
+               tmp = PyObject_Repr(self->meta);
+               CPY_STRCAT_AND_DEL(&ret, tmp);
+       }
        CPY_STRCAT(&ret, l_closing);
        return ret;
 }
@@ -614,12 +722,14 @@ static PyObject *Values_repr(PyObject *s) {
 static int Values_traverse(PyObject *self, visitproc visit, void *arg) {
        Values *v = (Values *) self;
        Py_VISIT(v->values);
+       Py_VISIT(v->meta);
        return 0;
 }
 
 static int Values_clear(PyObject *self) {
        Values *v = (Values *) self;
        Py_CLEAR(v->values);
+       Py_CLEAR(v->meta);
        return 0;
 }
 
@@ -631,6 +741,7 @@ static void Values_dealloc(PyObject *self) {
 static PyMemberDef Values_members[] = {
        {"interval", T_INT, offsetof(Values, interval), 0, interval_doc},
        {"values", T_OBJECT_EX, offsetof(Values, values), 0, values_doc},
+       {"meta", T_OBJECT_EX, offsetof(Values, meta), 0, meta_doc},
        {NULL}
 };
 
@@ -897,3 +1008,57 @@ PyTypeObject NotificationType = {
        0,                         /* tp_alloc */
        Notification_new           /* tp_new */
 };
+
+static const char Signed_doc[] = "This is a long by another name. Use it in meta data dicts\n"
+               "to choose the way it is stored in the meta data.";
+
+PyTypeObject SignedType = {
+       CPY_INIT_TYPE
+       "collectd.Signed",         /* tp_name */
+       sizeof(Signed),            /* tp_basicsize */
+       0,                         /* Will be filled in later */
+       0,                         /* 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*/
+       Signed_doc                 /* tp_doc */
+};
+
+static const char Unsigned_doc[] = "This is a long by another name. Use it in meta data dicts\n"
+               "to choose the way it is stored in the meta data.";
+
+PyTypeObject UnsignedType = {
+       CPY_INIT_TYPE
+       "collectd.Unsigned",       /* tp_name */
+       sizeof(Unsigned),          /* tp_basicsize */
+       0,                         /* Will be filled in later */
+       0,                         /* 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*/
+       Unsigned_doc               /* tp_doc */
+};