]> git.ipfire.org Git - people/ms/python-rrdtool.git/commitdiff
* Added support for Python 2.7 (other 2.x versions might also work, but its not tested)
authorChristian Jurk <commx@commx.ws>
Thu, 19 Dec 2013 16:13:45 +0000 (17:13 +0100)
committerChristian Jurk <commx@commx.ws>
Thu, 19 Dec 2013 16:13:45 +0000 (17:13 +0100)
* Added dump command
* Fixed some issues regarding generating graphs with graphv on Python 3.3

README.md
RRDtool.py
rrdtoolmodule.c [moved from rrdtool-py3k.c with 88% similarity]
setup.py

index 3492a0bd17772430c6da11fcd3ee7608f732a807..8afd59d4e43967b1f17574c43c233af27f486670 100644 (file)
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
-rrdtool-py3k
-============
+python-rrdtool
+==============
 
-Python 3 bindings for rrdtool with a native C extension and an object-oriented way to work with Round Robin Databases.
+Python bindings for rrdtool with a native C extension and an object-oriented way to work with Round Robin Databases. As of version 0.1.1, Python 2 and 3 is supported.
 
 The bindings are based on the code of the original Python 2 bindings for rrdtool by Hye-Shik Chang.
 
@@ -10,7 +10,7 @@ Installation
 
 In order to build the native C extension (which is an required step), you'll need librrd and its headers installed. Having rrdtool installed should be enough on most distributions.
 
-**How to Install? **
+**How to Install?**
 
 1. Download a copy of the repository.
 2. Run `python setup.py install` to build an install the native C extension as well as the RRD module.
@@ -20,8 +20,6 @@ Usage
 
 You can either use the low-level `rrdtool` module (which offers almost the same functions as the old Python 2 bindings for rrdtool provided), or the `RRDtool` module, which represents a object-oriented interface to rrdtool.
 
-Unlike the Python 2 binding, this binding is able to create graphs entirely in-memory, which makes it ideal for generating a large amount of graphs without having high I/O. This feature is currently available on POSIX platforms only, because I wasn't able to find a portable way to redirect stdout to a memory allocated buffer (which is required for that). To use this feature, specify "-" as the output filename in graphs (low-level extension), or `None` in the high-level module.
-
 ### Using the low-level `rrdtool` module
 
 ```python
@@ -49,13 +47,34 @@ rrd.update([(None, 32)])
 rrd.graph('test.png', '--end', 'now', '--start', 'end-5minutes', '--width', '400', 'DEF:ds0a=test.rrd:temp:AVERAGE', 'LINE1:ds0a#0000FF:"temperature\l"')
 
 # Same, but keep data in memory.
-data = rrd.graph(None, '--end', 'now', '--start', 'end-5minutes', '--width', '400', 'DEF:ds0a=test.rrd:temp:AVERAGE', 'LINE1:ds0a#0000FF:"temperature\l"')
+imgdata = rrd.graph(None, '--end', 'now', '--start', 'end-5minutes', '--width', '400', 'DEF:ds0a=test.rrd:temp:AVERAGE', 'LINE1:ds0a#0000FF:"temperature\l"')
 
 # You can also use file-like objects
 from io import BytesIO
 rrd.graph(io, ...)
 ```
 
+Changes
+-------
+
+## 0.1.1
+
+*Released 2013-12-19*
+
+* Added support for Python 2.7 (other 2.x versions might also work, but its not tested)
+* Added dump command
+* Fixed some issues regarding generating graphs with `graphv` on Python 3.3
+
+*Please note:* The `graph` method in the object-oriented RRD class will now return a dict by default (as returned by graphv). Only if the `output_file` parameter is None, the actual graph image bytes are returned. Python 3.3 will return a bytes object whereas Python 2.x will return a str object.
+
+## 0.1.0
+
+*Released 2012-09-17*
+
+* Initial release.
+* Support for Python 3.x added
+* Updated documentation strings (`__doc__`) for each of the rrdtool functions
+
 Author
 ------
 
index 006f33158125df02b32b4553eecdf4fe8f80d312..d85069eff9368b72df732578a6b4dd39023966d6 100644 (file)
@@ -1,7 +1,7 @@
-#!/usr/bin/env python2
+#!/usr/bin/env python
 # -*- coding: utf-8 -*-
 #
-#  rrdtool-py3k, rrdtool bindings for Python 3.
+#  python-rrdtool, rrdtool bindings for Python.
 #  Based on the rrdtool Python bindings for Python 2 from
 #  Hye-Shik Chang <perky@fallin.lv>.
 #
 #
 #
 
-from datetime import datetime
-from io import BytesIO
 import os
 import rrdtool
+
+from datetime import datetime
+from io import BytesIO
 from time import mktime
 
 def create(filename, *args):
@@ -57,25 +58,27 @@ class RRD:
                self.filename = filename
 
        def graph(self, output_file, *args):
-               "Create a graph based on one or more RRDs."
-               buffered = True
-               outfile = '-'
+               """
+               Generate a graph based on the arguments passed to this function.
+
+               If output_file is None, "-" will be used as the output filename.
+               In that case, rrdtool returns the image bytes within its info dict.
+               """
+               outfile = '-' if output_file is None else output_file
 
-               # write straigt into file using wrapper functions
-               if isinstance(output_file, str):
-                       buffered = False
-                       outfile = output_file
+               # when writing to a file-like object, use output buffering
+               if isinstance(output_file, os.IOBase):
+                       outfile = '-'
 
-               gdata = rrdtool.graph(outfile, *args)
+               info = rrdtool.graphv(outfile, *args)
 
-               if isinstance(gdata, tuple) and len(gdata) >= 4:
-                       if output_file is None:
-                               return gdata[3]
-                       elif isinstance(output_file, BytesIO):
-                               output_file.write(gdata[3])
-                               return output_file
+               if isinstance(info, dict) and 'image' in info:
+                       if isinstance(output_file, os.IOBase):
+                               output_file.write(info['image'])
+                       elif output_file is None:
+                               return info['image']
 
-               return None
+               return info
 
        def info(self):
                return rrdtool.info(self.filename)
similarity index 88%
rename from rrdtool-py3k.c
rename to rrdtoolmodule.c
index b5804e3bd668de13480687f70886f89493c90b05..9dececf0808e01d3d0fa3ecbdf2e6de6355b4eec 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * rrdtool-py3k, rrdtool bindings for Python 3.
+ * python-rrdtool, rrdtool bindings for Python.
  * Based on the rrdtool Python bindings for Python 2 from
  * Hye-Shik Chang <perky@fallin.lv>.
  *
@@ -25,7 +25,7 @@
 #include <Python.h>
 #include <rrd.h>
 
-static const char *_version = "0.1.0";
+static const char *_version = "0.1.1";
 
 /* Exception types */
 static PyObject *rrdtool_OperationalError;
@@ -142,8 +142,13 @@ _rrdtool_util_info2dict(const rrd_info_t *data)
                 break;
 
             case RD_I_BLO:
-                val = PyUnicode_FromStringAndSize(
+#if PY_MAJOR_VERSION >= 3
+                val = PyBytes_FromStringAndSize(
+                    (char *)data->value.u_blo.ptr, data->value.u_blo.size);
+#else
+                val = PyString_FromStringAndSize(
                   (char *)data->value.u_blo.ptr, data->value.u_blo.size);
+#endif
                 break;
             default:
                 break;
@@ -168,8 +173,8 @@ static char _rrdtool_create__doc__[] = "Create a new Round Robin Database.\n\n\
     [--step|-s step]\n\
     [DS:ds-name:DST:heartbeat:min:max]\n\
     [RRA:CF:xff:steps:rows]\n\n\
-    Full documentation can be found at:\n\
-    http://oss.oetiker.ch/rrdtool/doc/rrdcreate.en.html";
+  Full documentation can be found at:\n\
+  http://oss.oetiker.ch/rrdtool/doc/rrdcreate.en.html";
 
 static PyObject *
 _rrdtool_create(PyObject *self, PyObject *args)
@@ -192,6 +197,37 @@ _rrdtool_create(PyObject *self, PyObject *args)
     return ret;
 }
 
