Merge branch 'collectd-5.7' into collectd-5.8
[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 static PyObject *cpy_common_repr(PyObject *s) {
54   PyObject *ret, *tmp;
55   static PyObject *l_type = NULL, *l_type_instance = NULL, *l_plugin = NULL,
56                   *l_plugin_instance = NULL;
57   static PyObject *l_host = NULL, *l_time = NULL;
58   PluginData *self = (PluginData *)s;
59
60   if (l_type == NULL)
61     l_type = cpy_string_to_unicode_or_bytes("(type=");
62   if (l_type_instance == NULL)
63     l_type_instance = cpy_string_to_unicode_or_bytes(",type_instance=");
64   if (l_plugin == NULL)
65     l_plugin = cpy_string_to_unicode_or_bytes(",plugin=");
66   if (l_plugin_instance == NULL)
67     l_plugin_instance = cpy_string_to_unicode_or_bytes(",plugin_instance=");
68   if (l_host == NULL)
69     l_host = cpy_string_to_unicode_or_bytes(",host=");
70   if (l_time == NULL)
71     l_time = cpy_string_to_unicode_or_bytes(",time=");
72
73   if (!l_type || !l_type_instance || !l_plugin || !l_plugin_instance ||
74       !l_host || !l_time)
75     return NULL;
76
77   ret = cpy_string_to_unicode_or_bytes(s->ob_type->tp_name);
78
79   CPY_STRCAT(&ret, l_type);
80   tmp = cpy_string_to_unicode_or_bytes(self->type);
81   CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
82   CPY_STRCAT_AND_DEL(&ret, tmp);
83
84   if (self->type_instance[0] != 0) {
85     CPY_STRCAT(&ret, l_type_instance);
86     tmp = cpy_string_to_unicode_or_bytes(self->type_instance);
87     CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
88     CPY_STRCAT_AND_DEL(&ret, tmp);
89   }
90
91   if (self->plugin[0] != 0) {
92     CPY_STRCAT(&ret, l_plugin);
93     tmp = cpy_string_to_unicode_or_bytes(self->plugin);
94     CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
95     CPY_STRCAT_AND_DEL(&ret, tmp);
96   }
97
98   if (self->plugin_instance[0] != 0) {
99     CPY_STRCAT(&ret, l_plugin_instance);
100     tmp = cpy_string_to_unicode_or_bytes(self->plugin_instance);
101     CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
102     CPY_STRCAT_AND_DEL(&ret, tmp);
103   }
104
105   if (self->host[0] != 0) {
106     CPY_STRCAT(&ret, l_host);
107     tmp = cpy_string_to_unicode_or_bytes(self->host);
108     CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
109     CPY_STRCAT_AND_DEL(&ret, tmp);
110   }
111
112   if (self->time != 0) {
113     CPY_STRCAT(&ret, l_time);
114     tmp = PyFloat_FromDouble(self->time);
115     CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
116     CPY_STRCAT_AND_DEL(&ret, tmp);
117   }
118   return ret;
119 }
120
121 static char time_doc[] =
122     "This is the Unix timestamp of the time this value was read.\n"
123     "For dispatching values this can be set to 0 which means \"now\".\n"
124     "This means the time the value is actually dispatched, not the time\n"
125     "it was set to 0.";
126
127 static char host_doc[] =
128     "The hostname of the host this value was read from.\n"
129     "For dispatching this can be set to an empty string which means\n"
130     "the local hostname as defined in collectd.conf.";
131
132 static char type_doc[] =
133     "The type of this value. This type has to be defined\n"
134     "in the types.db file. Attempting to set it to any other value\n"
135     "will raise a TypeError exception.\n"
136     "Assigning a type is mandatory, calling dispatch without doing\n"
137     "so will raise a RuntimeError exception.";
138
139 static char type_instance_doc[] = "";
140
141 static char plugin_doc[] =
142     "The name of the plugin that read the data. Setting this\n"
143     "member to an empty string will insert \"python\" upon dispatching.";
144
145 static char plugin_instance_doc[] = "";
146
147 static char PluginData_doc[] =
148     "This is an internal class that is the base for Values\n"
149     "and Notification. It is pretty useless by itself and is therefore not\n"
150     "exported to the collectd module.";
151
152 static PyObject *PluginData_new(PyTypeObject *type, PyObject *args,
153                                 PyObject *kwds) {
154   PluginData *self;
155
156   self = (PluginData *)type->tp_alloc(type, 0);
157   if (self == NULL)
158     return NULL;
159
160   self->time = 0;
161   self->host[0] = 0;
162   self->plugin[0] = 0;
163   self->plugin_instance[0] = 0;
164   self->type[0] = 0;
165   self->type_instance[0] = 0;
166   return (PyObject *)self;
167 }
168
169 static int PluginData_init(PyObject *s, PyObject *args, PyObject *kwds) {
170   PluginData *self = (PluginData *)s;
171   double time = 0;
172   char *type = NULL, *plugin_instance = NULL, *type_instance = NULL,
173        *plugin = NULL, *host = NULL;
174   static char *kwlist[] = {
175       "type", "plugin_instance", "type_instance", "plugin", "host", "time",
176       NULL};
177
178   if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etetetetetd", kwlist, NULL,
179                                    &type, NULL, &plugin_instance, NULL,
180                                    &type_instance, NULL, &plugin, NULL, &host,
181                                    &time))
182     return -1;
183
184   if (type && plugin_get_ds(type) == NULL) {
185     PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
186     FreeAll();
187     return -1;
188   }
189
190   sstrncpy(self->host, host ? host : "", sizeof(self->host));
191   sstrncpy(self->plugin, plugin ? plugin : "", sizeof(self->plugin));
192   sstrncpy(self->plugin_instance, plugin_instance ? plugin_instance : "",
193            sizeof(self->plugin_instance));
194   sstrncpy(self->type, type ? type : "", sizeof(self->type));
195   sstrncpy(self->type_instance, type_instance ? type_instance : "",
196            sizeof(self->type_instance));
197   self->time = time;
198
199   FreeAll();
200
201   return 0;
202 }
203
204 static PyObject *PluginData_repr(PyObject *s) {
205   PyObject *ret;
206   static PyObject *l_closing = NULL;
207
208   if (l_closing == NULL)
209     l_closing = cpy_string_to_unicode_or_bytes(")");
210
211   if (l_closing == NULL)
212     return NULL;
213
214   ret = cpy_common_repr(s);
215   CPY_STRCAT(&ret, l_closing);
216   return ret;
217 }
218
219 static PyMemberDef PluginData_members[] = {
220     {"time", T_DOUBLE, offsetof(PluginData, time), 0, time_doc}, {NULL}};
221
222 static PyObject *PluginData_getstring(PyObject *self, void *data) {
223   const char *value = ((char *)self) + (intptr_t)data;
224
225   return cpy_string_to_unicode_or_bytes(value);
226 }
227
228 static int PluginData_setstring(PyObject *self, PyObject *value, void *data) {
229   char *old;
230   const char *new;
231
232   if (value == NULL) {
233     PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute");
234     return -1;
235   }
236   Py_INCREF(value);
237   new = cpy_unicode_or_bytes_to_string(&value);
238   if (new == NULL) {
239     Py_DECREF(value);
240     return -1;
241   }
242   old = ((char *)self) + (intptr_t)data;
243   sstrncpy(old, new, DATA_MAX_NAME_LEN);
244   Py_DECREF(value);
245   return 0;
246 }
247
248 static int PluginData_settype(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
263   if (plugin_get_ds(new) == NULL) {
264     PyErr_Format(PyExc_TypeError, "Dataset %s not found", new);
265     Py_DECREF(value);
266     return -1;
267   }
268
269   old = ((char *)self) + (intptr_t)data;
270   sstrncpy(old, new, DATA_MAX_NAME_LEN);
271   Py_DECREF(value);
272   return 0;
273 }
274
275 static PyGetSetDef PluginData_getseters[] = {
276     {"host", PluginData_getstring, PluginData_setstring, host_doc,
277      (void *)offsetof(PluginData, host)},
278     {"plugin", PluginData_getstring, PluginData_setstring, plugin_doc,
279      (void *)offsetof(PluginData, plugin)},
280     {"plugin_instance", PluginData_getstring, PluginData_setstring,
281      plugin_instance_doc, (void *)offsetof(PluginData, plugin_instance)},
282     {"type_instance", PluginData_getstring, PluginData_setstring,
283      type_instance_doc, (void *)offsetof(PluginData, type_instance)},
284     {"type", PluginData_getstring, PluginData_settype, type_doc,
285      (void *)offsetof(PluginData, type)},
286     {NULL}};
287
288 PyTypeObject PluginDataType = {
289     CPY_INIT_TYPE "collectd.PluginData", /* tp_name */
290     sizeof(PluginData),                  /* tp_basicsize */
291     0,                                   /* Will be filled in later */
292     0,                                   /* tp_dealloc */
293     0,                                   /* tp_print */
294     0,                                   /* tp_getattr */
295     0,                                   /* tp_setattr */
296     0,                                   /* tp_compare */
297     PluginData_repr,                     /* tp_repr */
298     0,                                   /* tp_as_number */
299     0,                                   /* tp_as_sequence */
300     0,                                   /* tp_as_mapping */
301     0,                                   /* tp_hash */
302     0,                                   /* tp_call */
303     0,                                   /* tp_str */
304     0,                                   /* tp_getattro */
305     0,                                   /* tp_setattro */
306     0,                                   /* tp_as_buffer */
307     Py_TPFLAGS_DEFAULT |
308         Py_TPFLAGS_BASETYPE /*| Py_TPFLAGS_HAVE_GC*/, /*tp_flags*/
309     PluginData_doc,                                   /* tp_doc */
310     0,                                                /* tp_traverse */
311     0,                                                /* tp_clear */
312     0,                                                /* tp_richcompare */
313     0,                                                /* tp_weaklistoffset */
314     0,                                                /* tp_iter */
315     0,                                                /* tp_iternext */
316     0,                                                /* tp_methods */
317     PluginData_members,                               /* tp_members */
318     PluginData_getseters,                             /* tp_getset */
319     0,                                                /* tp_base */
320     0,                                                /* tp_dict */
321     0,                                                /* tp_descr_get */
322     0,                                                /* tp_descr_set */
323     0,                                                /* tp_dictoffset */
324     PluginData_init,                                  /* tp_init */
325     0,                                                /* tp_alloc */
326     PluginData_new                                    /* tp_new */
327 };
328
329 static char interval_doc[] =
330     "The interval is the timespan in seconds between two submits for\n"
331     "the same data source. This value has to be a positive integer, so you "
332     "can't\n"
333     "submit more than one value per second. If this member is set to a\n"
334     "non-positive value, the default value as specified in the config file "
335     "will\n"
336     "be used (default: 10).\n"
337     "\n"
338     "If you submit values more often than the specified interval, the average\n"
339     "will be used. If you submit less values, your graphs will have gaps.";
340
341 static char values_doc[] =
342     "These are the actual values that get dispatched to collectd.\n"
343     "It has to be a sequence (a tuple or list) of numbers.\n"
344     "The size of the sequence and the type of its content depend on the type\n"
345     "member in the types.db file. For more information on this read the\n"
346     "types.db man page.\n"
347     "\n"
348     "If the sequence does not have the correct size upon dispatch a "
349     "RuntimeError\n"
350     "exception will be raised. If the content of the sequence is not a "
351     "number,\n"
352     "a TypeError exception will be raised.";
353
354 static char meta_doc[] =
355     "These are the meta data for this Value object.\n"
356     "It has to be a dictionary of numbers, strings or bools. All keys must be\n"
357     "strings. int and long objects will be dispatched as signed integers "
358     "unless\n"
359     "they are between 2**63 and 2**64-1, which will result in an unsigned "
360     "integer.\n"
361     "You can force one of these storage classes by using the classes\n"
362     "collectd.Signed and collectd.Unsigned. A meta object received by a write\n"
363     "callback will always contain Signed or Unsigned objects.";
364
365 static char dispatch_doc[] =
366     "dispatch([type][, values][, plugin_instance][, type_instance]"
367     "[, plugin][, host][, time][, interval]) -> None.  Dispatch a value list.\n"
368     "\n"
369     "Dispatch this instance to the collectd process. The object has members\n"
370     "for each of the possible arguments for this method. For a detailed "
371     "explanation\n"
372     "of these parameters see the member of the same same.\n"
373     "\n"
374     "If you do not submit a parameter the value saved in its member will be "
375     "submitted.\n"
376     "If you do provide a parameter it will be used instead, without altering "
377     "the member.";
378
379 static char write_doc[] =
380     "write([destination][, type][, values][, plugin_instance][, type_instance]"
381     "[, plugin][, host][, time][, interval]) -> None.  Dispatch a value list.\n"
382     "\n"
383     "Write this instance to a single plugin or all plugins if 'destination' is "
384     "omitted.\n"
385     "This will bypass the main collectd process and all filtering and "
386     "caching.\n"
387     "Other than that it works similar to 'dispatch'. In most cases 'dispatch' "
388     "should be\n"
389     "used instead of 'write'.\n";
390
391 static char Values_doc[] = "A Values object used for dispatching values to "
392                            "collectd and receiving values from write "
393                            "callbacks.";
394
395 static PyObject *Values_new(PyTypeObject *type, PyObject *args,
396                             PyObject *kwds) {
397   Values *self;
398
399   self = (Values *)PluginData_new(type, args, kwds);
400   if (self == NULL)
401     return NULL;
402
403   self->values = PyList_New(0);
404   self->meta = PyDict_New();
405   self->interval = 0;
406   return (PyObject *)self;
407 }
408
409 static int Values_init(PyObject *s, PyObject *args, PyObject *kwds) {
410   Values *self = (Values *)s;
411   double interval = 0, time = 0;
412   PyObject *values = NULL, *meta = NULL, *tmp;
413   char *type = NULL, *plugin_instance = NULL, *type_instance = NULL,
414        *plugin = NULL, *host = NULL;
415   static char *kwlist[] = {
416       "type", "values", "plugin_instance", "type_instance", "plugin",
417       "host", "time",   "interval",        "meta",          NULL};
418
419   if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etOetetetetddO", kwlist, NULL,
420                                    &type, &values, NULL, &plugin_instance, NULL,
421                                    &type_instance, NULL, &plugin, NULL, &host,
422                                    &time, &interval, &meta))
423     return -1;
424
425   if (type && plugin_get_ds(type) == NULL) {
426     PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
427     FreeAll();
428     return -1;
429   }
430
431   sstrncpy(self->data.host, host ? host : "", sizeof(self->data.host));
432   sstrncpy(self->data.plugin, plugin ? plugin : "", sizeof(self->data.plugin));
433   sstrncpy(self->data.plugin_instance, plugin_instance ? plugin_instance : "",
434            sizeof(self->data.plugin_instance));
435   sstrncpy(self->data.type, type ? type : "", sizeof(self->data.type));
436   sstrncpy(self->data.type_instance, type_instance ? type_instance : "",
437            sizeof(self->data.type_instance));
438   self->data.time = time;
439
440   FreeAll();
441
442   if (values == NULL) {
443     values = PyList_New(0);
444     PyErr_Clear();
445   } else {
446     Py_INCREF(values);
447   }
448
449   if (meta == NULL) {
450     meta = PyDict_New();
451     PyErr_Clear();
452   } else {
453     Py_INCREF(meta);
454   }
455
456   tmp = self->values;
457   self->values = values;
458   Py_XDECREF(tmp);
459
460   tmp = self->meta;
461   self->meta = meta;
462   Py_XDECREF(tmp);
463
464   self->interval = interval;
465   return 0;
466 }
467
468 static int cpy_build_meta_generic(PyObject *meta,
469                                   cpy_build_meta_handler_t *meta_func,
470                                   void *m) {
471   int s;
472   PyObject *l;
473
474   if ((meta == NULL) || (meta == Py_None))
475     return -1;
476
477   l = PyDict_Items(meta); /* New reference. */
478   if (!l) {
479     cpy_log_exception("building meta data");
480     return -1;
481   }
482   s = PyList_Size(l);
483   if (s <= 0) {
484     Py_XDECREF(l);
485     return -1;
486   }
487
488   for (int i = 0; i < s; ++i) {
489     const char *string, *keystring;
490     PyObject *key, *value, *item, *tmp;
491
492     item = PyList_GET_ITEM(l, i);
493     key = PyTuple_GET_ITEM(item, 0);
494     Py_INCREF(key);
495     keystring = cpy_unicode_or_bytes_to_string(&key);
496     if (!keystring) {
497       PyErr_Clear();
498       Py_XDECREF(key);
499       continue;
500     }
501     value = PyTuple_GET_ITEM(item, 1);
502     Py_INCREF(value);
503     if (value == Py_True) {
504       meta_func->add_boolean(m, keystring, 1);
505     } else if (value == Py_False) {
506       meta_func->add_boolean(m, keystring, 0);
507     } else if (PyFloat_Check(value)) {
508       meta_func->add_double(m, keystring, PyFloat_AsDouble(value));
509     } else if (PyObject_TypeCheck(value, &SignedType)) {
510       long long int lli;
511       lli = PyLong_AsLongLong(value);
512       if (!PyErr_Occurred() && (lli == (int64_t)lli))
513         meta_func->add_signed_int(m, keystring, lli);
514     } else if (PyObject_TypeCheck(value, &UnsignedType)) {
515       long long unsigned llu;
516       llu = PyLong_AsUnsignedLongLong(value);
517       if (!PyErr_Occurred() && (llu == (uint64_t)llu))
518         meta_func->add_unsigned_int(m, keystring, llu);
519     } else if (PyNumber_Check(value)) {
520       long long int lli;
521       long long unsigned llu;
522       tmp = PyNumber_Long(value);
523       lli = PyLong_AsLongLong(tmp);
524       if (!PyErr_Occurred() && (lli == (int64_t)lli)) {
525         meta_func->add_signed_int(m, keystring, lli);
526       } else {
527         PyErr_Clear();
528         llu = PyLong_AsUnsignedLongLong(tmp);
529         if (!PyErr_Occurred() && (llu == (uint64_t)llu))
530           meta_func->add_unsigned_int(m, keystring, llu);
531       }
532       Py_XDECREF(tmp);
533     } else {
534       string = cpy_unicode_or_bytes_to_string(&value);
535       if (string) {
536         meta_func->add_string(m, keystring, string);
537       } else {
538         PyErr_Clear();
539         tmp = PyObject_Str(value);
540         string = cpy_unicode_or_bytes_to_string(&tmp);
541         if (string)
542           meta_func->add_string(m, keystring, string);
543         Py_XDECREF(tmp);
544       }
545     }
546     if (PyErr_Occurred())
547       cpy_log_exception("building meta data");
548     Py_XDECREF(value);
549     Py_DECREF(key);
550   }
551   Py_XDECREF(l);
552   return 0;
553 }
554
555 #define CPY_BUILD_META_FUNC(meta_type, func, val_type)                         \
556   static int cpy_##func(void *meta, const char *key, val_type val) {           \
557     return func((meta_type *)meta, key, val);                                  \
558   }
559
560 #define CPY_BUILD_META_HANDLER(func_prefix, meta_type)                         \
561   CPY_BUILD_META_FUNC(meta_type, func_prefix##_add_string, const char *)       \
562   CPY_BUILD_META_FUNC(meta_type, func_prefix##_add_signed_int, int64_t)        \
563   CPY_BUILD_META_FUNC(meta_type, func_prefix##_add_unsigned_int, uint64_t)     \
564   CPY_BUILD_META_FUNC(meta_type, func_prefix##_add_double, double)             \
565   CPY_BUILD_META_FUNC(meta_type, func_prefix##_add_boolean, _Bool)             \
566                                                                                \
567   static cpy_build_meta_handler_t cpy_##func_prefix = {                        \
568       .add_string = cpy_##func_prefix##_add_string,                            \
569       .add_signed_int = cpy_##func_prefix##_add_signed_int,                    \
570       .add_unsigned_int = cpy_##func_prefix##_add_unsigned_int,                \
571       .add_double = cpy_##func_prefix##_add_double,                            \
572       .add_boolean = cpy_##func_prefix##_add_boolean}
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_meta(PyObject *meta) {
578   meta_data_t *m = meta_data_create();
579   if (cpy_build_meta_generic(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_generic(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_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_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[] = {
992       "type", "message", "plugin_instance", "type_instance", "plugin",
993       "host", "time",    "severity",        "meta",          NULL};
994
995   if (!PyArg_ParseTupleAndKeywords(
996           args, kwds, "|etetetetetetdiO", kwlist, NULL, &type, NULL, &message,
997           NULL, &plugin_instance, NULL, &type_instance, NULL, &plugin, NULL,
998           &host, &time, &severity, &meta))
999     return -1;
1000
1001   if (type && plugin_get_ds(type) == NULL) {
1002     PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
1003     FreeAll();
1004     PyMem_Free(message);
1005     return -1;
1006   }
1007
1008   sstrncpy(self->data.host, host ? host : "", sizeof(self->data.host));
1009   sstrncpy(self->data.plugin, plugin ? plugin : "", sizeof(self->data.plugin));
1010   sstrncpy(self->data.plugin_instance, plugin_instance ? plugin_instance : "",
1011            sizeof(self->data.plugin_instance));
1012   sstrncpy(self->data.type, type ? type : "", sizeof(self->data.type));
1013   sstrncpy(self->data.type_instance, type_instance ? type_instance : "",
1014            sizeof(self->data.type_instance));
1015   sstrncpy(self->message, message ? message : "", sizeof(self->message));
1016   self->data.time = time;
1017   self->severity = severity;
1018
1019   FreeAll();
1020   PyMem_Free(message);
1021
1022   if (meta == NULL) {
1023     meta = PyDict_New();
1024     PyErr_Clear();
1025   } else {
1026     Py_INCREF(meta);
1027   }
1028
1029   PyObject *tmp = self->meta;
1030   self->meta = meta;
1031   Py_XDECREF(tmp);
1032
1033   return 0;
1034 }
1035
1036 static PyObject *Notification_dispatch(Notification *self, PyObject *args,
1037                                        PyObject *kwds) {
1038   int ret;
1039   const data_set_t *ds;
1040   notification_t notification;
1041   double t = self->data.time;
1042   PyObject *meta = self->meta;
1043   int severity = self->severity;
1044   char *host = NULL, *plugin = NULL, *plugin_instance = NULL, *type = NULL,
1045        *type_instance = NULL;
1046   char *message = NULL;
1047
1048   static char *kwlist[] = {
1049       "type", "message", "plugin_instance", "type_instance", "plugin",
1050       "host", "time",    "severity",        "meta",          NULL};
1051   if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etetetetetetdiO", kwlist, NULL,
1052                                    &type, NULL, &message, NULL,
1053                                    &plugin_instance, NULL, &type_instance, NULL,
1054                                    &plugin, NULL, &host, &t, &severity, &meta))
1055     return NULL;
1056
1057   notification.time = DOUBLE_TO_CDTIME_T(t);
1058   notification.severity = severity;
1059   sstrncpy(notification.message, message ? message : self->message,
1060            sizeof(notification.message));
1061   sstrncpy(notification.host, host ? host : self->data.host,
1062            sizeof(notification.host));
1063   sstrncpy(notification.plugin, plugin ? plugin : self->data.plugin,
1064            sizeof(notification.plugin));
1065   sstrncpy(notification.plugin_instance,
1066            plugin_instance ? plugin_instance : self->data.plugin_instance,
1067            sizeof(notification.plugin_instance));
1068   sstrncpy(notification.type, type ? type : self->data.type,
1069            sizeof(notification.type));
1070   sstrncpy(notification.type_instance,
1071            type_instance ? type_instance : self->data.type_instance,
1072            sizeof(notification.type_instance));
1073   notification.meta = NULL;
1074   FreeAll();
1075   PyMem_Free(message);
1076
1077   if (notification.type[0] == 0) {
1078     PyErr_SetString(PyExc_RuntimeError, "type not set");
1079     return NULL;
1080   }
1081   ds = plugin_get_ds(notification.type);
1082   if (ds == NULL) {
1083     PyErr_Format(PyExc_TypeError, "Dataset %s not found", notification.type);
1084     return NULL;
1085   }
1086   if (meta != NULL && meta != Py_None && !PyDict_Check(meta)) {
1087     PyErr_Format(PyExc_TypeError, "meta must be a dict");
1088     return NULL;
1089   }
1090   cpy_build_notification_meta(&notification, meta);
1091
1092   if (notification.time == 0)
1093     notification.time = cdtime();
1094   if (notification.host[0] == 0)
1095     sstrncpy(notification.host, hostname_g, sizeof(notification.host));
1096   if (notification.plugin[0] == 0)
1097     sstrncpy(notification.plugin, "python", sizeof(notification.plugin));
1098   Py_BEGIN_ALLOW_THREADS;
1099   ret = plugin_dispatch_notification(&notification);
1100   if (notification.meta)
1101     plugin_notification_meta_free(notification.meta);
1102   Py_END_ALLOW_THREADS;
1103   if (ret != 0) {
1104     PyErr_SetString(PyExc_RuntimeError,
1105                     "error dispatching notification, read the logs");
1106     return NULL;
1107   }
1108   Py_RETURN_NONE;
1109 }
1110
1111 static PyObject *Notification_new(PyTypeObject *type, PyObject *args,
1112                                   PyObject *kwds) {
1113   Notification *self;
1114
1115   self = (Notification *)PluginData_new(type, args, kwds);
1116   if (self == NULL)
1117     return NULL;
1118
1119   self->meta = PyDict_New();
1120   self->message[0] = 0;
1121   self->severity = 0;
1122   return (PyObject *)self;
1123 }
1124
1125 static int Notification_setstring(PyObject *self, PyObject *value, void *data) {
1126   char *old;
1127   const char *new;
1128
1129   if (value == NULL) {
1130     PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute");
1131     return -1;
1132   }
1133   Py_INCREF(value);
1134   new = cpy_unicode_or_bytes_to_string(&value);
1135   if (new == NULL) {
1136     Py_DECREF(value);
1137     return -1;
1138   }
1139   old = ((char *)self) + (intptr_t)data;
1140   sstrncpy(old, new, NOTIF_MAX_MSG_LEN);
1141   Py_DECREF(value);
1142   return 0;
1143 }
1144
1145 static PyObject *Notification_repr(PyObject *s) {
1146   PyObject *ret, *tmp;
1147   static PyObject *l_severity = NULL, *l_message = NULL, *l_meta = NULL,
1148                   *l_closing = NULL;
1149   Notification *self = (Notification *)s;
1150
1151   if (l_severity == NULL)
1152     l_severity = cpy_string_to_unicode_or_bytes(",severity=");
1153   if (l_message == NULL)
1154     l_message = cpy_string_to_unicode_or_bytes(",message=");
1155   if (l_meta == NULL)
1156     l_meta = cpy_string_to_unicode_or_bytes(",meta=");
1157   if (l_closing == NULL)
1158     l_closing = cpy_string_to_unicode_or_bytes(")");
1159
1160   if (l_severity == NULL || l_message == NULL || l_meta == NULL ||
1161       l_closing == NULL)
1162     return NULL;
1163
1164   ret = cpy_common_repr(s);
1165   if (self->severity != 0) {
1166     CPY_STRCAT(&ret, l_severity);
1167     tmp = PyInt_FromLong(self->severity);
1168     CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
1169     CPY_STRCAT_AND_DEL(&ret, tmp);
1170   }
1171   if (self->message[0] != 0) {
1172     CPY_STRCAT(&ret, l_message);
1173     tmp = cpy_string_to_unicode_or_bytes(self->message);
1174     CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
1175     CPY_STRCAT_AND_DEL(&ret, tmp);
1176   }
1177   if (self->meta &&
1178       (!PyDict_Check(self->meta) || PyDict_Size(self->meta) > 0)) {
1179     CPY_STRCAT(&ret, l_meta);
1180     tmp = PyObject_Repr(self->meta);
1181     CPY_STRCAT_AND_DEL(&ret, tmp);
1182   }
1183   CPY_STRCAT(&ret, l_closing);
1184   return ret;
1185 }
1186
1187 static int Notification_traverse(PyObject *self, visitproc visit, void *arg) {
1188   Notification *n = (Notification *)self;
1189   Py_VISIT(n->meta);
1190   return 0;
1191 }
1192
1193 static int Notification_clear(PyObject *self) {
1194   Notification *n = (Notification *)self;
1195   Py_CLEAR(n->meta);
1196   return 0;
1197 }
1198
1199 static void Notification_dealloc(PyObject *self) {
1200   Notification_clear(self);
1201   self->ob_type->tp_free(self);
1202 }
1203
1204 static PyMethodDef Notification_methods[] = {
1205     {"dispatch", (PyCFunction)Notification_dispatch,
1206      METH_VARARGS | METH_KEYWORDS, dispatch_doc},
1207     {NULL}};
1208
1209 static PyMemberDef Notification_members[] = {
1210     {"severity", T_INT, offsetof(Notification, severity), 0, severity_doc},
1211     {"meta", T_OBJECT_EX, offsetof(Notification, meta), 0,
1212      notification_meta_doc},
1213     {NULL}};
1214
1215 static PyGetSetDef Notification_getseters[] = {
1216     {"message", PluginData_getstring, Notification_setstring, message_doc,
1217      (void *)offsetof(Notification, message)},
1218     {NULL}};
1219
1220 PyTypeObject NotificationType = {
1221     CPY_INIT_TYPE "collectd.Notification", /* tp_name */
1222     sizeof(Notification),                  /* tp_basicsize */
1223     0,                                     /* Will be filled in later */
1224     Notification_dealloc,                  /* tp_dealloc */
1225     0,                                     /* tp_print */
1226     0,                                     /* tp_getattr */
1227     0,                                     /* tp_setattr */
1228     0,                                     /* tp_compare */
1229     Notification_repr,                     /* tp_repr */
1230     0,                                     /* tp_as_number */
1231     0,                                     /* tp_as_sequence */
1232     0,                                     /* tp_as_mapping */
1233     0,                                     /* tp_hash */
1234     0,                                     /* tp_call */
1235     0,                                     /* tp_str */
1236     0,                                     /* tp_getattro */
1237     0,                                     /* tp_setattro */
1238     0,                                     /* tp_as_buffer */
1239     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
1240     Notification_doc,                                              /* tp_doc */
1241     Notification_traverse,  /* tp_traverse */
1242     Notification_clear,     /* tp_clear */
1243     0,                      /* tp_richcompare */
1244     0,                      /* tp_weaklistoffset */
1245     0,                      /* tp_iter */
1246     0,                      /* tp_iternext */
1247     Notification_methods,   /* tp_methods */
1248     Notification_members,   /* tp_members */
1249     Notification_getseters, /* tp_getset */
1250     0,                      /* tp_base */
1251     0,                      /* tp_dict */
1252     0,                      /* tp_descr_get */
1253     0,                      /* tp_descr_set */
1254     0,                      /* tp_dictoffset */
1255     Notification_init,      /* tp_init */
1256     0,                      /* tp_alloc */
1257     Notification_new        /* tp_new */
1258 };
1259
1260 static char Signed_doc[] =
1261     "This is a long by another name. Use it in meta data dicts\n"
1262     "to choose the way it is stored in the meta data.";
1263
1264 PyTypeObject SignedType = {
1265     CPY_INIT_TYPE "collectd.Signed",          /* tp_name */
1266     sizeof(Signed),                           /* tp_basicsize */
1267     0,                                        /* Will be filled in later */
1268     0,                                        /* tp_dealloc */
1269     0,                                        /* tp_print */
1270     0,                                        /* tp_getattr */
1271     0,                                        /* tp_setattr */
1272     0,                                        /* tp_compare */
1273     0,                                        /* tp_repr */
1274     0,                                        /* tp_as_number */
1275     0,                                        /* tp_as_sequence */
1276     0,                                        /* tp_as_mapping */
1277     0,                                        /* tp_hash */
1278     0,                                        /* tp_call */
1279     0,                                        /* tp_str */
1280     0,                                        /* tp_getattro */
1281     0,                                        /* tp_setattro */
1282     0,                                        /* tp_as_buffer */
1283     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
1284     Signed_doc                                /* tp_doc */
1285 };
1286
1287 static char Unsigned_doc[] =
1288     "This is a long by another name. Use it in meta data dicts\n"
1289     "to choose the way it is stored in the meta data.";
1290
1291 PyTypeObject UnsignedType = {
1292     CPY_INIT_TYPE "collectd.Unsigned",        /* tp_name */
1293     sizeof(Unsigned),                         /* tp_basicsize */
1294     0,                                        /* Will be filled in later */
1295     0,                                        /* tp_dealloc */
1296     0,                                        /* tp_print */
1297     0,                                        /* tp_getattr */
1298     0,                                        /* tp_setattr */
1299     0,                                        /* tp_compare */
1300     0,                                        /* tp_repr */
1301     0,                                        /* tp_as_number */
1302     0,                                        /* tp_as_sequence */
1303     0,                                        /* tp_as_mapping */
1304     0,                                        /* tp_hash */
1305     0,                                        /* tp_call */
1306     0,                                        /* tp_str */
1307     0,                                        /* tp_getattro */
1308     0,                                        /* tp_setattro */
1309     0,                                        /* tp_as_buffer */
1310     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
1311     Unsigned_doc                              /* tp_doc */
1312 };