python: Extend Notification class
[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   cpy_build_meta(meta, &cpy_meta_data, (void *)m);
580   return m;
581 }
582
583 static void cpy_build_notification_meta(notification_t *n, PyObject *meta) {
584   cpy_build_meta(meta, &cpy_plugin_notification_meta, (void *)n);
585 }
586
587 static PyObject *Values_dispatch(Values *self, PyObject *args, PyObject *kwds) {
588   int ret;
589   const data_set_t *ds;
590   size_t size;
591   value_t *value;
592   value_list_t value_list = VALUE_LIST_INIT;
593   PyObject *values = self->values, *meta = self->meta;
594   double time = self->data.time, interval = self->interval;
595   char *host = NULL, *plugin = NULL, *plugin_instance = NULL, *type = NULL,
596        *type_instance = NULL;
597
598   static char *kwlist[] = {
599       "type", "values", "plugin_instance", "type_instance", "plugin",
600       "host", "time",   "interval",        "meta",          NULL};
601   if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etOetetetetddO", kwlist, NULL,
602                                    &type, &values, NULL, &plugin_instance, NULL,
603                                    &type_instance, NULL, &plugin, NULL, &host,
604                                    &time, &interval, &meta))
605     return NULL;
606
607   sstrncpy(value_list.host, host ? host : self->data.host,
608            sizeof(value_list.host));
609   sstrncpy(value_list.plugin, plugin ? plugin : self->data.plugin,
610            sizeof(value_list.plugin));
611   sstrncpy(value_list.plugin_instance,
612            plugin_instance ? plugin_instance : self->data.plugin_instance,
613            sizeof(value_list.plugin_instance));
614   sstrncpy(value_list.type, type ? type : self->data.type,
615            sizeof(value_list.type));
616   sstrncpy(value_list.type_instance,
617            type_instance ? type_instance : self->data.type_instance,
618            sizeof(value_list.type_instance));
619   FreeAll();
620   if (value_list.type[0] == 0) {
621     PyErr_SetString(PyExc_RuntimeError, "type not set");
622     FreeAll();
623     return NULL;
624   }
625   ds = plugin_get_ds(value_list.type);
626   if (ds == NULL) {
627     PyErr_Format(PyExc_TypeError, "Dataset %s not found", value_list.type);
628     return NULL;
629   }
630   if (values == NULL ||
631       (PyTuple_Check(values) == 0 && PyList_Check(values) == 0)) {
632     PyErr_Format(PyExc_TypeError, "values must be list or tuple");
633     return NULL;
634   }
635   if (meta != NULL && meta != Py_None && !PyDict_Check(meta)) {
636     PyErr_Format(PyExc_TypeError, "meta must be a dict");
637     return NULL;
638   }
639   size = (size_t)PySequence_Length(values);
640   if (size != ds->ds_num) {
641     PyErr_Format(PyExc_RuntimeError, "type %s needs %zu values, got %zu",
642                  value_list.type, ds->ds_num, size);
643     return NULL;
644   }
645   value = calloc(size, sizeof(*value));
646   for (size_t i = 0; i < size; ++i) {
647     PyObject *item, *num;
648     item = PySequence_Fast_GET_ITEM(values, (int)i); /* Borrowed reference. */
649     switch (ds->ds[i].type) {
650     case DS_TYPE_COUNTER:
651       num = PyNumber_Long(item); /* New reference. */
652       if (num != NULL) {
653         value[i].counter = PyLong_AsUnsignedLongLong(num);
654         Py_XDECREF(num);
655       }
656       break;
657     case DS_TYPE_GAUGE:
658       num = PyNumber_Float(item); /* New reference. */
659       if (num != NULL) {
660         value[i].gauge = PyFloat_AsDouble(num);
661         Py_XDECREF(num);
662       }
663       break;
664     case DS_TYPE_DERIVE:
665       /* This might overflow without raising an exception.
666        * Not much we can do about it */
667       num = PyNumber_Long(item); /* New reference. */
668       if (num != NULL) {
669         value[i].derive = PyLong_AsLongLong(num);
670         Py_XDECREF(num);
671       }
672       break;
673     case DS_TYPE_ABSOLUTE:
674       /* This might overflow without raising an exception.
675        * Not much we can do about it */
676       num = PyNumber_Long(item); /* New reference. */
677       if (num != NULL) {
678         value[i].absolute = PyLong_AsUnsignedLongLong(num);
679         Py_XDECREF(num);
680       }
681       break;
682     default:
683       free(value);
684       PyErr_Format(PyExc_RuntimeError, "unknown data type %d for %s",
685                    ds->ds[i].type, value_list.type);
686       return NULL;
687     }
688     if (PyErr_Occurred() != NULL) {
689       free(value);
690       return NULL;
691     }
692   }
693   value_list.values = value;
694   value_list.meta = cpy_build_value_meta(meta);
695   value_list.values_len = size;
696   value_list.time = DOUBLE_TO_CDTIME_T(time);
697   value_list.interval = DOUBLE_TO_CDTIME_T(interval);
698   if (value_list.host[0] == 0)
699     sstrncpy(value_list.host, hostname_g, sizeof(value_list.host));
700   if (value_list.plugin[0] == 0)
701     sstrncpy(value_list.plugin, "python", sizeof(value_list.plugin));
702   Py_BEGIN_ALLOW_THREADS;
703   ret = plugin_dispatch_values(&value_list);
704   Py_END_ALLOW_THREADS;
705   meta_data_destroy(value_list.meta);
706   free(value);
707   if (ret != 0) {
708     PyErr_SetString(PyExc_RuntimeError,
709                     "error dispatching values, read the logs");
710     return NULL;
711   }
712   Py_RETURN_NONE;
713 }
714
715 static PyObject *Values_write(Values *self, PyObject *args, PyObject *kwds) {
716   int ret;
717   const data_set_t *ds;
718   size_t size;
719   value_t *value;
720   value_list_t value_list = VALUE_LIST_INIT;
721   PyObject *values = self->values, *meta = self->meta;
722   double time = self->data.time, interval = self->interval;
723   char *host = NULL, *plugin = NULL, *plugin_instance = NULL, *type = NULL,
724        *type_instance = NULL, *dest = NULL;
725
726   static char *kwlist[] = {
727       "destination",   "type",   "values", "plugin_instance",
728       "type_instance", "plugin", "host",   "time",
729       "interval",      "meta",   NULL};
730   if (!PyArg_ParseTupleAndKeywords(
731           args, kwds, "et|etOetetetetdiO", kwlist, NULL, &dest, NULL, &type,
732           &values, NULL, &plugin_instance, NULL, &type_instance, NULL, &plugin,
733           NULL, &host, &time, &interval, &meta))
734     return NULL;
735
736   sstrncpy(value_list.host, host ? host : self->data.host,
737            sizeof(value_list.host));
738   sstrncpy(value_list.plugin, plugin ? plugin : self->data.plugin,
739            sizeof(value_list.plugin));
740   sstrncpy(value_list.plugin_instance,
741            plugin_instance ? plugin_instance : self->data.plugin_instance,
742            sizeof(value_list.plugin_instance));
743   sstrncpy(value_list.type, type ? type : self->data.type,
744            sizeof(value_list.type));
745   sstrncpy(value_list.type_instance,
746            type_instance ? type_instance : self->data.type_instance,
747            sizeof(value_list.type_instance));
748   FreeAll();
749   if (value_list.type[0] == 0) {
750     PyErr_SetString(PyExc_RuntimeError, "type not set");
751     return NULL;
752   }
753   ds = plugin_get_ds(value_list.type);
754   if (ds == NULL) {
755     PyErr_Format(PyExc_TypeError, "Dataset %s not found", value_list.type);
756     return NULL;
757   }
758   if (values == NULL ||
759       (PyTuple_Check(values) == 0 && PyList_Check(values) == 0)) {
760     PyErr_Format(PyExc_TypeError, "values must be list or tuple");
761     return NULL;
762   }
763   size = (size_t)PySequence_Length(values);
764   if (size != ds->ds_num) {
765     PyErr_Format(PyExc_RuntimeError, "type %s needs %zu values, got %zu",
766                  value_list.type, ds->ds_num, size);
767     return NULL;
768   }
769   value = calloc(size, sizeof(*value));
770   for (size_t i = 0; i < size; ++i) {
771     PyObject *item, *num;
772     item = PySequence_Fast_GET_ITEM(values, i); /* Borrowed reference. */
773     switch (ds->ds[i].type) {
774     case DS_TYPE_COUNTER:
775       num = PyNumber_Long(item); /* New reference. */
776       if (num != NULL) {
777         value[i].counter = PyLong_AsUnsignedLongLong(num);
778         Py_XDECREF(num);
779       }
780       break;
781     case DS_TYPE_GAUGE:
782       num = PyNumber_Float(item); /* New reference. */
783       if (num != NULL) {
784         value[i].gauge = PyFloat_AsDouble(num);
785         Py_XDECREF(num);
786       }
787       break;
788     case DS_TYPE_DERIVE:
789       /* This might overflow without raising an exception.
790        * Not much we can do about it */
791       num = PyNumber_Long(item); /* New reference. */
792       if (num != NULL) {
793         value[i].derive = PyLong_AsLongLong(num);
794         Py_XDECREF(num);
795       }
796       break;
797     case DS_TYPE_ABSOLUTE:
798       /* This might overflow without raising an exception.
799        * Not much we can do about it */
800       num = PyNumber_Long(item); /* New reference. */
801       if (num != NULL) {
802         value[i].absolute = PyLong_AsUnsignedLongLong(num);
803         Py_XDECREF(num);
804       }
805       break;
806     default:
807       free(value);
808       PyErr_Format(PyExc_RuntimeError, "unknown data type %d for %s",
809                    ds->ds[i].type, value_list.type);
810       return NULL;
811     }
812     if (PyErr_Occurred() != NULL) {
813       free(value);
814       return NULL;
815     }
816   }
817   value_list.values = value;
818   value_list.values_len = size;
819   value_list.time = DOUBLE_TO_CDTIME_T(time);
820   value_list.interval = DOUBLE_TO_CDTIME_T(interval);
821   value_list.meta = cpy_build_value_meta(meta);
822   if (value_list.host[0] == 0)
823     sstrncpy(value_list.host, hostname_g, sizeof(value_list.host));
824   if (value_list.plugin[0] == 0)
825     sstrncpy(value_list.plugin, "python", sizeof(value_list.plugin));
826   Py_BEGIN_ALLOW_THREADS;
827   ret = plugin_write(dest, NULL, &value_list);
828   Py_END_ALLOW_THREADS;
829   meta_data_destroy(value_list.meta);
830   free(value);
831   if (ret != 0) {
832     PyErr_SetString(PyExc_RuntimeError,
833                     "error dispatching values, read the logs");
834     return NULL;
835   }
836   Py_RETURN_NONE;
837 }
838
839 static PyObject *Values_repr(PyObject *s) {
840   PyObject *ret, *tmp;
841   static PyObject *l_interval = NULL, *l_values = NULL, *l_meta = NULL,
842                   *l_closing = NULL;
843   Values *self = (Values *)s;
844
845   if (l_interval == NULL)
846     l_interval = cpy_string_to_unicode_or_bytes(",interval=");
847   if (l_values == NULL)
848     l_values = cpy_string_to_unicode_or_bytes(",values=");
849   if (l_meta == NULL)
850     l_meta = cpy_string_to_unicode_or_bytes(",meta=");
851   if (l_closing == NULL)
852     l_closing = cpy_string_to_unicode_or_bytes(")");
853
854   if (l_interval == NULL || l_values == NULL || l_meta == NULL ||
855       l_closing == NULL)
856     return NULL;
857
858   ret = cpy_common_repr(s);
859   if (self->interval != 0) {
860     CPY_STRCAT(&ret, l_interval);
861     tmp = PyFloat_FromDouble(self->interval);
862     CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
863     CPY_STRCAT_AND_DEL(&ret, tmp);
864   }
865   if (self->values &&
866       (!PyList_Check(self->values) || PySequence_Length(self->values) > 0)) {
867     CPY_STRCAT(&ret, l_values);
868     tmp = PyObject_Repr(self->values);
869     CPY_STRCAT_AND_DEL(&ret, tmp);
870   }
871   if (self->meta &&
872       (!PyDict_Check(self->meta) || PyDict_Size(self->meta) > 0)) {
873     CPY_STRCAT(&ret, l_meta);
874     tmp = PyObject_Repr(self->meta);
875     CPY_STRCAT_AND_DEL(&ret, tmp);
876   }
877   CPY_STRCAT(&ret, l_closing);
878   return ret;
879 }
880
881 static int Values_traverse(PyObject *self, visitproc visit, void *arg) {
882   Values *v = (Values *)self;
883   Py_VISIT(v->values);
884   Py_VISIT(v->meta);
885   return 0;
886 }
887
888 static int Values_clear(PyObject *self) {
889   Values *v = (Values *)self;
890   Py_CLEAR(v->values);
891   Py_CLEAR(v->meta);
892   return 0;
893 }
894
895 static void Values_dealloc(PyObject *self) {
896   Values_clear(self);
897   self->ob_type->tp_free(self);
898 }
899
900 static PyMemberDef Values_members[] = {
901     {"interval", T_DOUBLE, offsetof(Values, interval), 0, interval_doc},
902     {"values", T_OBJECT_EX, offsetof(Values, values), 0, values_doc},
903     {"meta", T_OBJECT_EX, offsetof(Values, meta), 0, meta_doc},
904     {NULL}};
905
906 static PyMethodDef Values_methods[] = {
907     {"dispatch", (PyCFunction)Values_dispatch, METH_VARARGS | METH_KEYWORDS,
908      dispatch_doc},
909     {"write", (PyCFunction)Values_write, METH_VARARGS | METH_KEYWORDS,
910      write_doc},
911     {NULL}};
912
913 PyTypeObject ValuesType = {
914     CPY_INIT_TYPE "collectd.Values", /* tp_name */
915     sizeof(Values),                  /* tp_basicsize */
916     0,                               /* Will be filled in later */
917     Values_dealloc,                  /* tp_dealloc */
918     0,                               /* tp_print */
919     0,                               /* tp_getattr */
920     0,                               /* tp_setattr */
921     0,                               /* tp_compare */
922     Values_repr,                     /* tp_repr */
923     0,                               /* tp_as_number */
924     0,                               /* tp_as_sequence */
925     0,                               /* tp_as_mapping */
926     0,                               /* tp_hash */
927     0,                               /* tp_call */
928     0,                               /* tp_str */
929     0,                               /* tp_getattro */
930     0,                               /* tp_setattro */
931     0,                               /* tp_as_buffer */
932     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
933     Values_doc,                                                    /* tp_doc */
934     Values_traverse, /* tp_traverse */
935     Values_clear,    /* tp_clear */
936     0,               /* tp_richcompare */
937     0,               /* tp_weaklistoffset */
938     0,               /* tp_iter */
939     0,               /* tp_iternext */
940     Values_methods,  /* tp_methods */
941     Values_members,  /* tp_members */
942     0,               /* tp_getset */
943     0,               /* tp_base */
944     0,               /* tp_dict */
945     0,               /* tp_descr_get */
946     0,               /* tp_descr_set */
947     0,               /* tp_dictoffset */
948     Values_init,     /* tp_init */
949     0,               /* tp_alloc */
950     Values_new       /* tp_new */
951 };
952
953 static char notification_meta_doc[] =
954     "These are the meta data for the Notification object.\n"
955     "It has to be a dictionary of numbers, strings or bools. All keys must be\n"
956     "strings. int and long objects will be dispatched as signed integers "
957     "unless\n"
958     "they are between 2**63 and 2**64-1, which will result in an unsigned "
959     "integer.\n"
960     "One of these storage classes can be forced by using the classes\n"
961     "collectd.Signed and collectd.Unsigned. A meta object received by a\n"
962     "notification callback will always contain Signed or Unsigned objects.";
963
964 static char severity_doc[] =
965     "The severity of this notification. Assign or compare to\n"
966     "NOTIF_FAILURE, NOTIF_WARNING or NOTIF_OKAY.";
967
968 static char message_doc[] = "Some kind of description what's going on and why "
969                             "this Notification was generated.";
970
971 static char Notification_doc[] =
972     "The Notification class is a wrapper around the collectd notification.\n"
973     "It can be used to notify other plugins about bad stuff happening. It "
974     "works\n"
975     "similar to Values but has a severity and a message instead of interval\n"
976     "and time.\n"
977     "Notifications can be dispatched at any time and can be received with "
978     "register_notification.";
979
980 static int Notification_init(PyObject *s, PyObject *args, PyObject *kwds) {
981   Notification *self = (Notification *)s;
982   int severity = 0;
983   double time = 0;
984   char *message = NULL;
985   PyObject *meta = NULL;
986   char *type = NULL, *plugin_instance = NULL, *type_instance = NULL,
987        *plugin = NULL, *host = NULL;
988   static char *kwlist[] = {"type",          "message",  "plugin_instance",
989                            "type_instance", "plugin",   "host",
990                            "time",          "severity", "meta",
991                            NULL};
992
993   if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etetetetetetdiO", kwlist, NULL,
994                                    &type, NULL, &message, NULL,
995                                    &plugin_instance, NULL, &type_instance, NULL,
996                                    &plugin, NULL, &host, &time, &severity, &meta))
997     return -1;
998
999   if (type && plugin_get_ds(type) == NULL) {
1000     PyErr_Format(PyExc_TypeError, "Dataset %s not found", type);
1001     FreeAll();
1002     PyMem_Free(message);
1003     return -1;
1004   }
1005
1006   sstrncpy(self->data.host, host ? host : "", sizeof(self->data.host));
1007   sstrncpy(self->data.plugin, plugin ? plugin : "", sizeof(self->data.plugin));
1008   sstrncpy(self->data.plugin_instance, plugin_instance ? plugin_instance : "",
1009            sizeof(self->data.plugin_instance));
1010   sstrncpy(self->data.type, type ? type : "", sizeof(self->data.type));
1011   sstrncpy(self->data.type_instance, type_instance ? type_instance : "",
1012            sizeof(self->data.type_instance));
1013   sstrncpy(self->message, message ? message : "", sizeof(self->message));
1014   self->data.time = time;
1015   self->severity = severity;
1016
1017   FreeAll();
1018   PyMem_Free(message);
1019
1020   if (meta == NULL) {
1021     meta = PyDict_New();
1022     PyErr_Clear();
1023   } else {
1024     Py_INCREF(meta);
1025   }
1026
1027   PyObject *tmp = self->meta;
1028   self->meta = meta;
1029   Py_XDECREF(tmp);
1030
1031   return 0;
1032 }
1033
1034 static PyObject *Notification_dispatch(Notification *self, PyObject *args,
1035                                        PyObject *kwds) {
1036   int ret;
1037   const data_set_t *ds;
1038   notification_t notification;
1039   double t = self->data.time;
1040   PyObject *meta = self->meta;
1041   int severity = self->severity;
1042   char *host = NULL, *plugin = NULL, *plugin_instance = NULL, *type = NULL,
1043        *type_instance = NULL;
1044   char *message = NULL;
1045
1046   static char *kwlist[] = {"type",          "message",  "plugin_instance",
1047                            "type_instance", "plugin",   "host",
1048                            "time",          "severity", "meta",
1049                            NULL};
1050   if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etetetetetetdiO", kwlist, NULL,
1051                                    &type, NULL, &message, NULL,
1052                                    &plugin_instance, NULL, &type_instance, NULL,
1053                                    &plugin, NULL, &host, &t, &severity, &meta))
1054     return NULL;
1055
1056   notification.time = DOUBLE_TO_CDTIME_T(t);
1057   notification.severity = severity;
1058   sstrncpy(notification.message, message ? message : self->message,
1059            sizeof(notification.message));
1060   sstrncpy(notification.host, host ? host : self->data.host,
1061            sizeof(notification.host));
1062   sstrncpy(notification.plugin, plugin ? plugin : self->data.plugin,
1063            sizeof(notification.plugin));
1064   sstrncpy(notification.plugin_instance,
1065            plugin_instance ? plugin_instance : self->data.plugin_instance,
1066            sizeof(notification.plugin_instance));
1067   sstrncpy(notification.type, type ? type : self->data.type,
1068            sizeof(notification.type));
1069   sstrncpy(notification.type_instance,
1070            type_instance ? type_instance : self->data.type_instance,
1071            sizeof(notification.type_instance));
1072   notification.meta = NULL;
1073   FreeAll();
1074   PyMem_Free(message);
1075
1076   if (notification.type[0] == 0) {
1077     PyErr_SetString(PyExc_RuntimeError, "type not set");
1078     return NULL;
1079   }
1080   ds = plugin_get_ds(notification.type);
1081   if (ds == NULL) {
1082     PyErr_Format(PyExc_TypeError, "Dataset %s not found", notification.type);
1083     return NULL;
1084   }
1085   if (meta != NULL && meta != Py_None && !PyDict_Check(meta)) {
1086     PyErr_Format(PyExc_TypeError, "meta must be a dict");
1087     return NULL;
1088   }
1089   cpy_build_notification_meta(&notification, meta);
1090
1091   if (notification.time == 0)
1092     notification.time = cdtime();
1093   if (notification.host[0] == 0)
1094     sstrncpy(notification.host, hostname_g, sizeof(notification.host));
1095   if (notification.plugin[0] == 0)
1096     sstrncpy(notification.plugin, "python", sizeof(notification.plugin));
1097   Py_BEGIN_ALLOW_THREADS;
1098   ret = plugin_dispatch_notification(&notification);
1099   if (notification.meta)
1100     plugin_notification_meta_free(notification.meta);
1101   Py_END_ALLOW_THREADS;
1102   if (ret != 0) {
1103     PyErr_SetString(PyExc_RuntimeError,
1104                     "error dispatching notification, read the logs");
1105     return NULL;
1106   }
1107   Py_RETURN_NONE;
1108 }
1109
1110 static PyObject *Notification_new(PyTypeObject *type, PyObject *args,
1111                                   PyObject *kwds) {
1112   Notification *self;
1113
1114   self = (Notification *)PluginData_new(type, args, kwds);
1115   if (self == NULL)
1116     return NULL;
1117
1118   self->meta = PyDict_New();
1119   self->message[0] = 0;
1120   self->severity = 0;
1121   return (PyObject *)self;
1122 }
1123
1124 static int Notification_setstring(PyObject *self, PyObject *value, void *data) {
1125   char *old;
1126   const char *new;
1127
1128   if (value == NULL) {
1129     PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute");
1130     return -1;
1131   }
1132   Py_INCREF(value);
1133   new = cpy_unicode_or_bytes_to_string(&value);
1134   if (new == NULL) {
1135     Py_DECREF(value);
1136     return -1;
1137   }
1138   old = ((char *)self) + (intptr_t)data;
1139   sstrncpy(old, new, NOTIF_MAX_MSG_LEN);
1140   Py_DECREF(value);
1141   return 0;
1142 }
1143
1144 static PyObject *Notification_repr(PyObject *s) {
1145   PyObject *ret, *tmp;
1146   static PyObject *l_severity = NULL, *l_message = NULL, *l_meta = NULL,
1147                   *l_closing = NULL;
1148   Notification *self = (Notification *)s;
1149
1150   if (l_severity == NULL)
1151     l_severity = cpy_string_to_unicode_or_bytes(",severity=");
1152   if (l_message == NULL)
1153     l_message = cpy_string_to_unicode_or_bytes(",message=");
1154   if (l_meta == NULL)
1155     l_meta = cpy_string_to_unicode_or_bytes(",meta=");
1156   if (l_closing == NULL)
1157     l_closing = cpy_string_to_unicode_or_bytes(")");
1158
1159   if (l_severity == NULL || l_message == NULL || l_meta == NULL ||
1160       l_closing == NULL)
1161     return NULL;
1162
1163   ret = cpy_common_repr(s);
1164   if (self->severity != 0) {
1165     CPY_STRCAT(&ret, l_severity);
1166     tmp = PyInt_FromLong(self->severity);
1167     CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
1168     CPY_STRCAT_AND_DEL(&ret, tmp);
1169   }
1170   if (self->message[0] != 0) {
1171     CPY_STRCAT(&ret, l_message);
1172     tmp = cpy_string_to_unicode_or_bytes(self->message);
1173     CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
1174     CPY_STRCAT_AND_DEL(&ret, tmp);
1175   }
1176   if (self->meta &&
1177       (!PyDict_Check(self->meta) || PyDict_Size(self->meta) > 0)) {
1178     CPY_STRCAT(&ret, l_meta);
1179     tmp = PyObject_Repr(self->meta);
1180     CPY_STRCAT_AND_DEL(&ret, tmp);
1181   }
1182   CPY_STRCAT(&ret, l_closing);
1183   return ret;
1184 }
1185
1186 static int Notification_traverse(PyObject *self, visitproc visit, void *arg) {
1187   Notification *n = (Notification *)self;
1188   Py_VISIT(n->meta);
1189   return 0;
1190 }
1191
1192 static int Notification_clear(PyObject *self) {
1193   Notification *n = (Notification *)self;
1194   Py_CLEAR(n->meta);
1195   return 0;
1196 }
1197
1198 static void Notification_dealloc(PyObject *self) {
1199   Notification_clear(self);
1200   self->ob_type->tp_free(self);
1201 }
1202
1203 static PyMethodDef Notification_methods[] = {
1204     {"dispatch", (PyCFunction)Notification_dispatch,
1205      METH_VARARGS | METH_KEYWORDS, dispatch_doc},
1206     {NULL}};
1207
1208 static PyMemberDef Notification_members[] = {
1209     {"severity", T_INT, offsetof(Notification, severity), 0, severity_doc},
1210     {"meta", T_OBJECT_EX, offsetof(Notification, meta), 0, notification_meta_doc},
1211     {NULL}};
1212
1213 static PyGetSetDef Notification_getseters[] = {
1214     {"message", PluginData_getstring, Notification_setstring, message_doc,
1215      (void *)offsetof(Notification, message)},
1216     {NULL}};
1217
1218 PyTypeObject NotificationType = {
1219     CPY_INIT_TYPE "collectd.Notification",    /* tp_name */
1220     sizeof(Notification),                     /* tp_basicsize */
1221     0,                                        /* Will be filled in later */
1222     Notification_dealloc,                     /* tp_dealloc */
1223     0,                                        /* tp_print */
1224     0,                                        /* tp_getattr */
1225     0,                                        /* tp_setattr */
1226     0,                                        /* tp_compare */
1227     Notification_repr,                        /* tp_repr */
1228     0,                                        /* tp_as_number */
1229     0,                                        /* tp_as_sequence */
1230     0,                                        /* tp_as_mapping */
1231     0,                                        /* tp_hash */
1232     0,                                        /* tp_call */
1233     0,                                        /* tp_str */
1234     0,                                        /* tp_getattro */
1235     0,                                        /* tp_setattro */
1236     0,                                        /* tp_as_buffer */
1237     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
1238     Notification_doc,                         /* tp_doc */
1239     Notification_traverse,                    /* tp_traverse */
1240     Notification_clear,                       /* tp_clear */
1241     0,                                        /* tp_richcompare */
1242     0,                                        /* tp_weaklistoffset */
1243     0,                                        /* tp_iter */
1244     0,                                        /* tp_iternext */
1245     Notification_methods,                     /* tp_methods */
1246     Notification_members,                     /* tp_members */
1247     Notification_getseters,                   /* tp_getset */
1248     0,                                        /* tp_base */
1249     0,                                        /* tp_dict */
1250     0,                                        /* tp_descr_get */
1251     0,                                        /* tp_descr_set */
1252     0,                                        /* tp_dictoffset */
1253     Notification_init,                        /* tp_init */
1254     0,                                        /* tp_alloc */
1255     Notification_new                          /* tp_new */
1256 };
1257
1258 static char Signed_doc[] =
1259     "This is a long by another name. Use it in meta data dicts\n"
1260     "to choose the way it is stored in the meta data.";
1261
1262 PyTypeObject SignedType = {
1263     CPY_INIT_TYPE "collectd.Signed",          /* tp_name */
1264     sizeof(Signed),                           /* tp_basicsize */
1265     0,                                        /* Will be filled in later */
1266     0,                                        /* tp_dealloc */
1267     0,                                        /* tp_print */
1268     0,                                        /* tp_getattr */
1269     0,                                        /* tp_setattr */
1270     0,                                        /* tp_compare */
1271     0,                                        /* tp_repr */
1272     0,                                        /* tp_as_number */
1273     0,                                        /* tp_as_sequence */
1274     0,                                        /* tp_as_mapping */
1275     0,                                        /* tp_hash */
1276     0,                                        /* tp_call */
1277     0,                                        /* tp_str */
1278     0,                                        /* tp_getattro */
1279     0,                                        /* tp_setattro */
1280     0,                                        /* tp_as_buffer */
1281     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
1282     Signed_doc                                /* tp_doc */
1283 };
1284
1285 static char Unsigned_doc[] =
1286     "This is a long by another name. Use it in meta data dicts\n"
1287     "to choose the way it is stored in the meta data.";
1288
1289 PyTypeObject UnsignedType = {
1290     CPY_INIT_TYPE "collectd.Unsigned",        /* tp_name */
1291     sizeof(Unsigned),                         /* tp_basicsize */
1292     0,                                        /* Will be filled in later */
1293     0,                                        /* tp_dealloc */
1294     0,                                        /* tp_print */
1295     0,                                        /* tp_getattr */
1296     0,                                        /* tp_setattr */
1297     0,                                        /* tp_compare */
1298     0,                                        /* tp_repr */
1299     0,                                        /* tp_as_number */
1300     0,                                        /* tp_as_sequence */
1301     0,                                        /* tp_as_mapping */
1302     0,                                        /* tp_hash */
1303     0,                                        /* tp_call */
1304     0,                                        /* tp_str */
1305     0,                                        /* tp_getattro */
1306     0,                                        /* tp_setattro */
1307     0,                                        /* tp_as_buffer */
1308     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
1309     Unsigned_doc                              /* tp_doc */
1310 };