+static char _rrdtool_dump__doc__[] = "Dump an RRD to XML.\n\n\
+  Usage: dump(args..)\n\
+  Arguments:\n\n\
+    [-h|--header {none,xsd,dtd}\n\
+    [--no-header]\n\
+    file.rrd\n\
+    [file.xml]\n\n\
+  Full documentation can be found at:\n\
+  http://oss.oetiker.ch/rrdtool/doc/rrddump.en.html";
+
+static PyObject *
+_rrdtool_dump(PyObject *self, PyObject *args)
+{
+    PyObject *ret;
+
+    if (convert_args("dump", args) == -1)
+        return NULL;
+
+    if (rrd_dump(rrdtool_argc, rrdtool_argv) != 0) {
+        PyErr_SetString(rrdtool_OperationalError, rrd_get_error());
+        rrd_clear_error();
+        ret = NULL;
+    } else {
+        Py_INCREF(Py_None);
+        ret = Py_None;
+    }
+
+    destroy_args();
+    return ret;
+}
+
 static char _rrdtool_update__doc__[] = "Store a new set of values into\
  the RRD.\n\n\
  Usage: update(args..)\n\
@@ -200,8 +236,8 @@ static char _rrdtool_update__doc__[] = "Store a new set of values into\
    [--template|-t ds-name[:ds-name]...]\n\
    N|timestamp:value[:value...]\n\
    [timestamp:value[:value...] ...]\n\n\
-   Full documentation can be found at:\n\
-   http://oss.oetiker.ch/rrdtool/doc/rrdupdate.en.html";
+  Full documentation can be found at:\n\
+  http://oss.oetiker.ch/rrdtool/doc/rrdupdate.en.html";
 
 static PyObject *
 _rrdtool_update(PyObject *self, PyObject *args)
@@ -259,8 +295,8 @@ static char _rrdtool_fetch__doc__[] = "Fetch data from an RRD.\n\n\
     [--resolution|-r resolution]\n\
     [--start|-s start]\n\
     [--end|-e end]\n\n\
-    Full documentation can be found at:\n\
-    http://oss.oetiker.ch/rrdtool/doc/rrdfetch.en.html";
+  Full documentation can be found at:\n\
+  http://oss.oetiker.ch/rrdtool/doc/rrdfetch.en.html";
 
 static PyObject *
 _rrdtool_fetch(PyObject *self, PyObject *args)
@@ -330,8 +366,8 @@ static char _rrdtool_flushcached__doc__[] = "Flush RRD files from memory.\n\n\
     [--daemon address]\n\
     filename\n\
     [filename ...]\n\n\
-    Full documentation can be found at:\n\
-    http://oss.oetiker.ch/rrdtool/doc/rrdflushcached.en.html";
+  Full documentation can be found at:\n\
+  http://oss.oetiker.ch/rrdtool/doc/rrdflushcached.en.html";
 
 static PyObject *
 _rrdtool_flushcached(PyObject *self, PyObject *args)
@@ -410,49 +446,27 @@ static char _rrdtool_graph__doc__[] = "Create a graph based on one or more " \
     DEF:vname=rrdfile:ds-name:CF[:step=step][:start=time][:end=time]\n\
     CDEF:vname=RPN expression\n\
     VDEF=vname:RPN expression\n\n\
