[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#334923: Please provide a C/C++-language interface to python-apt.



On Thu, Oct 20, 2005 at 01:05:57PM -0700, Daniel Burrows wrote:
> Package: python-apt
> Severity: wishlist
> 
>   If a program that uses libapt-pkg wants to allow python extensions to access
> apt objects directly, the obvious way to do it is via python-apt.
> Unfortunately, it doesn't look like this is possible unless the apt layer
> of the program is placed entirely under the control of python code.  It would
> be nice if python-apt provided headers and interface functions that could be
> used to wrap apt objects so they can be passed to Python and to unwrap them
> so they can be processed by C++ functions.
> 
>   Presumably this stuff would go in the hypothetical package python-apt-dev.

The attached patch shows the current state of the work. Basically, all types
are exported via the module and some macros and functions are provided to
create those objects and to get the C++ object from the object (which often
is a pointer).

For every type, we provide the following (on the example of HashString):

  1. PyHashString_Type    -- The PyTypeObject of the type.
  2. PyHashString_FromCpp -- Takes HashString* and returns a PyObject*.
  3. PyHashString_ToCpp   -- Takes PyObject* and returns HashString*.
  4. PyHashString_Check   -- Check that the PyObject is a HashString,
                             or subclass.

Using the API also seems to be a bit complicated, because the Python objects
delete the underlying object when no reference is there. This means that you
should probably call Py_INCREF() on the object before exporting it, and
Py_DECREF() at the end of the program. Otherwise, calling 'del' in Python
will cause the C++ object to be deallocated.

The patch is not complete, it's purpose is to show the basic idea, and to
get some review of this idea before I continue with this. And it's not very
formatted yet.

Regards,
Julian

-- 
Julian Andres Klode  - Free Software Developer
   Debian Developer  - Contributing Member of SPI
   Ubuntu Member     - Fellow of FSFE

Website: http://jak-linux.org/   XMPP: juliank@jabber.org
Debian:  http://www.debian.org/  SPI:  http://www.spi-inc.org/
Ubuntu:  http://www.ubuntu.com/  FSFE: http://www.fsfe.org/
=== modified file 'debian/changelog'
--- debian/changelog	2009-06-14 16:21:05 +0000
+++ debian/changelog	2009-06-14 16:22:06 +0000
@@ -3,6 +3,7 @@ python-apt (0.7.92) UNRELEASED; urgency=
   [ Julian Andres Klode ]
   * Add apt_pkg.HashString and apt_pkg.IndexRecords (Closes: #456141)
   * Add apt_pkg.Policy class (Closes: #382725)
+  * Provide a C++ API in the package python-apt-dev (Closes: #334923)
   * Allow types providing __new__() to be subclassed.
   * Bugfix: Delete pointers correctly, fixing memory leaks. (LP: #370149)
   * apt/package.py: Return VersionList objects in Package.versions, which

=== modified file 'debian/control'
--- debian/control	2009-06-05 17:36:59 +0000
+++ debian/control	2009-06-11 19:05:20 +0000
@@ -54,3 +54,14 @@ Description: Python interface to libapt-
  variety of functions.
  .
  This package contains the extension built for the Python debug interpreter.
+
+Package: python-apt-dev
+Architecture: all
+Depends: python-apt (>= ${source:Version}), libapt-pkg-dev (>= 0.7.10)
+Description: Python interface to libapt-pkg (development files)
+ The apt_pkg Python interface will provide full access to the internal
+ libapt-pkg structures allowing Python programs to easily perform a
+ variety of functions.
+ .
+ This package contains the header files needed to use python-apt objects from
+ C++ applications.

=== added file 'debian/python-apt-dev.examples'
--- debian/python-apt-dev.examples	1970-01-01 00:00:00 +0000
+++ debian/python-apt-dev.examples	2009-06-11 19:09:18 +0000
@@ -0,0 +1 @@
+doc/client-example.cc

=== added file 'debian/python-apt-dev.install'
--- debian/python-apt-dev.install	1970-01-01 00:00:00 +0000
+++ debian/python-apt-dev.install	2009-06-11 18:56:25 +0000
@@ -0,0 +1,2 @@
+python/python-apt.h usr/include/python-apt/
+python/generic.h usr/include/python-apt/

=== added file 'doc/client-example.cc'
--- doc/client-example.cc	1970-01-01 00:00:00 +0000
+++ doc/client-example.cc	2009-06-11 19:10:47 +0000
@@ -0,0 +1,46 @@
+/*
+ * client-example.cc - A simple example for using the python-apt C++ API.
+ *
+ * Copyright 2009 Julian Andres Klode <jak@debian.org>
+ *
+ * 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 <python-apt/python-apt.h>
+
+int main(int argc, char *argv[]) {
+    Py_Initialize();
+    if (import_apt_pkg() < 0)
+        return 1;
+
+    // Initialize a module.
+    PyObject *Module = Py_InitModule("client", NULL);
+
+    // Create a HashString, which will be added to the module.
+    HashString *hash = new HashString("0966a120bb936bdc6fdeac445707aa6b");
+    // Create a Python object for the hashstring and add it to the module
+    PyModule_AddObject(Module, "hash", PyHashString_FromCpp(hash));
+
+    // Another example: Add the HashString type to the module.
+    Py_INCREF(&PyHashString_Type);
+    PyModule_AddObject(Module, "HashString", (PyObject*)(&PyHashString_Type));
+
+    // Run IPython, adding the client module to the namespace.
+    PySys_SetArgv(argc, argv);
+    PyRun_SimpleString("from IPython.Shell import start\n");
+    PyRun_SimpleString("import client\n");
+    PyRun_SimpleString("start(user_ns=dict(client=client)).mainloop()\n");
+    Py_Finalize();
+}

=== modified file 'python/apt_pkgmodule.cc'
--- python/apt_pkgmodule.cc	2009-06-09 19:04:36 +0000
+++ python/apt_pkgmodule.cc	2009-06-11 18:43:28 +0000
@@ -501,6 +501,38 @@ static PyMethodDef methods[] =
    {}
 };
 
+static struct _PyAptPkgAPIStruct API = {
+   &PkgAcquireType,           // acquire_type
+   &PkgAcquireFileType,       // acquirefile_type
+   &AcquireItemType,          // acquireitem_type
+   &PkgActionGroupType,       // actiongroup_type
+   &PkgCacheType,             // cache_type
+   &PkgCdromType,             // cdrom_type
+   &ConfigurationType,        // configuration_type
+   &ConfigurationPtrType,     // configurationptr_type
+   &ConfigurationSubType,     // configurationsub_type
+   &PkgDepCacheType,          // depcache_type
+   &DependencyType,           // dependency_type
+   &RDepListType,             // dependencylist_type
+   &DescriptionType,          // description_type
+   &PyHashString_Type,        // hashstring_type
+   &PyIndexRecords_Type,      // indexrecords_type
+   &MetaIndexType,            // metaindex_type
+   &PackageType,              // package_type
+   &PackageFileType,          // packagefile_type
+   &PackageIndexFileType,     // packageindexfile_type
+   &PkgListType,              // packagelist_type
+   &PkgManagerType,           // packagemanager_type
+   &PkgRecordsType,           // packagerecords_type
+   &PyPolicy_Type,            // policy_type
+   &PkgProblemResolverType,   // problemresolver_type
+   &PkgSourceListType,        // sourcelist_type
+   &PkgSrcRecordsType,        // sourcerecords_type
+   &TagFileType,              // tagfile_type
+   &TagSecType,               // tagsection_type
+   &VersionType,              // version_type
+};
+
 
 #define ADDTYPE(mod,name,type) { \
     if (PyType_Ready(type) == -1) INIT_ERROR; \
@@ -621,6 +653,8 @@ extern "C" void initapt_pkg()
                       CharCharToList(TFRewriteSourceOrder));
 #endif
 
+   PyModule_AddObject(Module, "_C_API", PyCObject_FromVoidPtr(&API, NULL));
+
    // Version..
    PyModule_AddStringConstant(Module,"VERSION",(char *)pkgVersion);
    PyModule_AddStringConstant(Module,"LIB_VERSION",(char *)pkgLibVersion);

=== modified file 'python/apt_pkgmodule.h'
--- python/apt_pkgmodule.h	2009-06-09 18:44:58 +0000
+++ python/apt_pkgmodule.h	2009-06-12 17:24:49 +0000
@@ -11,6 +11,7 @@
 #define APT_PKGMODULE_H
 
 #include <Python.h>
+#include "python-apt.h"
 #include <apt-pkg/hashes.h>
 
 // Configuration Stuff

=== added file 'python/python-apt.h'
--- python/python-apt.h	1970-01-01 00:00:00 +0000
+++ python/python-apt.h	2009-06-14 16:18:42 +0000
@@ -0,0 +1,111 @@
+/*
+ * python-apt.h - Header file for the public interface.
+ *
+ * Copyright 2009 Julian Andres Klode <jak@debian.org>
+ *
+ * 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.
+ */
+
+#ifndef PYTHON_APT_H
+#define PYTHON_APT_H
+#include <Python.h>
+#include <apt-pkg/hashes.h>
+#include "generic.h"
+
+struct _PyAptPkgAPIStruct {
+    PyTypeObject *acquire_type;
+    PyTypeObject *acquirefile_type;
+    PyTypeObject *acquireitem_type;
+    PyTypeObject *actiongroup_type;
+    PyTypeObject *cache_type;
+    PyTypeObject *cdrom_type;
+    PyTypeObject *configuration_type;
+    PyTypeObject *configurationptr_type;
+    PyTypeObject *configurationsub_type;
+    PyTypeObject *depcache_type;
+    PyTypeObject *dependency_type;
+    PyTypeObject *dependencylist_type;
+    PyTypeObject *description_type;
+    PyTypeObject *hashstring_type;
+    PyTypeObject *indexrecords_type;
+    PyTypeObject *metaindex_type;
+    PyTypeObject *package_type;
+    PyTypeObject *packagefile_type;
+    PyTypeObject *packageindexfile_type;
+    PyTypeObject *packagelist_type;
+    PyTypeObject *packagemanager_type;
+    PyTypeObject *packagerecords_type;
+    PyTypeObject *policy_type;
+    PyTypeObject *problemresolver_type;
+    PyTypeObject *sourcelist_type;
+    PyTypeObject *sourcerecords_type;
+    PyTypeObject *tagfile_type;
+    PyTypeObject *tagsection_type;
+    PyTypeObject *version_type;
+};
+
+#ifndef APT_PKGMODULE_H
+    #define PyAcquire_Type           *(_PyAptPkg_API->acquire_type)
+    #define PyAcquireFile_Type       *(_PyAptPkg_API->acquirefile_type)
+    #define PyAcquireItem_Type       *(_PyAptPkg_API->acquireitem_type)
+    #define PyActionGroup_Type       *(_PyAptPkg_API->actiongroup_type)
+    #define PyCache_Type             *(_PyAptPkg_API->cache_type)
+    #define PyCdrom_Type             *(_PyAptPkg_API->cdrom_type)
+    #define PyConfiguration_Type     *(_PyAptPkg_API->configuration_type)
+    #define PyConfigurationPtr_Type  *(_PyAptPkg_API->configurationptr_type)
+    #define PyConfigurationSub_Type  *(_PyAptPkg_API->configurationsub_type)
+    #define PyDepCache_Type          *(_PyAptPkg_API->depcache_type)
+    #define PyDependency_Type        *(_PyAptPkg_API->dependency_type)
+    #define PyDependencyList_Type    *(_PyAptPkg_API->dependencylist_type)
+    #define PyDescription_Type       *(_PyAptPkg_API->description_type)
+    #define PyHashString_Type        *(_PyAptPkg_API->hashstring_type)
+    #define PyIndexRecords_Type      *(_PyAptPkg_API->indexrecords_type)
+    #define PyMetaIndex_Type         *(_PyAptPkg_API->metaindex_type)
+    #define PyPackage_Type           *(_PyAptPkg_API->package_type)
+    #define PyPackageFile_Type       *(_PyAptPkg_API->packagefile_type)
+    #define PyPackageIndexFile_Type  *(_PyAptPkg_API->packageindexfile_type)
+    #define PyPackageList_Type       *(_PyAptPkg_API->packagelist_type)
+    #define PyPackageManager_Type    *(_PyAptPkg_API->packagemanager_type)
+    #define PyPackageRecords_Type    *(_PyAptPkg_API->packagerecords_type)
+    #define PyPolicy_Type            *(_PyAptPkg_API->policy_type)
+    #define PyProblemResolver_Type   *(_PyAptPkg_API->problemresolver_type)
+    #define PySourceList_Type        *(_PyAptPkg_API->sourcelist_type)
+    #define PySourceRecords_Type     *(_PyAptPkg_API->sourcerecords_type)
+    #define PyTagFile_Type           *(_PyAptPkg_API->tagfile_type)
+    #define PyTagSection_Type        *(_PyAptPkg_API->tagsection_type)
+    #define PyVersion_Type           *(_PyAptPkg_API->version_type)
+
+    // Creating
+    #define PyHashString_FromCpp(op) (CppPyObject_NEW<HashString*>(&PyHashString_Type, op))
+
+    struct _PyAptPkgAPIStruct *_PyAptPkg_API;
+
+    static int import_apt_pkg(void) {
+        PyObject *module = PyImport_ImportModule("apt_pkg");
+
+        if (module != NULL) {
+            PyObject *c_api_object = PyObject_GetAttrString(module, "_C_API");
+            if (c_api_object == NULL)
+                return -1;
+            if (PyCObject_Check(c_api_object))
+                _PyAptPkg_API = (struct _PyAptPkgAPIStruct *)PyCObject_AsVoidPtr(c_api_object);
+            Py_DECREF(c_api_object);
+        }
+        return 0;
+}
+#endif
+
+#endif

Attachment: signature.asc
Description: Digital signature


Reply to: