From: Michael Tremer Date: Thu, 9 Dec 2021 11:59:10 +0000 (+0000) Subject: python: Make callbacks available from Python X-Git-Tag: 0.9.28~841 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=45cbf6f4f7e37f31565414d1e46b33a369b496f1;p=pakfire.git python: Make callbacks available from Python Signed-off-by: Michael Tremer --- diff --git a/src/_pakfire/pakfire.c b/src/_pakfire/pakfire.c index 1cdf5a963..8320bdd73 100644 --- a/src/_pakfire/pakfire.c +++ b/src/_pakfire/pakfire.c @@ -47,18 +47,22 @@ static PyObject* Pakfire_new(PyTypeObject* type, PyObject* args, PyObject* kwds) PakfireObject* self = (PakfireObject *)type->tp_alloc(type, 0); if (self) { self->pakfire = NULL; - self->logger = NULL; + + // Callbacks + self->callbacks.log = NULL; + self->callbacks.status = NULL; + self->callbacks.progress = NULL; } return (PyObject *)self; } -static void Pakfire_logging_callback(void* data, int priority, const char* file, int line, +static void Pakfire_log_callback(void* data, int priority, const char* file, int line, const char* fn, const char* format, va_list args) { - PyObject* callback = (PyObject*)data; + struct callbacks* callbacks = (struct callbacks*)data; // Do nothing if callback isn't set - if (!callback) + if (!callbacks->log) return; // Translate priority to Python logging priorities @@ -95,7 +99,7 @@ static void Pakfire_logging_callback(void* data, int priority, const char* file, goto ERROR; // Call the callback - result = PyObject_CallObject(callback, tuple); + result = PyObject_CallObject(callbacks->log, tuple); ERROR: if (buffer) @@ -104,29 +108,87 @@ ERROR: Py_XDECREF(result); } +static void Pakfire_status_callback(void* data, const char* message) { + struct callbacks* callbacks = (struct callbacks*)data; + + // Do nothing if callback isn't set + if (!callbacks->status) + return; + + PyObject* args = NULL; + PyObject* result = NULL; + + // Create arguments tuple + args = Py_BuildValue("(s)", message); + if (!args) + goto ERROR; + + // Call the callback + result = PyObject_CallObject(callbacks->status, args); + +ERROR: + Py_XDECREF(args); + Py_XDECREF(result); +} + +static void Pakfire_progress_callback(void* data, int progress) { + struct callbacks* callbacks = (struct callbacks*)data; + + // Do nothing if callback isn't set + if (!callbacks->progress) + return; + + PyObject* args = NULL; + PyObject* result = NULL; + + // Create arguments tuple + args = Py_BuildValue("(i)", progress); + if (!args) + goto ERROR; + + // Call the callback + result = PyObject_CallObject(callbacks->progress, args); + +ERROR: + Py_XDECREF(args); + Py_XDECREF(result); +} + static int Pakfire_init(PakfireObject* self, PyObject* args, PyObject* kwds) { char* kwlist[] = { "path", "arch", "logger", "offline", "conf", "build", - "enable_ccache", "enable_snapshot", NULL }; + "enable_ccache", "enable_snapshot", "status_callback", "progress_callback", NULL }; const char* path = NULL; const char* arch = NULL; - PyObject* logger = NULL; const char* conf = NULL; int offline = 0; int build = 0; int enable_ccache = 1; int enable_snapshot = 1; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|zzOpzppp", kwlist, - &path, &arch, &logger, &offline, &conf, &build, - &enable_ccache, &enable_snapshot)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|zzOpzpppOO", kwlist, + &path, &arch, &self->callbacks.log, &offline, &conf, &build, + &enable_ccache, &enable_snapshot, &self->callbacks.status, + &self->callbacks.progress)) return -1; - // Check if logger is callable - if (logger && !PyCallable_Check(logger)) { + // Check if log callback is callable + if (self->callbacks.log && !PyCallable_Check(self->callbacks.log)) { PyErr_SetString(PyExc_TypeError, "logger must be callable\n"); return -1; } + // Check if status callback is callable + if (self->callbacks.status && !PyCallable_Check(self->callbacks.status)) { + PyErr_SetString(PyExc_TypeError, "status callback must be callable\n"); + return -1; + } + + // Check if progress callback is callable + if (self->callbacks.progress && !PyCallable_Check(self->callbacks.progress)) { + PyErr_SetString(PyExc_TypeError, "progress callback must be callable\n"); + return -1; + } + int flags = 0; // Enable offline mode @@ -146,10 +208,24 @@ static int Pakfire_init(PakfireObject* self, PyObject* args, PyObject* kwds) { // Configure callbacks struct pakfire_callbacks callbacks = { - .data = logger, - .log = (logger) ? Pakfire_logging_callback : NULL, + .data = &self->callbacks, }; + if (self->callbacks.log) { + callbacks.log = Pakfire_log_callback; + Py_INCREF(self->callbacks.log); + } + + if (self->callbacks.status) { + callbacks.status = Pakfire_status_callback; + Py_INCREF(self->callbacks.status); + } + + if (self->callbacks.progress) { + callbacks.progress = Pakfire_progress_callback; + Py_INCREF(self->callbacks.progress); + } + // Create a new Pakfire instance int r = pakfire_create(&self->pakfire, path, arch, conf, flags, &callbacks); if (r) { @@ -167,12 +243,6 @@ static int Pakfire_init(PakfireObject* self, PyObject* args, PyObject* kwds) { return -1; } - // Store a reference to the logger - if (logger) { - self->logger = logger; - Py_INCREF(self->logger); - } - return 0; } @@ -189,8 +259,9 @@ static void Pakfire_dealloc(PakfireObject* self) { TODO This has to move into struct pakfire or something similar. */ - if (self->logger) - Py_DECREF(self->logger); + Py_XDECREF(self->callbacks.log); + Py_XDECREF(self->callbacks.status); + Py_XDECREF(self->callbacks.progress); #endif Py_TYPE(self)->tp_free((PyObject *)self); diff --git a/src/_pakfire/pakfire.h b/src/_pakfire/pakfire.h index c8215766e..f720f1402 100644 --- a/src/_pakfire/pakfire.h +++ b/src/_pakfire/pakfire.h @@ -28,7 +28,13 @@ typedef struct { PyObject_HEAD struct pakfire* pakfire; - PyObject* logger; + + // Callbacks + struct callbacks { + PyObject* log; + PyObject* status; + PyObject* progress; + } callbacks; } PakfireObject; extern PyTypeObject PakfireType;