-    Full documentation can be found at:\n\
-    http://oss.oetiker.ch/rrdtool/doc/rrdgraph.en.html";
+  Full documentation can be found at:\n\
+  http://oss.oetiker.ch/rrdtool/doc/rrdgraph.en.html";
 
 static PyObject *
 _rrdtool_graph(PyObject *self, PyObject *args, PyObject *kwargs)
 {
     PyObject *ret;
     int xsize, ysize, i;
-    int keep_in_mem = 0;
     double ymin, ymax;
-    char **calcpr, *bp;
-#ifdef _POSIX_C_SOURCE
-    FILE *orig_stdout = stdout;
-    size_t bsize;
-#endif
+    char **calcpr;
 
     if (convert_args("graph", args) == -1)
         return NULL;
 
-    if (rrdtool_argc >= 2 && strcmp(rrdtool_argv[1], "-") == 0) {
-#ifdef _POSIX_C_SOURCE
-        keep_in_mem = 1;
-#else
-        PyErr_SetString(rrdtool_ProgrammingError,
-          "Output filename cannot be '-', because this platform does not "\
-          "support output buffering");
-        destroy_args();
-        return NULL;
-#endif
-    }
-
-#ifdef _POSIX_C_SOURCE
-    if (keep_in_mem)
-        stdout = open_memstream(&bp, &bsize);
-#endif
-
     if (rrd_graph(rrdtool_argc, rrdtool_argv, &calcpr, &xsize, &ysize, NULL,
                   &ymin, &ymax) == -1) {
         PyErr_SetString(rrdtool_OperationalError, rrd_get_error());
         rrd_clear_error();
         ret = NULL;
     } else {
-        ret = PyTuple_New(keep_in_mem ? 4 : 3);
+        ret = PyTuple_New(3);
 
         PyTuple_SET_ITEM(ret, 0, PyLong_FromLong((long)xsize));
         PyTuple_SET_ITEM(ret, 1, PyLong_FromLong((long)ysize));
@@ -473,21 +487,6 @@ _rrdtool_graph(PyObject *self, PyObject *args, PyObject *kwargs)
             Py_INCREF(Py_None);
             PyTuple_SET_ITEM(ret, 2, Py_None);
         }
-
-        /* feed buffered contents into a PyBytes object */
-        if (keep_in_mem) {
-            PyObject *pb;
-
-            fflush(stdout);
-            pb = PyBytes_FromStringAndSize(bp, bsize);
-
-            PyTuple_SET_ITEM(ret, 3, pb);
-        }
-    }
-
-    if (keep_in_mem) {
-        fclose(stdout);
-        stdout = orig_stdout;
     }
 
     destroy_args();
@@ -531,8 +530,8 @@ static char _rrdtool_tune__doc__[] = "Modify some basic properties of a " \
     [-a|--maximum ds-name:max]\n\
     [-d|--data-source-type ds-name:DST]\n\
     [-r|--data-source-rename old-name:new-name]\n\n\
-    Full documentation can be found at:\n\
-    http://oss.oetiker.ch/rrdtool/doc/rrdtune.en.html";
+  Full documentation can be found at:\n\
+  http://oss.oetiker.ch/rrdtool/doc/rrdtune.en.html";
 
 static PyObject *
 _rrdtool_tune(PyObject *self, PyObject *args)
@@ -561,8 +560,8 @@ static char _rrdtool_first__doc__[] = "Get the first UNIX timestamp of the "\
   Arguments:\n\n\
     filename\n\
     [--rraindex number]\n\n\
-    Full documentation can be found at:\n\
-    http://oss.oetiker.ch/rrdtool/doc/rrdfirst.en.html";
+  Full documentation can be found at:\n\
+  http://oss.oetiker.ch/rrdtool/doc/rrdfirst.en.html";
 
 static PyObject *
 _rrdtool_first(PyObject *self, PyObject *args)
@@ -590,8 +589,8 @@ static char _rrdtool_last__doc__[] = "Get the UNIX timestamp of the most "\
   Arguments:\n\n\
     filename\n\
     [--daemon address]\n\n\
-    Full documentation can be found at:\n\
-    http://oss.oetiker.ch/rrdtool/doc/rrdlast.en.html";
+  Full documentation can be found at:\n\
+  http://oss.oetiker.ch/rrdtool/doc/rrdlast.en.html";
 
 static PyObject *
 _rrdtool_last(PyObject *self, PyObject *args)
