From aaf5907863bed9a044fa0e3e2eacd1ca2de53c59 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Wed, 15 Jul 2009 21:36:58 +0200 Subject: Introduce new progress (base) classes in apt_pkg: - apt_pkg.AcquireProgress - apt_pkg.OpProgress --- python/acquireprogress.cc | 198 ++++++++++++++++++++++++++++++++++++++++++++++ python/apt_pkgmodule.cc | 2 + python/apt_pkgmodule.h | 2 + python/opprogress.cc | 173 ++++++++++++++++++++++++++++++++++++++++ python/progress.cc | 14 +++- 5 files changed, 387 insertions(+), 2 deletions(-) create mode 100644 python/acquireprogress.cc create mode 100644 python/opprogress.cc (limited to 'python') diff --git a/python/acquireprogress.cc b/python/acquireprogress.cc new file mode 100644 index 00000000..ac3b8fd9 --- /dev/null +++ b/python/acquireprogress.cc @@ -0,0 +1,198 @@ +/* acquireprogress.cc - Base class for FetchProgress classes. + * + * Copyright 2009 Julian Andres Klode + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "generic.h" +#include +#include + +typedef struct { + PyObject_HEAD + double last_bytes; + double current_cps; + double current_bytes; + double total_bytes; + double fetched_bytes; + unsigned long elapsed_time; + unsigned long total_items; + unsigned long current_items; +} PyAcquireProgressObject; + + +// DUMMY IMPLEMENTATIONS. +static char *acquireprogress_media_change_doc = + "media_change(media: str, drive: str) -> bool\n\n" + "Invoked when the user should be prompted to change the inserted\n" + "removable media.\n\n" + "This method should not return until the user has confirmed to the user\n" + "interface that the media change is complete.\n\n" + ":param:media The name of the media type that should be changed.\n" + ":param:drive The identifying name of the drive whose media should be\n" + " changed.\n\n" + "Return True if the user confirms the media change, False if it is\n" + "cancelled."; +static PyObject *acquireprogress_media_change(PyObject *self, PyObject *args) +{ + Py_RETURN_FALSE; +} + +static char *acquireprogress_ims_hit_doc = "ims_hit(item: AcquireItemDesc)\n\n" + "Invoked when an item is confirmed to be up-to-date. For instance,\n" + "when an HTTP download is informed that the file on the server was\n" + "not modified."; +static PyObject *acquireprogress_ims_hit(PyObject *self, PyObject *arg) +{ + // TODO: Add type check. + Py_RETURN_NONE; +} + +static char *acquireprogress_fetch_doc = "fetch(item: AcquireItemDesc)\n\n" + "Invoked when some of an item's data is fetched."; +static PyObject *acquireprogress_fetch(PyObject *self, PyObject *args) +{ + // TODO: Add type check. + Py_RETURN_NONE; +} + +static char *acquireprogress_done_doc = "done(item: AcquireItemDesc)\n\n" + "Invoked when an item is successfully and completely fetched."; +static PyObject *acquireprogress_done(PyObject *self, PyObject *args) +{ + // TODO: Add type check. + Py_RETURN_NONE; +} + +static char *acquireprogress_fail_doc = "fail(item: AcquireItemDesc)\n\n" + "Invoked when the process of fetching an item encounters a fatal error."; +static PyObject *acquireprogress_fail(PyObject *self, PyObject *args) +{ + // TODO: Add type check. + Py_RETURN_NONE; +} + +static char *acquireprogress_pulse_doc = "pulse(owner: Acquire) -> bool\n\n" + "Periodically invoked while the Acquire process is underway.\n\n" + "Return False if the user asked to cancel the whole Acquire process."; +static PyObject *acquireprogress_pulse(PyObject *self, PyObject *args) +{ + // TODO: Add type check. + Py_RETURN_TRUE; +} + +static char *acquireprogress_start_doc = "start()\n\n" + "Invoked when the Acquire process starts running."; +static PyObject *acquireprogress_start(PyObject *self, PyObject *args) +{ + Py_RETURN_NONE; +} + +static char *acquireprogress_stop_doc = "stop()\n\n" + "Invoked when the Acquire process stops running."; +static PyObject *acquireprogress_stop(PyObject *self, PyObject *args) +{ + Py_RETURN_NONE; +} + +static PyMethodDef acquireprogress_methods[] = { + {"media_change", acquireprogress_media_change, METH_VARARGS, + acquireprogress_media_change_doc}, + {"ims_hit",acquireprogress_ims_hit,METH_VARARGS, + acquireprogress_ims_hit_doc}, + {"fetch",acquireprogress_fetch,METH_VARARGS,acquireprogress_fetch_doc}, + {"done",acquireprogress_done,METH_VARARGS,acquireprogress_done_doc}, + {"fail",acquireprogress_fail,METH_VARARGS,acquireprogress_fail_doc}, + {"pulse",acquireprogress_pulse,METH_VARARGS,acquireprogress_pulse_doc}, + {"start",acquireprogress_start,METH_NOARGS,acquireprogress_start_doc}, + {"stop",acquireprogress_stop,METH_NOARGS,acquireprogress_stop_doc}, + {NULL} +}; + +static PyMemberDef acquireprogress_members[] = { + {"last_bytes", T_DOUBLE, offsetof(PyAcquireProgressObject, last_bytes), 0, + "The number of bytes fetched as of the previous call to pulse(),\n" + "including local items."}, + {"current_cps", T_DOUBLE, offsetof(PyAcquireProgressObject, current_cps), 0, + "The current rate of download, in bytes per second."}, + {"current_bytes", T_DOUBLE, offsetof(PyAcquireProgressObject, current_bytes), + 0, "The number of bytes fetched."}, + {"total_bytes", T_DOUBLE, offsetof(PyAcquireProgressObject, total_bytes), 0, + "The total number of bytes that need to be fetched. This member is\n" + "inaccurate, as new items might be enqueued while the download is\n" + "in progress!"}, + {"fetched_bytes", T_DOUBLE,offsetof(PyAcquireProgressObject, fetched_bytes), + 0, "The total number of bytes accounted for by items that were\n" + "successfully fetched."}, + {"elapsed_time", T_ULONG, offsetof(PyAcquireProgressObject, elapsed_time),0, + "The amount of time that has elapsed since the download started."}, + {"total_items", T_ULONG, offsetof(PyAcquireProgressObject, total_items),0, + "The total number of items that need to be fetched. This member is\n" + "inaccurate, as new items might be enqueued while the download is\n" + "in progress!"}, + {"current_items", T_ULONG, offsetof(PyAcquireProgressObject, current_items), + 0, "The number of items that have been successfully downloaded."}, + {NULL} +}; + +static char *acquireprogress_doc = "AcquireProgress()\n\n" + "A monitor object for downloads controlled by the Acquire class. This is\n" + "an mostly abstract class. You should subclass it and implement the\n" + "methods to get something useful."; + +PyTypeObject PyAcquireProgress_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.AcquireProgress", // tp_name + sizeof(PyAcquireProgressObject), // tp_basicsize + 0, // tp_itemsize + // Methods + 0, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + 0, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + Py_TPFLAGS_DEFAULT | // tp_flags + Py_TPFLAGS_BASETYPE, + acquireprogress_doc, // tp_doc + 0, // tp_traverse + 0, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + acquireprogress_methods, // tp_methods + acquireprogress_members, // tp_members + 0, // tp_getset + 0, // tp_base + 0, // tp_dict + 0, // tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + 0, // tp_init + 0, // tp_alloc + PyType_GenericNew, // tp_new +}; diff --git a/python/apt_pkgmodule.cc b/python/apt_pkgmodule.cc index bc2f4258..4f948847 100644 --- a/python/apt_pkgmodule.cc +++ b/python/apt_pkgmodule.cc @@ -621,6 +621,8 @@ extern "C" void initapt_pkg() ADDTYPE(Module,"HashString",&PyHashString_Type); ADDTYPE(Module,"Policy",&PyPolicy_Type); ADDTYPE(Module,"Hashes",&PyHashes_Type); + ADDTYPE(Module,"OpProgress",&PyOpProgress_Type); + ADDTYPE(Module,"AcquireProgress",&PyAcquireProgress_Type); // Tag file constants PyModule_AddObject(Module,"REWRITE_PACKAGE_ORDER", CharCharToList(TFRewritePackageOrder)); diff --git a/python/apt_pkgmodule.h b/python/apt_pkgmodule.h index 97be5d5c..34bc2ae5 100644 --- a/python/apt_pkgmodule.h +++ b/python/apt_pkgmodule.h @@ -112,6 +112,8 @@ extern PyTypeObject PyIndexRecords_Type; // Policy extern PyTypeObject PyPolicy_Type; extern PyTypeObject PyHashes_Type; +extern PyTypeObject PyOpProgress_Type; +extern PyTypeObject PyAcquireProgress_Type; #include "python-apt.h" #endif diff --git a/python/opprogress.cc b/python/opprogress.cc new file mode 100644 index 00000000..450e290a --- /dev/null +++ b/python/opprogress.cc @@ -0,0 +1,173 @@ +/* op-progress.cc - Base class for OpProgress classes. + * + * Copyright 2009 Julian Andres Klode + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "generic.h" +#include +#include + +typedef struct { + PyObject_HEAD + PyObject *op; + PyObject *subop; + int major_change; + float percent; +} PyOpProgressObject; + +static PyObject *opprogress_update(PyObject *Self, PyObject *args) +{ + Py_RETURN_NONE; +} + +static PyObject *opprogress_done(PyObject *Self, PyObject *args) +{ + Py_RETURN_NONE; +} + +static PyObject *opprogress_get_op(PyOpProgressObject *self, void *closure) +{ + return self->op; +} + +static int opprogress_set_op(PyOpProgressObject *self, PyObject *value, + void *closure) +{ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete 'op'"); + return -1; + } + if (!PyString_Check(value)) { + PyErr_SetString(PyExc_TypeError,"'op' must be a string."); + return -1; + } + Py_DECREF(self->op); + Py_INCREF(value); + + self->op = value; + return 0; +} + +static PyObject *opprogress_get_subop(PyOpProgressObject *self, void *closure) +{ + return self->subop; +} + +static int opprogress_set_subop(PyOpProgressObject *self, PyObject *value, + void *closure) +{ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete 'subop'."); + return -1; + } + if (!PyString_Check(value)) { + PyErr_SetString(PyExc_TypeError,"'subop' must be a string."); + return -1; + } + Py_DECREF(self->subop); + Py_INCREF(value); + self->subop = value; + return 0; +} + +static PyMethodDef opprogress_methods[] = { + {"update",opprogress_update,METH_NOARGS,"update()\n\nCalled periodically."}, + {"done",opprogress_done,METH_NOARGS,"update()\n\nCalled when done."}, + {NULL}, +}; + +static PyMemberDef opprogress_members[] = { + {"major_change", T_INT, offsetof(PyOpProgressObject, major_change), 0, + "Boolean value indicating whether the change is a major change."}, + {"percent", T_FLOAT, offsetof(PyOpProgressObject, percent), 0, + "Percentage of completion (float value)."}, + {NULL} +}; + +static PyGetSetDef opprogress_getset[] = { + {"op", (getter)opprogress_get_op, (setter)opprogress_set_op, + "Description of the current operation"}, + {"subop", (getter)opprogress_get_subop, (setter)opprogress_set_subop, + "Description of the current sub-operation"}, + {NULL}, +}; + +static void opprogress_dealloc(PyObject *self) +{ + Py_XDECREF(((PyOpProgressObject *)self)->op); + Py_XDECREF(((PyOpProgressObject *)self)->subop); + self->ob_type->tp_free(self); +} + +static PyObject *opprogress_new(PyTypeObject *type, PyObject *args, + PyObject *kwds) +{ + PyOpProgressObject *res = (PyOpProgressObject *)type->tp_alloc(type, 0); + res->op = PyString_FromString(""); + res->subop = PyString_FromString(""); + return (PyObject *)res; +} + +static char *opprogress_doc = "OpProgress()\n\n" + "A base class for writing custom operation progress classes. Subclasses\n" + "should override all the methods (and call the parent ones) but shall\n" + "not override any of the inherited descriptors because they may be\n" + "ignored."; + +PyTypeObject PyOpProgress_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.OpProgress", // tp_name + sizeof(PyOpProgressObject), // tp_basicsize + 0, // tp_itemsize + // Methods + opprogress_dealloc, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + 0, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + Py_TPFLAGS_DEFAULT | // tp_flags + Py_TPFLAGS_BASETYPE, + opprogress_doc, // tp_doc + 0, // tp_traverse + 0, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + opprogress_methods, // tp_methods + opprogress_members, // tp_members + opprogress_getset, // tp_getset + 0, // tp_base + 0, // tp_dict + 0, // tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + 0, // tp_init + 0, // tp_alloc + opprogress_new, // tp_new +}; diff --git a/python/progress.cc b/python/progress.cc index 44f27b0c..b1845f0a 100644 --- a/python/progress.cc +++ b/python/progress.cc @@ -15,6 +15,7 @@ #include #include "progress.h" #include "generic.h" +#include "apt_pkgmodule.h" // generic bool PyCallbackObj::RunSimpleCallback(const char* method_name, @@ -75,11 +76,20 @@ void PyOpProgress::Update() PyObject_SetAttrString(callbackInst, "majorChange", o); Py_XDECREF(o); + + // Build up the argument list... if(CheckChange(0.05)) { - PyObject *arglist = Py_BuildValue("(f)", Percent); - RunSimpleCallback("update", arglist); + if (PyObject_TypeCheck(callbackInst, &PyOpProgress_Type)) { + o = Py_BuildValue("f", Percent); + PyObject_SetAttrString(callbackInst, "percent", o); + RunSimpleCallback("update"); + Py_XDECREF(o); + } else { + PyObject *arglist = Py_BuildValue("(f)", Percent); + RunSimpleCallback("update", arglist); + } } }; -- cgit v1.2.3