python: Fix python plugin crash
[collectd.git] / src / pyvalues.c
1 /**
2  * collectd - src/pyvalues.c
3  * Copyright (C) 2009  Sven Trenkel
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  *
23  * Authors:
24  *   Sven Trenkel <collectd at semidefinite.de>
25  **/
26
27 #include <Python.h>
28 #include <structmember.h>
29
30 #include "collectd.h"
31
32 #include "common.h"
33
34 #include "cpython.h"
35
36 typedef struct {
37   int (*add_string)(void *, const char *, const char *);
38   int (*add_signed_int)(void *, const char *, int64_t);
39   int (*add_unsigned_int)(void *, const char *, uint64_t);
40   int (*add_double)(void *, const char *, double);
41   int (*add_boolean)(void *, const char *, _Bool);
42 } cpy_build_meta_handler_t;
43
44 #define FreeAll()                                                              \
45   do {                                                                         \
46     PyMem_Free(type);                                                          \
47     PyMem_Free(plugin_instance);                                               \
48     PyMem_Free(type_instance);                                                 \
49     PyMem_Free(plugin);                                                        \
50     PyMem_Free(host);                                                          \
51   } while (0)
52
53 #define CPY_BUILD_META_FUNC(meta_type, func, val_type)                         \
54 static int cpy_ ## func(void *meta, const char *key, val_type val)  {          \
55   return func((meta_type *)meta, key, val);                                    \
56 }
57
58 #define CPY_BUILD_META_HANDLER(func_prefix, meta_type)                         \
59 CPY_BUILD_META_FUNC(meta_type, func_prefix ## _add_string, const char *)       \
60 CPY_BUILD_META_FUNC(meta_type, func_prefix ## _add_signed_int, int64_t)        \
61 CPY_BUILD_META_FUNC(meta_type, func_prefix ## _add_unsigned_int, uint64_t)     \
62 CPY_BUILD_META_FUNC(meta_type, func_prefix ## _add_double, double)             \
63 CPY_BUILD_META_FUNC(meta_type, func_prefix ## _add_boolean, _Bool)             \
64                                                                                \
65 static cpy_build_meta_handler_t cpy_ ## func_prefix = {                        \
66   .add_string = cpy_ ## func_prefix ## _add_string,                            \
67   .add_signed_int = cpy_ ## func_prefix ## _add_signed_int,                    \
68   .add_unsigned_int = cpy_ ## func_prefix ## _add_unsigned_int,                \
69   .add_double = cpy_ ## func_prefix ## _add_double,                            \
70   .add_boolean = cpy_ ## func_prefix ## _add_boolean                           \
71 }
72
73 static PyObject *cpy_common_repr(PyObject *s) {
74   PyObject *ret, *tmp;
75   static PyObject *l_type = NULL, *l_type_instance = NULL, *l_plugin = NULL,
76                   *l_plugin_instance = NULL;
77   static PyObject *l_host = NULL, *l_time = NULL;
78   PluginData *self = (PluginData *)s;
79
80   if (l_type == NULL)
81     l_type = cpy_string_to_unicode_or_bytes("(type=");
82   if (l_type_instance == NULL)
83     l_type_instance = cpy_string_to_unicode_or_bytes(",type_instance=");
84   if (l_plugin == NULL)
85     l_plugin = cpy_string_to_unicode_or_bytes(",plugin=");
86   if (l_plugin_instance == NULL)
87     l_plugin_instance = cpy_string_to_unicode_or_bytes(",plugin_instance=");
88   if (l_host == NULL)
89     l_host = cpy_string_to_unicode_or_bytes(",host=");
90   if (l_time == NULL)
91     l_time = cpy_string_to_unicode_or_bytes(",time=");
92
93   if (!l_type || !l_type_instance || !l_plugin || !l_plugin_instance ||
94       !l_host || !l_time)
95     return NULL;
96
97   ret = cpy_string_to_unicode_or_bytes(s->ob_type->tp_name);
98
99   CPY_STRCAT(&ret, l_type);
100   tmp = cpy_string_to_unicode_or_bytes(self->type);
101   CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
102   CPY_STRCAT_AND_DEL(&ret, tmp);
103
104   if (self->type_instance[0] != 0) {
105     CPY_STRCAT(&ret, l_type_instance);
106     tmp = cpy_string_to_unicode_or_bytes(self->type_instance);
107     CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
108     CPY_STRCAT_AND_DEL(&ret, tmp);
109   }
110
111   if (self->plugin[0] != 0) {
112     CPY_STRCAT(&ret, l_plugin);
113     tmp = cpy_string_to_unicode_or_bytes(self->plugin);
114     CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
115     CPY_STRCAT_AND_DEL(&ret, tmp);
116   }
117
118   if (self->plugin_instance[0] != 0) {
119     CPY_STRCAT(&ret, l_plugin_instance);
120     tmp = cpy_string_to_unicode_or_bytes(self->plugin_instance);
121     CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
122     CPY_STRCAT_AND_DEL(&ret, tmp);
123   }
124
125   if (self->host[0] != 0) {
126     CPY_STRCAT(&ret, l_host);
127     tmp = cpy_string_to_unicode_or_bytes(self->host);
128     CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
129     CPY_STRCAT_AND_DEL(&ret, tmp);
130   }
131
132   if (self->time != 0) {
133     CPY_STRCAT(&ret, l_time);
134     tmp = PyFloat_FromDouble(self->time);
135     CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
136     CPY_STRCAT_AND_DEL(&ret, tmp);
137   }
138   return ret;
139 }
140
141 static char time_doc[] =
142     "This is the Unix timestamp of the time this value was read.\n"
143     "For dispatching values this can be set to 0 which means \"now\".\n"
144     "This means the time the value is actually dispatched, not the time\n"
145     "it was set to 0.";
146
147 static char host_doc[] =
148     "The hostname of the host this value was read from.\n"
149     "For dispatching this can be set to an empty string which means\n"
150     "the local hostname as defined in collectd.conf.";
151
152 static char type_doc[] =
153     "The type of this value. This type has to be defined\n"
154     "in the types.db file. Attempting to set it to any other value\n"
155     "will raise a TypeError exception.\n"
156     "Assigning a type is mandatory, calling dispatch without doing\n"
157     "so will raise a RuntimeError exception.";
158
159 static char type_instance_doc[] = "";
160
161 static char plugin_doc[] =
162     "The name of the plugin that read the data. Setting this\n"
163     "member to an empty string will insert \"python\" upon dispatching.";
164
165 static char plugin_instance_doc[] = "";
166
167 static char PluginData_doc[] =
168     "This is an internal class that is the base for Values\n"
169     "and Notification. It is pretty useless by itself and is therefore not\n"
170     "exported to the collectd module.";
171
172 static PyObject *PluginData_new(PyTypeObject *type, PyObject *args,
173                                 PyObject *kwds) {
174   PluginData *self;
175
176   self = (PluginData *)type->tp_alloc(type, 0);
177   if (self == NULL)
178     return NULL;
179
180   self->time = 0;
181   self->host[0] = 0;
182   self->plugin[0] = 0;
183   self->plugin_instance[0] = 0;
184   self->type[0] = 0;
185   self->type_instance[0] = 0;
186   return (PyObject *)self;
187 }
188
189 static int PluginData_init(PyObject *s, PyObject *args, PyObject *kwds) {
190   PluginData *self = (PluginData *)s;
191   double time = 0;
192   char *type = NULL, *plugin_instance = NULL, *type_instance = NULL,
193        *plugin = NULL, *host = NULL;
194   static char *kwlist[] = {
195       "type", "plugin_instance", "type_instance", "plugin", "host", "time",
196       NULL};
197
198   if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etetetetetd", kwlist, NULL,
199                                    &type, NULL, &plugin_instance, NULL,
200                                    &type_instance, NULL, &plugin, NULL, &host,
201                                    &time))
202     return -1;
203
204   if (type && plugin_get_ds(type) == NULL) {
205     PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
206     FreeAll();
207     return -1;
208   }
209
210   sstrncpy(self->host, host ? host : "", sizeof(self->host));
211   sstrncpy(self->plugin, plugin ? plugin : "", sizeof(self->plugin));
212   sstrncpy(self->plugin_instance, plugin_instance ? plugin_instance : "",
213            sizeof(self->plugin_instance));
214   sstrncpy(self->type, type ? type : "", sizeof(self->type));
215   sstrncpy(self->type_instance, type_instance ? type_instance : "",
216            sizeof(self->type_instance));
217   self->time = time;
218
219   FreeAll();
220
221   return 0;
222 }
223
224 static PyObject *PluginData_repr(PyObject *s) {
225   PyObject *ret;
226   static PyObject *l_closing = NULL;
227
228   if (l_closing == NULL)
229     l_closing = cpy_string_to_unicode_or_bytes(")");
230
231   if (l_closing == NULL)
232     return NULL;
233
234   ret = cpy_common_repr(s);
235   CPY_STRCAT(&ret, l_closing);
236   return ret;
237 }
238
239 static PyMemberDef PluginData_members[] = {
240     {"time", T_DOUBLE, offsetof(PluginData, time), 0, time_doc}, {NULL}};
241
242 static PyObject *PluginData_getstring(PyObject *self, void *data) {
243   const char *value = ((char *)self) + (intptr_t)data;
244
245   return cpy_string_to_unicode_or_bytes(value);
246 }
247
248 static int PluginData_setstring(PyObject *self, PyObject *value, void *data) {
249   char *old;
250   const char *new;
251
252   if (value == NULL) {
253     PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute");
254     return -1;
255   }
256   Py_INCREF(value);
257   new = cpy_unicode_or_bytes_to_string(&value);
258   if (new == NULL) {
259     Py_DECREF(value);
260     return -1;
261   }
262   old = ((char *)self) + (intptr_t)data;
263   sstrncpy(old, new, DATA_MAX_NAME_LEN);
264   Py_DECREF(value);
265   return 0;
266 }
267
268 static int PluginData_settype(PyObject *self, PyObject *value, void *data) {
269   char *old;
270   const char *new;
271
272   if (value == NULL) {
273     PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute");
274     return -1;
275   }
276   Py_INCREF(value);
277   new = cpy_unicode_or_bytes_to_string(&value);
278   if (new == NULL) {
279     Py_DECREF(value);
280     return -1;
281   }
282
283   if (plugin_get_ds(new) == NULL) {
284     PyErr_Format(PyExc_TypeError, "Dataset %s not found", new);
285     Py_DECREF(value);
286     return -1;
287   }
288
289   old = ((char *)self) + (intptr_t)data;
290   sstrncpy(old, new, DATA_MAX_NAME_LEN);
291   Py_DECREF(value);
292   return 0;
293 }
294
295 static PyGetSetDef PluginData_getseters[] = {
296     {"host", PluginData_getstring, PluginData_setstring, host_doc,
297      (void *)offsetof(PluginData, host)},
298     {"plugin", PluginData_getstring, PluginData_setstring, plugin_doc,
299      (void *)offsetof(PluginData, plugin)},
300     {"plugin_instance", PluginData_getstring, PluginData_setstring,
301      plugin_instance_doc, (void *)offsetof(PluginData, plugin_instance)},
302     {"type_instance", PluginData_getstring, PluginData_setstring,
303      type_instance_doc, (void *)offsetof(PluginData, type_instance)},
304     {"type", PluginData_getstring, PluginData_settype, type_doc,
305      (void *)offsetof(PluginData, type)},
306     {NULL}};
307
308 PyTypeObject PluginDataType = {
309     CPY_INIT_TYPE "collectd.PluginData", /* tp_name */
310     sizeof(PluginData),                  /* tp_basicsize */
311     0,                                   /* Will be filled in later */
312     0,                                   /* tp_dealloc */
313     0,                                   /* tp_print */
314     0,                                   /* tp_getattr */
315     0,                                   /* tp_setattr */
316     0,                                   /* tp_compare */
317     PluginData_repr,                     /* tp_repr */
318     0,                                   /* tp_as_number */
319     0,                                   /* tp_as_sequence */
320     0,                                   /* tp_as_mapping */
321     0,                                   /* tp_hash */
322     0,                                   /* tp_call */
323     0,                                   /* tp_str */
324     0,                                   /* tp_getattro */
325     0,                                   /* tp_setattro */
326     0,                                   /* tp_as_buffer */
327     Py_TPFLAGS_DEFAULT |
328         Py_TPFLAGS_BASETYPE /*| Py_TPFLAGS_HAVE_GC*/, /*tp_flags*/
329     PluginData_doc,                                   /* tp_doc */
330     0,                                                /* tp_traverse */
331     0,                                                /* tp_clear */
332     0,                                                /* tp_richcompare */
333     0,                                                /* tp_weaklistoffset */
334     0,                                                /* tp_iter */
335     0,                                                /* tp_iternext */
336     0,                                                /* tp_methods */
337     PluginData_members,                               /* tp_members */
338     PluginData_getseters,                             /* tp_getset */
339     0,                                                /* tp_base */
340     0,                                                /* tp_dict */
341     0,                                                /* tp_descr_get */
342     0,                                                /* tp_descr_set */
343     0,                                                /* tp_dictoffset */
344     PluginData_init,                                  /* tp_init */
345     0,                                                /* tp_alloc */
346     PluginData_new                                    /* tp_new */
347 };
348
349 static char interval_doc[] =
350     "The interval is the timespan in seconds between two submits for\n"
351     "the same data source. This value has to be a positive integer, so you "
352     "can't\n"
353     "submit more than one value per second. If this member is set to a\n"
354     "non-positive value, the default value as specified in the config file "
355     "will\n"
356     "be used (default: 10).\n"
357     "\n"
358     "If you submit values more often than the specified interval, the average\n"
359     "will be used. If you submit less values, your graphs will have gaps.";
360
361 static char values_doc[] =
362     "These are the actual values that get dispatched to collectd.\n"
363     "It has to be a sequence (a tuple or list) of numbers.\n"
364     "The size of the sequence and the type of its content depend on the type\n"
365     "member in the types.db file. For more information on this read the\n"
366     "types.db man page.\n"
367     "\n"
368     "If the sequence does not have the correct size upon dispatch a "
369     "RuntimeError\n"
370     "exception will be raised. If the content of the sequence is not a "
371     "number,\n"
372     "a TypeError exception will be raised.";
373
374 static char meta_doc[] =
375     "These are the meta data for this Value object.\n"
376     "It has to be a dictionary of numbers, strings or bools. All keys must be\n"
377     "strings. int and long objects will be dispatched as signed integers "
378     "unless\n"
379     "they are between 2**63 and 2**64-1, which will result in an unsigned "
380     "integer.\n"
381     "You can force one of these storage classes by using the classes\n"
382     "collectd.Signed and collectd.Unsigned. A meta object received by a write\n"
383     "callback will always contain Signed or Unsigned objects.";
384
385 static char dispatch_doc[] =
386     "dispatch([type][, values][, plugin_instance][, type_instance]"
387     "[, plugin][, host][, time][, interval]) -> None.  Dispatch a value list.\n"
388     "\n"
389     "Dispatch this instance to the collectd process. The object has members\n"
390     "for each of the possible arguments for this method. For a detailed "
391     "explanation\n"
392     "of these parameters see the member of the same same.\n"
393     "\n"
394     "If you do not submit a parameter the value saved in its member will be "
395     "submitted.\n"
396     "If you do provide a parameter it will be used instead, without altering "
397     "the member.";
398
399 static char write_doc[] =
400     "write([destination][, type][, values][, plugin_instance][, type_instance]"
401     "[, plugin][, host][, time][, interval]) -> None.  Dispatch a value list.\n"
402     "\n"
403     "Write this instance to a single plugin or all plugins if 'destination' is "
404     "omitted.\n"
405     "This will bypass the main collectd process and all filtering and "
406     "caching.\n"
407     "Other than that it works similar to 'dispatch'. In most cases 'dispatch' "
408     "should be\n"
409     "used instead of 'write'.\n";
410
411 static char Values_doc[] = "A Values object used for dispatching values to "
412                            "collectd and receiving values from write "
413                            "callbacks.";
414
415 static PyObject *Values_new(PyTypeObject *type, PyObject *args,
416                             PyObject *kwds) {
417   Values *self;
418
419   self = (Values *)PluginData_new(type, args, kwds);
420   if (self == NULL)
421     return NULL;
422
423   self->values = PyList_New(0);
424   self->meta = PyDict_New();
425   self->interval = 0;
426   return (PyObject *)self;
427 }
428
429 static int Values_init(PyObject *s, PyObject *args, PyObject *kwds) {
430   Values *self = (Values *)s;
431   double interval = 0, time = 0;
432   PyObject *values = NULL, *meta = NULL, *tmp;
433   char *type = NULL, *plugin_instance = NULL, *type_instance = NULL,
434        *plugin = NULL, *host = NULL;
435   static char *kwlist[] = {
436       "type", "values", "plugin_instance", "type_instance", "plugin",
437       "host", "time",   "interval",        "meta",          NULL};
438
439   if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etOetetetetddO", kwlist, NULL,
440                                    &type, &values, NULL, &plugin_instance, NULL,
441                                    &type_instance, NULL, &plugin, NULL, &host,
442                                    &time, &interval, &meta))
443     return -1;
444
445   if (type && plugin_get_ds(type) == NULL) {
446     PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
447     FreeAll();
448     return -1;
449   }
450
451   sstrncpy(self->data.host, host ? host : "", sizeof(self->data.host));
452   sstrncpy(self->data.plugin, plugin ? plugin : "", sizeof(self->data.plugin));
453   sstrncpy(self->data.plugin_instance, plugin_instance ? plugin_instance : "",
454            sizeof(self->data.plugin_instance));
455   sstrncpy(self->data.type, type ? type : "", sizeof(self->data.type));
456   sstrncpy(self->data.type_instance, type_instance ? type_instance : "",
457            sizeof(self->data.type_instance));
458   self->data.time = time;
459
460   FreeAll();
461
462   if (values == NULL) {
463     values = PyList_New(0);
464     PyErr_Clear();
465   } else {
466     Py_INCREF(values);
467   }
468
469   if (meta == NULL) {
470     meta = PyDict_New();
471     PyErr_Clear();
472   } else {
473     Py_INCREF(meta);
474   }
475
476   tmp = self->values;
477   self->values = values;
478   Py_XDECREF(tmp);
479
480   tmp = self->meta;
481   self->meta = meta;
482   Py_XDECREF(tmp);
483
484   self->interval = interval;
485   return 0;
486 }
487
488 static int cpy_build_meta(PyObject *meta, cpy_build_meta_handler_t *meta_func,
489                           void *m) {
490   int s;
491   PyObject *l;
492
493   if ((meta == NULL) || (meta == Py_None))
494     return -1;
495
496   l = PyDict_Items(meta); /* New reference. */
497   if (!l) {
498     cpy_log_exception("building meta data");
499     return -1;
500   }
501   s = PyList_Size(l);
502   if (s <= 0) {
503     Py_XDECREF(l);
504     return -1;
505   }
506
507   for (int i = 0; i < s; ++i) {
508     const char *string, *keystring;
509     PyObject *key, *value, *item, *tmp;
510
511     item = PyList_GET_ITEM(l, i);
512     key = PyTuple_GET_ITEM(item, 0);
513     Py_INCREF(key);
514     keystring = cpy_unicode_or_bytes_to_string(&key);
515     if (!keystring) {
516       PyErr_Clear();
517       Py_XDECREF(key);
518       continue;
519     }
520     value = PyTuple_GET_ITEM(item, 1);
521     Py_INCREF(value);
522     if (value == Py_True) {
523       meta_func->add_boolean(m, keystring, 1);
524     } else if (value == Py_False) {
525       meta_func->add_boolean(m, keystring, 0);
526     } else if (PyFloat_Check(value)) {
527       meta_func->add_double(m, keystring, PyFloat_AsDouble(value));
528     } else if (PyObject_TypeCheck(value, &SignedType)) {
529       long long int lli;
530       lli = PyLong_AsLongLong(value);
531       if (!PyErr_Occurred() && (lli == (int64_t)lli))
532         meta_func->add_signed_int(m, keystring, lli);
533     } else if (PyObject_TypeCheck(value, &UnsignedType)) {
534       long long unsigned llu;
535       llu = PyLong_AsUnsignedLongLong(value);
536       if (!PyErr_Occurred() && (llu == (uint64_t)llu))
537         meta_func->add_unsigned_int(m, keystring, llu);
538     } else if (PyNumber_Check(value)) {
539       long long int lli;
540       long long unsigned llu;
541       tmp = PyNumber_Long(value);
542       lli = PyLong_AsLongLong(tmp);
543       if (!PyErr_Occurred() && (lli == (int64_t)lli)) {
544         meta_func->add_signed_int(m, keystring, lli);
545       } else {
546         PyErr_Clear();
547         llu = PyLong_AsUnsignedLongLong(tmp);
548         if (!PyErr_Occurred() && (llu == (uint64_t)llu))
549           meta_func->add_unsigned_int(m, keystring, llu);
550       }
551       Py_XDECREF(tmp);
552     } else {
553       string = cpy_unicode_or_bytes_to_string(&value);
554       if (string) {
555         meta_func->add_string(m, keystring, string);
556       } else {
557         PyErr_Clear();
558         tmp = PyObject_Str(value);
559         string = cpy_unicode_or_bytes_to_string(&tmp);
560         if (string)
561           meta_func->add_string(m, keystring, string);
562         Py_XDECREF(tmp);
563       }
564     }
565     if (PyErr_Occurred())
566       cpy_log_exception("building meta data");
567     Py_XDECREF(value);
568     Py_DECREF(key);
569   }
570   Py_XDECREF(l);
571   return 0;
572 }
573
574 CPY_BUILD_META_HANDLER(meta_data, meta_data_t);
575 CPY_BUILD_META_HANDLER(plugin_notification_meta, notification_t);
576
577 static meta_data_t *cpy_build_value_meta(PyObject *meta) {
578   meta_data_t *m = meta_data_create();
579   if (cpy_build_meta(meta, &cpy_meta_data, (void *)m) < 0) {
580     meta_data_destroy(m);
581     return NULL;
582   }
583   return m;
584 }
585
586 static void cpy_build_notification_meta(notification_t *n, PyObject *meta) {
587   cpy_build_meta(meta, &cpy_plugin_notification_meta, (void *)n);
588 }
589
590 static PyObject *Values_dispatch(Values *self, PyObject *args, PyObject *kwds) {
591   int ret;
592   const data_set_t *ds;
593   size_t size;
594   value_t *value;
595   value_list_t value_list = VALUE_LIST_INIT;
596   PyObject *values = self->values, *meta = self->meta;
597   double time = self->data.time, interval = self->interval;
598   char *host = NULL, *plugin = NULL, *plugin_instance = NULL, *type = NULL,
599        *type_instance = NULL;
600
601   static char *kwlist[] = {
602       "type", "values", "plugin_instance", "type_instance", "plugin",
603       "host", "time",   "interval",        "meta",          NULL};
604   if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etOetetetetddO", kwlist, NULL,
605                                    &type, &values, NULL, &plugin_instance, NULL,
606                                    &type_instance, NULL, &plugin, NULL, &host,
607                                    &time, &interval, &meta))
608     return NULL;
609
610   sstrncpy(value_list.host, host ? host : self->data.host,
611            sizeof(value_list.host));
612   sstrncpy(value_list.plugin, plugin ? plugin : self->data.plugin,
613            sizeof(value_list.plugin));
614   sstrncpy(value_list.plugin_instance,
615            plugin_instance ? plugin_instance : self->data.plugin_instance,
616            sizeof(value_list.plugin_instance));
617   sstrncpy(value_list.type, type ? type : self->data.type,
618            sizeof(value_list.type));
619   sstrncpy(value_list.type_instance,
620            type_instance ? type_instance : self->data.type_instance,
621            sizeof(value_list.type_instance));
622   FreeAll();
623   if (value_list.type[0] == 0) {
624     PyErr_SetString(PyExc_RuntimeError, "type not set");
625     FreeAll();
626     return NULL;
627   }
628   ds = plugin_get_ds(value_list.type);
629   if (ds == NULL) {
630     PyErr_Format(PyExc_TypeError, "Dataset %s not found", value_list.type);
631     return NULL;
632   }
633   if (values == NULL ||
634       (PyTuple_Check(values) == 0 && PyList_Check(values) == 0)) {
635     PyErr_Format(PyExc_TypeError, "values must be list or tuple");
636     return NULL;
637   }
638   if (meta != NULL && meta != Py_None && !PyDict_Check(meta)) {
639     PyErr_Format(PyExc_TypeError, "meta must be a dict");
640     return NULL;
641   }
642   size = (size_t)PySequence_Length(values);
643   if (size != ds->ds_num) {
644     PyErr_Format(PyExc_RuntimeError, "type %s needs %zu values, got %zu",
645                  value_list.type, ds->ds_num, size);
646     return NULL;
647   }
648   value = calloc(size, sizeof(*value));
649   for (size_t i = 0; i < size; ++i) {
650     PyObject *item, *num;
651     item = PySequence_Fast_GET_ITEM(values, (int)i); /* Borrowed reference. */
652     switch (ds->ds[i].type) {
653     case DS_TYPE_COUNTER:
654       num = PyNumber_Long(item); /* New reference. */
655       if (num != NULL) {
656         value[i].counter = PyLong_AsUnsignedLongLong(num);
657         Py_XDECREF(num);
658       }
659       break;
660     case DS_TYPE_GAUGE:
661       num = PyNumber_Float(item); /* New reference. */
662       if (num != NULL) {
663         value[i].gauge = PyFloat_AsDouble(num);
664         Py_XDECREF(num);
665       }
666       break;
667     case DS_TYPE_DERIVE:
668       /* This might overflow without raising an exception.
669        * Not much we can do about it */
670       num = PyNumber_Long(item); /* New reference. */
671       if (num != NULL) {
672         value[i].derive = PyLong_AsLongLong(num);
673         Py_XDECREF(num);
674       }
675       break;
676     case DS_TYPE_ABSOLUTE:
677       /* This might overflow without raising an exception.
678        * Not much we can do about it */
679       num = PyNumber_Long(item); /* New reference. */
680       if (num != NULL) {
681         value[i].absolute = PyLong_AsUnsignedLongLong(num);
682         Py_XDECREF(num);
683       }
684       break;
685     default:
686       free(value);
687       PyErr_Format(PyExc_RuntimeError, "unknown data type %d for %s",
688                    ds->ds[i].type, value_list.type);
689       return NULL;
690     }
691     if (PyErr_Occurred() != NULL) {
692       free(value);
693       return NULL;
694     }
695   }
696   value_list.values = value;
697   value_list.meta = cpy_build_value_meta(meta);
698   value_list.values_len = size;
699   value_list.time = DOUBLE_TO_CDTIME_T(time);
700   value_list.interval = DOUBLE_TO_CDTIME_T(interval);
701   if (value_list.host[0] == 0)
702     sstrncpy(value_list.host, hostname_g, sizeof(value_list.host));
703   if (value_list.plugin[0] == 0)
704     sstrncpy(value_list.plugin, "python", sizeof(value_list.plugin));
705   Py_BEGIN_ALLOW_THREADS;
706   ret = plugin_dispatch_values(&value_list);
707   Py_END_ALLOW_THREADS;
708   meta_data_destroy(value_list.meta);
709   free(value);
710   if (ret != 0) {
711     PyErr_SetString(PyExc_RuntimeError,
712                     "error dispatching values, read the logs");
713     return NULL;
714   }
715   Py_RETURN_NONE;
716 }
717
718 static PyObject *Values_write(Values *self, PyObject *args, PyObject *kwds) {
719   int ret;
720   const data_set_t *ds;
721   size_t size;
722   value_t *value;
723   value_list_t value_list = VALUE_LIST_INIT;
724   PyObject *values = self->values, *meta = self->meta;
725   double time = self->data.time, interval = self->interval;
726   char *host = NULL, *plugin = NULL, *plugin_instance = NULL, *type = NULL,
727        *type_instance = NULL, *dest = NULL;
728
729   static char *kwlist[] = {
730       "destination",   "type",   "values", "plugin_instance",
731       "type_instance", "plugin", "host",   "time",
732       "interval",      "meta",   NULL};
733   if (!PyArg_ParseTupleAndKeywords(
734           args, kwds, "et|etOetetetetdiO", kwlist, NULL, &dest, NULL, &type,
735           &values, NULL, &plugin_instance, NULL, &type_instance, NULL, &plugin,
736           NULL, &host, &time, &interval, &meta))
737     return NULL;
738
739   sstrncpy(value_list.host, host ? host : self->data.host,
740            sizeof(value_list.host));
741   sstrncpy(value_list.plugin, plugin ? plugin : self->data.plugin,
742            sizeof(value_list.plugin));
743   sstrncpy(value_list.plugin_instance,
744            plugin_instance ? plugin_instance : self->data.plugin_instance,
745            sizeof(value_list.plugin_instance));
746   sstrncpy(value_list.type, type ? type : self->data.type,
747            sizeof(value_list.type));
748   sstrncpy(value_list.type_instance,
749            type_instance ? type_instance : self->data.type_instance,
750            sizeof(value_list.type_instance));
751   FreeAll();
752   if (value_list.type[0] == 0) {
753     PyErr_SetString(PyExc_RuntimeError, "type not set");
754     return NULL;
755   }
756   ds = plugin_get_ds(value_list.type);
757   if (ds == NULL) {
758     PyErr_Format(PyExc_TypeError, "Dataset %s not found", value_list.type);
759     return NULL;
760   }
761   if (values == NULL ||
762       (PyTuple_Check(values) == 0 && PyList_Check(values) == 0)) {
763     PyErr_Format(PyExc_TypeError, "values must be list or tuple");
764     return NULL;
765   }
766   size = (size_t)PySequence_Length(values);
767   if (size != ds->ds_num) {
768     PyErr_Format(PyExc_RuntimeError, "type %s needs %zu values, got %zu",
769                  value_list.type, ds->ds_num, size);
770     return NULL;
771   }
772   value = calloc(size, sizeof(*value));
773   for (size_t i = 0; i < size; ++i) {
774     PyObject *item, *num;
775     item = PySequence_Fast_GET_ITEM(values, i); /* Borrowed reference. */
776     switch (ds->ds[i].type) {
777     case DS_TYPE_COUNTER:
778       num = PyNumber_Long(item); /* New reference. */
779       if (num != NULL) {
780         value[i].counter = PyLong_AsUnsignedLongLong(num);
781         Py_XDECREF(num);
782       }
783       break;
784     case DS_TYPE_GAUGE:
785       num = PyNumber_Float(item); /* New reference. */
786       if (num != NULL) {
787         value[i].gauge = PyFloat_AsDouble(num);
788         Py_XDECREF(num);
789       }
790       break;
791     case DS_TYPE_DERIVE:
792       /* This might overflow without raising an exception.
793        * Not much we can do about it */
794       num = PyNumber_Long(item); /* New reference. */
795       if (num != NULL) {
796         value[i].derive = PyLong_AsLongLong(num);
797         Py_XDECREF(num);
798       }
799       break;
800     case DS_TYPE_ABSOLUTE:
801       /* This might overflow without raising an exception.
802        * Not much we can do about it */
803       num = PyNumber_Long(item); /* New reference. */
804       if (num != NULL) {
805         value[i].absolute = PyLong_AsUnsignedLongLong(num);
806         Py_XDECREF(num);
807       }
808       break;
809     default:
810       free(value);
811       PyErr_Format(PyExc_RuntimeError, "unknown data type %d for %s",
812                    ds->ds[i].type, value_list.type);
813       return NULL;
814     }
815     if (PyErr_Occurred() != NULL) {
816       free(value);
817       return NULL;
818     }
819   }
820   value_list.values = value;
821   value_list.values_len = size;
822   value_list.time = DOUBLE_TO_CDTIME_T(time);
823   value_list.interval = DOUBLE_TO_CDTIME_T(interval);
824   value_list.meta = cpy_build_value_meta(meta);
825   if (value_list.host[0] == 0)
826     sstrncpy(value_list.host, hostname_g, sizeof(value_list.host));
827   if (value_list.plugin[0] == 0)
828     sstrncpy(value_list.plugin, "python", sizeof(value_list.plugin));
829   Py_BEGIN_ALLOW_THREADS;
830   ret = plugin_write(dest, NULL, &value_list);
831   Py_END_ALLOW_THREADS;
832   meta_data_destroy(value_list.meta);
833   free(value);
834   if (ret != 0) {
835     PyErr_SetString(PyExc_RuntimeError,
836                     "error dispatching values, read the logs");
837     return NULL;
838   }
839   Py_RETURN_NONE;
840 }
841
842 static PyObject *Values_repr(PyObject *s) {
843   PyObject *ret, *tmp;
844   static PyObject *l_interval = NULL, *l_values = NULL, *l_meta = NULL,
845                   *l_closing = NULL;
846   Values *self = (Values *)s;
847
848   if (l_interval == NULL)
849     l_interval = cpy_string_to_unicode_or_bytes(",interval=");
850   if (l_values == NULL)
851     l_values = cpy_string_to_unicode_or_bytes(",values=");
852   if (l_meta == NULL)
853     l_meta = cpy_string_to_unicode_or_bytes(",meta=");
854   if (l_closing == NULL)
855     l_closing = cpy_string_to_unicode_or_bytes(")");
856
857   if (l_interval == NULL || l_values == NULL || l_meta == NULL ||
858       l_closing == NULL)
859     return NULL;
860
861   ret = cpy_common_repr(s);
862   if (self->interval != 0) {
863     CPY_STRCAT(&ret, l_interval);
864     tmp = PyFloat_FromDouble(self->interval);
865     CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
866     CPY_STRCAT_AND_DEL(&ret, tmp);
867   }
868   if (self->values &&
869       (!PyList_Check(self->values) || PySequence_Length(self->values) > 0)) {
870     CPY_STRCAT(&ret, l_values);
871     tmp = PyObject_Repr(self->values);
872     CPY_STRCAT_AND_DEL(&ret, tmp);
873   }
874   if (self->meta &&
875       (!PyDict_Check(self->meta) || PyDict_Size(self->meta) > 0)) {
876     CPY_STRCAT(&ret, l_meta);
877     tmp = PyObject_Repr(self->meta);
878     CPY_STRCAT_AND_DEL(&ret, tmp);
879   }
880   CPY_STRCAT(&ret, l_closing);
881   return ret;
882 }
883
884 static int Values_traverse(PyObject *self, visitproc visit, void *arg) {
885   Values *v = (Values *)self;
886   Py_VISIT(v->values);
887   Py_VISIT(v->meta);
888   return 0;
889 }
890
891 static int Values_clear(PyObject *self) {
892   Values *v = (Values *)self;
893   Py_CLEAR(v->values);
894   Py_CLEAR(v->meta);
895   return 0;
896 }
897
898 static void Values_dealloc(PyObject *self) {
899   Values_clear(self);
900   self->ob_type->tp_free(self);
901 }
902
903 static PyMemberDef Values_members[] = {
904     {"interval", T_DOUBLE, offsetof(Values, interval), 0, interval_doc},
905     {"values", T_OBJECT_EX, offsetof(Values, values), 0, values_doc},
906     {"meta", T_OBJECT_EX, offsetof(Values, meta), 0, meta_doc},
907     {NULL}};
908
909 static PyMethodDef Values_methods[] = {
910     {"dispatch", (PyCFunction)Values_dispatch, METH_VARARGS | METH_KEYWORDS,
911      dispatch_doc},
912     {"write", (PyCFunction)Values_write, METH_VARARGS | METH_KEYWORDS,
913      write_doc},
914     {NULL}};
915
916 PyTypeObject ValuesType = {
917     CPY_INIT_TYPE "collectd.Values", /* tp_name */
918     sizeof(Values),                  /* tp_basicsize */
919     0,                               /* Will be filled in later */
920     Values_dealloc,                  /* tp_dealloc */
921     0,                               /* tp_print */
922     0,                               /* tp_getattr */
923     0,                               /* tp_setattr */
924     0,                               /* tp_compare */
925     Values_repr,                     /* tp_repr */
926     0,                               /* tp_as_number */
927     0,                               /* tp_as_sequence */
928     0,                               /* tp_as_mapping */
929     0,                               /* tp_hash */
930     0,                               /* tp_call */
931     0,                               /* tp_str */
932     0,                               /* tp_getattro */
933     0,                               /* tp_setattro */
934     0,                               /* tp_as_buffer */
935     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
936     Values_doc,                                                    /* tp_doc */
937     Values_traverse, /* tp_traverse */
938     Values_clear,    /* tp_clear */
939     0,               /* tp_richcompare */
940     0,               /* tp_weaklistoffset */
941     0,               /* tp_iter */
942     0,               /* tp_iternext */
943     Values_methods,  /* tp_methods */
944     Values_members,  /* tp_members */
945     0,               /* tp_getset */
946     0,               /* tp_base */
947     0,               /* tp_dict */
948     0,               /* tp_descr_get */
949     0,               /* tp_descr_set */
950     0,               /* tp_dictoffset */
951     Values_init,     /* tp_init */
952     0,               /* tp_alloc */
953     Values_new       /* tp_new */
954 };
955
956 static char notification_meta_doc[] =
957     "These are the meta data for the Notification object.\n"
958     "It has to be a dictionary of numbers, strings or bools. All keys must be\n"
959     "strings. int and long objects will be dispatched as signed integers "
960     "unless\n"
961     "they are between 2**63 and 2**64-1, which will result in an unsigned "
962     "integer.\n"
963     "One of these storage classes can be forced by using the classes\n"
964     "collectd.Signed and collectd.Unsigned. A meta object received by a\n"
965     "notification callback will always contain Signed or Unsigned objects.";
966
967 static char severity_doc[] =
968     "The severity of this notification. Assign or compare to\n"
969     "NOTIF_FAILURE, NOTIF_WARNING or NOTIF_OKAY.";
970
971 static char message_doc[] = "Some kind of description what's going on and why "
972                             "this Notification was generated.";
973
974 static char Notification_doc[] =
975     "The Notification class is a wrapper around the collectd notification.\n"
976     "It can be used to notify other plugins about bad stuff happening. It "
977     "works\n"
978     "similar to Values but has a severity and a message instead of interval\n"
979     "and time.\n"
980     "Notifications can be dispatched at any time and can be received with "
981     "register_notification.";
982
983 static int Notification_init(PyObject *s, PyObject *args, PyObject *kwds) {
984   Notification *self = (Notification *)s;
985   int severity = 0;
986   double time = 0;
987   char *message = NULL;
988   PyObject *meta = NULL;
989   char *type = NULL, *plugin_instance = NULL, *type_instance = NULL,
990        *plugin = NULL, *host = NULL;
991   static char *kwlist[] = {"type",          "message",  "plugin_instance",
992                            "type_instance", "plugin",   "host",
993                            "time",          "severity", "meta",
994                            NULL};
995
996   if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etetetetetetdiO", kwlist, NULL,
997                                    &type, NULL, &message, NULL,
998                                    &plugin_instance, NULL, &type_instance, NULL,
999                                    &plugin, NULL, &host, &time, &severity, &meta))
1000     return -1;
1001
1002   if (type && plugin_get_ds(type) == NULL) {
1003     PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
1004     FreeAll();
1005     PyMem_Free(message);
1006     return -1;
1007   }
1008
1009   sstrncpy(self->data.host, host ? host : "", sizeof(self->data.host));
1010   sstrncpy(self->data.plugin, plugin ? plugin : "", sizeof(self->data.plugin));
1011   sstrncpy(self->data.plugin_instance, plugin_instance ? plugin_instance : "",
1012            sizeof(self->data.plugin_instance));
1013   sstrncpy(self->data.type, type ? type : "", sizeof(self->data.type));
1014   sstrncpy(self->data.type_instance, type_instance ? type_instance : "",
1015            sizeof(self->data.type_instance));
1016   sstrncpy(self->message, message ? message : "", sizeof(self->message));
1017   self->data.time = time;
1018   self->severity = severity;
1019
1020   FreeAll();
1021   PyMem_Free(message);
1022
1023   if (meta == NULL) {
1024     meta = PyDict_New();
1025     PyErr_Clear();
1026   } else {
1027     Py_INCREF(meta);
1028   }
1029
1030   PyObject *tmp = self->meta;
1031   self->meta = meta;
1032   Py_XDECREF(tmp);
1033
1034   return 0;
1035 }
1036
1037 static PyObject *Notification_dispatch(Notification *self, PyObject *args,
1038                                        PyObject *kwds) {
1039   int ret;
1040   const data_set_t *ds;
1041   notification_t notification;
1042   double t = self->data.time;
1043   PyObject *meta = self->meta;
1044   int severity = self->severity;
1045   char *host = NULL, *plugin = NULL, *plugin_instance = NULL, *type = NULL,
1046        *type_instance = NULL;
1047   char *message = NULL;
1048
1049   static char *kwlist[] = {"type",          "message",  "plugin_instance",
1050                            "type_instance", "plugin",   "host",
1051                            "time",          "severity", "meta",
1052                            NULL};
1053   if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etetetetetetdiO", kwlist, NULL,
1054                                    &type, NULL, &message, NULL,
1055                                    &plugin_instance, NULL, &type_instance, NULL,
1056                                    &plugin, NULL, &host, &t, &severity, &meta))
1057     return NULL;
1058
1059   notification.time = DOUBLE_TO_CDTIME_T(t);
1060   notification.severity = severity;
1061   sstrncpy(notification.message, message ? message : self->message,
1062            sizeof(notification.message));
1063   sstrncpy(notification.host, host ? host : self->data.host,
1064            sizeof(notification.host));
1065   sstrncpy(notification.plugin, plugin ? plugin : self->data.plugin,
1066            sizeof(notification.plugin));
1067   sstrncpy(notification.plugin_instance,
1068            plugin_instance ? plugin_instance : self->data.plugin_instance,
1069            sizeof(notification.plugin_instance));
1070   sstrncpy(notification.type, type ? type : self->data.type,
1071            sizeof(notification.type));
1072   sstrncpy(notification.type_instance,
1073            type_instance ? type_instance : self->data.type_instance,
1074            sizeof(notification.type_instance));
1075   notification.meta = NULL;
1076   FreeAll();
1077   PyMem_Free(message);
1078
1079   if (notification.type[0] == 0) {
1080     PyErr_SetString(PyExc_RuntimeError, "type not set");
1081     return NULL;
1082   }
1083   ds = plugin_get_ds(notification.type);
1084   if (ds == NULL) {
1085     PyErr_Format(PyExc_TypeError, "Dataset %s not found", notification.type);
1086     return NULL;
1087   }
1088   if (meta != NULL && meta != Py_None && !PyDict_Check(meta)) {
1089     PyErr_Format(PyExc_TypeError, "meta must be a dict");
1090     return NULL;
1091   }
1092   cpy_build_notification_meta(&notification, meta);
1093
1094   if (notification.time == 0)
1095     notification.time = cdtime();
1096   if (notification.host[0] == 0)
1097     sstrncpy(notification.host, hostname_g, sizeof(notification.host));
1098   if (notification.plugin[0] == 0)
1099     sstrncpy(notification.plugin, "python", sizeof(notification.plugin));
1100   Py_BEGIN_ALLOW_THREADS;
1101   ret = plugin_dispatch_notification(&notification);
1102   if (notification.meta)
1103     plugin_notification_meta_free(notification.meta);
1104   Py_END_ALLOW_THREADS;
1105   if (ret != 0) {
1106     PyErr_SetString(PyExc_RuntimeError,
1107                     "error dispatching notification, read the logs");
1108     return NULL;
1109   }
1110   Py_RETURN_NONE;
1111 }
1112
1113 static PyObject *Notification_new(PyTypeObject *type, PyObject *args,
1114                                   PyObject *kwds) {
1115   Notification *self;
1116
1117   self = (Notification *)PluginData_new(type, args, kwds);
1118   if (self == NULL)
1119     return NULL;
1120
1121   self->meta = PyDict_New();
1122   self->message[0] = 0;
1123   self->severity = 0;
1124   return (PyObject *)self;
1125 }
1126
1127 static int Notification_setstring(PyObject *self, PyObject *value, void *data) {
1128   char *old;
1129   const char *new;
1130
1131   if (value == NULL) {
1132     PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute");
1133     return -1;
1134   }
1135   Py_INCREF(value);
1136   new = cpy_unicode_or_bytes_to_string(&value);
1137   if (new == NULL) {
1138     Py_DECREF(value);
1139     return -1;
1140   }
1141   old = ((char *)self) + (intptr_t)data;
1142   sstrncpy(old, new, NOTIF_MAX_MSG_LEN);
1143   Py_DECREF(value);
1144   return 0;
1145 }
1146
1147 static PyObject *Notification_repr(PyObject *s) {
1148   PyObject *ret, *tmp;
1149   static PyObject *l_severity = NULL, *l_message = NULL, *l_meta = NULL,
1150                   *l_closing = NULL;
1151   Notification *self = (Notification *)s;
1152
1153   if (l_severity == NULL)
1154     l_severity = cpy_string_to_unicode_or_bytes(",severity=");
1155   if (l_message == NULL)
1156     l_message = cpy_string_to_unicode_or_bytes(",message=");
1157   if (l_meta == NULL)
1158     l_meta = cpy_string_to_unicode_or_bytes(",meta=");
1159   if (l_closing == NULL)
1160     l_closing = cpy_string_to_unicode_or_bytes(")");
1161
1162   if (l_severity == NULL || l_message == NULL || l_meta == NULL ||
1163       l_closing == NULL)
1164     return NULL;
1165
1166   ret = cpy_common_repr(s);
1167   if (self->severity != 0) {
1168     CPY_STRCAT(&ret, l_severity);
1169     tmp = PyInt_FromLong(self->severity);
1170     CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
1171     CPY_STRCAT_AND_DEL(&ret, tmp);
1172   }
1173   if (self->message[0] != 0) {
1174     CPY_STRCAT(&ret, l_message);
1175     tmp = cpy_string_to_unicode_or_bytes(self->message);
1176     CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
1177     CPY_STRCAT_AND_DEL(&ret, tmp);
1178   }
1179   if (self->meta &&
1180       (!PyDict_Check(self->meta) || PyDict_Size(self->meta) > 0)) {
1181     CPY_STRCAT(&ret, l_meta);
1182     tmp = PyObject_Repr(self->meta);
1183     CPY_STRCAT_AND_DEL(&ret, tmp);
1184   }
1185   CPY_STRCAT(&ret, l_closing);
1186   return ret;
1187 }
1188
1189 static int Notification_traverse(PyObject *self, visitproc visit, void *arg) {
1190   Notification *n = (Notification *)self;
1191   Py_VISIT(n->meta);
1192   return 0;
1193 }
1194
1195 static int Notification_clear(PyObject *self) {
1196   Notification *n = (Notification *)self;
1197   Py_CLEAR(n->meta);
1198   return 0;
1199 }
1200
1201 static void Notification_dealloc(PyObject *self) {
1202   Notification_clear(self);
1203   self->ob_type->tp_free(self);
1204 }
1205
1206 static PyMethodDef Notification_methods[] = {
1207     {"dispatch", (PyCFunction)Notification_dispatch,
1208      METH_VARARGS | METH_KEYWORDS, dispatch_doc},
1209     {NULL}};
1210
1211 static PyMemberDef Notification_members[] = {
1212     {"severity", T_INT, offsetof(Notification, severity), 0, severity_doc},
1213     {"meta", T_OBJECT_EX, offsetof(Notification, meta), 0, notification_meta_doc},
1214     {NULL}};
1215
1216 static PyGetSetDef Notification_getseters[] = {
1217     {"message", PluginData_getstring, Notification_setstring, message_doc,
1218      (void *)offsetof(Notification, message)},
1219     {NULL}};
1220
1221 PyTypeObject NotificationType = {
1222     CPY_INIT_TYPE "collectd.Notification",    /* tp_name */
1223     sizeof(Notification),                     /* tp_basicsize */
1224     0,                                        /* Will be filled in later */
1225     Notification_dealloc,                     /* tp_dealloc */
1226     0,                                        /* tp_print */
1227     0,                                        /* tp_getattr */
1228     0,                                        /* tp_setattr */
1229     0,                                        /* tp_compare */
1230     Notification_repr,                        /* tp_repr */
1231     0,                                        /* tp_as_number */
1232     0,                                        /* tp_as_sequence */
1233     0,                                        /* tp_as_mapping */
1234     0,                                        /* tp_hash */
1235     0,                                        /* tp_call */
1236     0,                                        /* tp_str */
1237     0,                                        /* tp_getattro */
1238     0,                                        /* tp_setattro */
1239     0,                                        /* tp_as_buffer */
1240     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
1241     Notification_doc,                         /* tp_doc */
1242     Notification_traverse,                    /* tp_traverse */
1243     Notification_clear,                       /* tp_clear */
1244     0,                                        /* tp_richcompare */
1245     0,                                        /* tp_weaklistoffset */
1246     0,                                        /* tp_iter */
1247     0,                                        /* tp_iternext */
1248     Notification_methods,                     /* tp_methods */
1249     Notification_members,                     /* tp_members */
1250     Notification_getseters,                   /* tp_getset */
1251     0,                                        /* tp_base */
1252     0,                                        /* tp_dict */
1253     0,                                        /* tp_descr_get */
1254     0,                                        /* tp_descr_set */
1255     0,                                        /* tp_dictoffset */
1256     Notification_init,                        /* tp_init */
1257     0,                                        /* tp_alloc */
1258     Notification_new                          /* tp_new */
1259 };
1260
1261 static char Signed_doc[] =
1262     "This is a long by another name. Use it in meta data dicts\n"
1263     "to choose the way it is stored in the meta data.";
1264
1265 PyTypeObject SignedType = {
1266     CPY_INIT_TYPE "collectd.Signed",          /* tp_name */
1267     sizeof(Signed),                           /* tp_basicsize */
1268     0,                                        /* Will be filled in later */
1269     0,                                        /* tp_dealloc */
1270     0,                                        /* tp_print */
1271     0,                                        /* tp_getattr */
1272     0,                                        /* tp_setattr */
1273     0,                                        /* tp_compare */
1274     0,                                        /* tp_repr */
1275     0,                                        /* tp_as_number */
1276     0,                                        /* tp_as_sequence */
1277     0,                                        /* tp_as_mapping */
1278     0,                                        /* tp_hash */
1279     0,                                        /* tp_call */
1280     0,                                        /* tp_str */
1281     0,                                        /* tp_getattro */
1282     0,                                        /* tp_setattro */
1283     0,                                        /* tp_as_buffer */
1284     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
1285     Signed_doc                                /* tp_doc */
1286 };
1287
1288 static char Unsigned_doc[] =
1289     "This is a long by another name. Use it in meta data dicts\n"
1290     "to choose the way it is stored in the meta data.";
1291
1292 PyTypeObject UnsignedType = {
1293     CPY_INIT_TYPE "collectd.Unsigned",        /* tp_name */
1294     sizeof(Unsigned),                         /* tp_basicsize */
1295     0,                                        /* Will be filled in later */
1296     0,                                        /* tp_dealloc */
1297     0,                                        /* tp_print */
1298     0,                                        /* tp_getattr */
1299     0,                                        /* tp_setattr */
1300     0,                                        /* tp_compare */
1301     0,                                        /* tp_repr */
1302     0,                                        /* tp_as_number */
1303     0,                                        /* tp_as_sequence */
1304     0,                                        /* tp_as_mapping */
1305     0,                                        /* tp_hash */
1306     0,                                        /* tp_call */
1307     0,                                        /* tp_str */
1308     0,                                        /* tp_getattro */
1309     0,                                        /* tp_setattro */
1310     0,                                        /* tp_as_buffer */
1311     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
1312     Unsigned_doc                              /* tp_doc */
1313 };