@@ -621,8 +620,8 @@ static char _rrdtool_resize__doc__[] = "Modify the number of rows in a "\
     rra-num\n\
     GROW|SHRINK\n\
     rows\n\n\
-    Full documentation can be found at:\n\
-    http://oss.oetiker.ch/rrdtool/doc/rrdlast.en.html";
+  Full documentation can be found at:\n\
+  http://oss.oetiker.ch/rrdtool/doc/rrdlast.en.html";
 
 static PyObject *
 _rrdtool_resize(PyObject *self, PyObject *args)
@@ -651,8 +650,8 @@ static char _rrdtool_info__doc__[] = "Extract header information from an "\
   Usage: info(filename)\n\
   Arguments:\n\n\
     filename\n\n\
-    Full documentation can be found at:\n\
-    http://oss.oetiker.ch/rrdtool/doc/rrdinfo.en.html";
+  Full documentation can be found at:\n\
+  http://oss.oetiker.ch/rrdtool/doc/rrdinfo.en.html";
 
 static PyObject *
 _rrdtool_info(PyObject *self, PyObject *args)
@@ -688,6 +687,8 @@ _rrdtool_lib_version(PyObject *self, PyObject *args)
 static PyMethodDef rrdtool_methods[] = {
        {"create", (PyCFunction)_rrdtool_create,
      METH_VARARGS, _rrdtool_create__doc__},
+    {"dump", (PyCFunction)_rrdtool_dump,
+     METH_VARARGS, _rrdtool_dump__doc__},
     {"update", (PyCFunction)_rrdtool_update,
      METH_VARARGS, _rrdtool_update__doc__},
     {"updatev", (PyCFunction)_rrdtool_updatev,
@@ -715,6 +716,8 @@ static PyMethodDef rrdtool_methods[] = {
        {NULL, NULL, 0, NULL}
 };
 
+#if PY_MAJOR_VERSION >= 3
+
 static struct PyModuleDef rrdtoolmodule = {
        PyModuleDef_HEAD_INIT,
        "rrdtool",
@@ -723,14 +726,32 @@ static struct PyModuleDef rrdtoolmodule = {
        rrdtool_methods
 };
 
+#endif
+
+#if PY_MAJOR_VERSION >= 3
 PyMODINIT_FUNC
 PyInit_rrdtool(void)
+#else
+void
+initrrdtool(void)
+#endif
 {
        PyObject *m;
 
+#if PY_MAJOR_VERSION >= 3
        m = PyModule_Create(&rrdtoolmodule);
+#else
+    m = Py_InitModule3("rrdtool",
+                       rrdtool_methods,
+                       "rrdtool bindings for Python");
+#endif
+
        if (m == NULL)
-               return NULL;
+#if PY_MAJOR_VERSION >= 3
+        return NULL;
+#else
+        return;
+#endif
 
        rrdtool_ProgrammingError = PyErr_NewException("rrdtool.ProgrammingError",
                                                      NULL, NULL);
@@ -743,5 +764,7 @@ PyInit_rrdtool(void)
        PyModule_AddObject(m, "OperationalError", rrdtool_OperationalError);
     PyModule_AddObject(m, "__version__", PyUnicode_FromString(_version));
 
+#if PY_MAJOR_VERSION >= 3
        return m;
+#endif
 }
index be48251db86b77617292458765123cea72b87c65..7637dac7f392afb79d8957f4a516fc53b00882b9 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -1,13 +1,15 @@
 from distutils.core import setup, Extension
 
 def main():
-    module = Extension('rrdtool', sources=['rrdtool-py3k.c'],
+    module = Extension('rrdtool',
+                       sources=['rrdtoolmodule.c'],
+                       include_dirs = ['/opt/local/include'],
                        libraries=['rrd'])
 
     kwargs = dict(
         name='python-rrdtool',
-        version='0.1.0',
-        description='rrdtool bindings for Python 3',
+        version='0.1.1',
+        description='rrdtool bindings for Python',
         keywords=['rrdtool'],
         author='Christian Jurk, Hye-Shik Chang',
         author_email='commx@commx.ws',