]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
* Makefile.am configure.in libvir.spec.in python/*: added a first
authorDaniel Veillard <veillard@redhat.com>
Mon, 19 Dec 2005 16:34:11 +0000 (16:34 +0000)
committerDaniel Veillard <veillard@redhat.com>
Mon, 19 Dec 2005 16:34:11 +0000 (16:34 +0000)
  version for python bindings, heavilly based on libxml2/libxslt
  way of doing things, maybe this need to be revisited. Added packaging
  too.
* src/hash.h: fixed the Copyright notice.
Daniel

12 files changed:
ChangeLog
Makefile.am
configure.in
libvir.spec.in
python/Makefile.am [new file with mode: 0644]
python/TODO [new file with mode: 0644]
python/generator.py [new file with mode: 0755]
python/libvir-python-api.xml [new file with mode: 0644]
python/libvir.c [new file with mode: 0644]
python/libvir_wrap.h [new file with mode: 0644]
python/types.c [new file with mode: 0644]
src/hash.h

index 450af34acddf6846b26dd04eaf2aad5643a16cee..4a17ea0086540dd3989967320ce49cc76d5b8ae0 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+Mon Dec 19 17:32:22 CET 2005 Daniel Veillard <veillard@redhat.com>
+
+       * Makefile.am configure.in libvir.spec.in python/*: added a first
+         version for python bindings, heavilly based on libxml2/libxslt
+         way of doing things, maybe this need to be revisited. Added packaging
+         too.
+       * src/hash.h: fixed the Copyright notice.
+
 Fri Dec 16 19:35:29 CET 2005 Karel Zak <kzak@redhat.com>
 
        * src/xml.c src/internal.h src/libvir.c: struct checks cleanup, 
index 1a83a139de340338f77a1cbe84db5bc6f144d88b..1c83f92e3ca81c03dea1b77396b6adb948d957bf 100644 (file)
@@ -1,6 +1,7 @@
 ## Process this file with automake to produce Makefile.in
 
-SUBDIRS = src include docs
+SUBDIRS = src include docs @PYTHON_SUBDIR@
+
 EXTRA_DIST = libvir.spec.in libvir.spec COPYING.LIB \
              libvir.pc.in libvir.pc TODO AUTHORS ChangeLog \
             NEWS README 
index 31c9400d6286b7d631d7a7ddc98ad3179fd8e600..a30f0678db99510fd8967cb68deb150803a4580b 100644 (file)
@@ -101,6 +101,89 @@ AC_CHECK_LIB(readline, main,
        [$VIRSH_LIBS])
 AC_SUBST(VIRSH_LIBS)
 
+dnl
+dnl check for python
+dnl
+
+PYTHON_VERSION=
+PYTHON_INCLUDES=
+PYTHON_SITE_PACKAGES=
+PYTHON_TESTS=
+pythondir=
+if test "$with_python" != "no" ; then
+    if test -x "$with_python/bin/python"
+    then
+        echo Found python in $with_python/bin/python
+        PYTHON="$with_python/bin/python"
+    else
+       if test -x "$with_python"
+       then
+           echo Found python in $with_python
+           PYTHON="$with_python"
+       else
+           if test -x "$PYTHON"
+           then
+               echo Found python in environment PYTHON=$PYTHON
+           else
+               AC_PATH_PROG(PYTHON, python python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 python2.0 python1.6 python1.5)
+           fi
+       fi
+    fi
+    if test "$PYTHON" != ""
+    then
+        PYTHON_VERSION=`$PYTHON -c "import sys; print sys.version[[0:3]]"`
+       echo Found Python version $PYTHON_VERSION
+    fi
+    if test "$PYTHON_VERSION" != ""
+    then
+       if test -r $with_python/include/python$PYTHON_VERSION/Python.h -a \
+          -d $with_python/lib/python$PYTHON_VERSION/site-packages
+       then
+           PYTHON_INCLUDES=$with_python/include/python$PYTHON_VERSION
+           PYTHON_SITE_PACKAGES=$with_python/lib/python$PYTHON_VERSION/site-packages
+       else
+           if test -r $prefix/include/python$PYTHON_VERSION/Python.h
+           then
+               PYTHON_INCLUDES='$(prefix)/include/python$(PYTHON_VERSION)'
+               PYTHON_SITE_PACKAGES='$(libdir)/python$(PYTHON_VERSION)/site-packages'
+           else
+               if test -r /usr/include/python$PYTHON_VERSION/Python.h
+               then
+                   PYTHON_INCLUDES=/usr/include/python$PYTHON_VERSION
+                   PYTHON_SITE_PACKAGES='$(libdir)/python$(PYTHON_VERSION)/site-packages'
+               else
+                   echo could not find python$PYTHON_VERSION/Python.h
+               fi
+           fi
+           if test ! -d "$PYTHON_SITE_PACKAGES"
+           then
+                   PYTHON_SITE_PACKAGES=`$PYTHON -c "from distutils import sysconfig; print sysconfig.get_python_lib()"`
+           fi
+       fi
+    fi
+    if test "$with_python" != ""
+    then
+        pythondir='$(PYTHON_SITE_PACKAGES)'
+    else
+        pythondir='$(libdir)/python${PYTHON_VERSION}/site-packages'
+    fi
+else
+    PYTHON=
+fi
+AM_CONDITIONAL(WITH_PYTHON, test "$PYTHON_INCLUDES" != "")
+if test "$PYTHON_INCLUDES" != ""
+then
+    PYTHON_SUBDIR=python
+else
+    PYTHON_SUBDIR=
+fi
+AC_SUBST(pythondir)
+AC_SUBST(PYTHON)
+AC_SUBST(PYTHON_VERSION)
+AC_SUBST(PYTHON_INCLUDES)
+AC_SUBST(PYTHON_SITE_PACKAGES)
+AC_SUBST(PYTHON_SUBDIR)
+
 # end of if with_depends
 fi
 
@@ -108,4 +191,4 @@ fi
 rm -f COPYING
 
 AC_OUTPUT(Makefile src/Makefile include/Makefile docs/Makefile \
-          libvir.pc libvir.spec include/libvir.h)
+          libvir.pc libvir.spec include/libvir.h python/Makefile)
index 686de2e90ffbbbe0dcd20c926b2543128e39a224..ef39b7db6f08419ca531b309976c7965ba2fab35 100644 (file)
@@ -7,7 +7,7 @@ Group: Development/Libraries
 Source: libvir-%{version}.tar.gz
 BuildRoot: %{_tmppath}/%{name}-%{version}-root
 URL: http://libvir.org/
-BuildRequires: xen
+BuildRequires: xen python python-devel
 Requires: xen
 
 %description
@@ -23,6 +23,17 @@ Requires: libvir = %{version}
 Includes and documantations for the C library providing an API to use
 the Xen virtualization framework
 
+%package python
+Summary: Python bindings for the libvir library
+Group: Development/Libraries
+Requires: libvir = %{version}
+Requires: %{_libdir}/python%(echo `python -c "import sys; print sys.version[0:3]"`)
+
+%description python
+The libvir-python package contains a module that permits applications
+written in the Python programming language to use the interface
+supplied by the libvir library to use the Xen virtualization framework.
+
 %prep
 %setup -q
 
@@ -36,6 +47,8 @@ rm -fr %{buildroot}
 %makeinstall
 rm -f $RPM_BUILD_ROOT%{_libdir}/*.la
 rm -f $RPM_BUILD_ROOT%{_libdir}/*.a
+rm -f $RPM_BUILD_ROOT%{_libdir}/python*/site-packages/*.la
+rm -f $RPM_BUILD_ROOT%{_libdir}/python*/site-packages/*.a
 
 %clean
 rm -fr %{buildroot}
@@ -63,6 +76,15 @@ rm -fr %{buildroot}
 %doc docs/*.html docs/html docs/*.gif
 %doc docs/libvir-api.xml
 
+%files python
+%defattr(-, root, root)
+
+%doc AUTHORS NEWS README COPYING.LIB
+%{_libdir}/python*/site-packages/libvir.py*
+%{_libdir}/python*/site-packages/libvirmod*
+%doc python/TODO
+%doc python/libvirclass.txt
+
 %changelog
 * Wed Nov  2 2005 Daniel Veillard <veillard@redhat.com> 0.0.1-1
 - created
diff --git a/python/Makefile.am b/python/Makefile.am
new file mode 100644 (file)
index 0000000..0921e32
--- /dev/null
@@ -0,0 +1,62 @@
+# Makefile for libvir python library
+
+INCLUDES = \
+        -I$(PYTHON_INCLUDES) \
+       -I$(top_srcdir)/include \
+       -I$(top_builddir)/include \
+       -I$(top_builddir)/$(subdir)
+
+DOCS_DIR = $(datadir)/doc/libvir-python-$(LIBVIR_VERSION)
+
+DOCS = ${srcdir}/TODO
+
+EXTRA_DIST =           \
+       libvir.c        \
+       types.c         \
+       generator.py    \
+       libvir_wrap.h   \
+       libvir.py       \
+       libvir-python-api.xml \
+       $(DOCS)
+
+libvirmod_la_LDFLAGS = -module -avoid-version -L$(top_builddir)/src/.libs
+
+if WITH_PYTHON
+mylibs = $(top_builddir)/src/libvir.la
+
+all-local: libvir.py
+
+python_LTLIBRARIES = libvirmod.la
+
+libvirmod_la_SOURCES = libvir.c types.c libvir-py.c
+libvirmod_la_LIBADD = $(mylibs) 
+
+
+install-data-local:
+       $(mkinstalldirs) $(DESTDIR)$(pythondir)
+       @INSTALL@ -m 0644 libvir.py $(DESTDIR)$(pythondir)
+       $(mkinstalldirs) $(DESTDIR)$(DOCS_DIR)
+       @(for doc in $(DOCS) ; \
+          do @INSTALL@ -m 0644 $$doc $(DESTDIR)$(DOCS_DIR) ; done)
+
+GENERATE = generator.py
+API_DESC = $(top_srcdir)/docs/libvir-api.xml $(srcdir)/libvir-python-api.xml
+GENERATED= libvir.py \
+           libvir-export.c \
+           libvirclass.txt \
+          libvir-py.c \
+          libvir-py.h
+
+CLEANFILES= $(GENERATED) gen_prog libvir.py
+
+$(GENERATED): gen_prog
+
+gen_prog: $(srcdir)/$(GENERATE) $(API_DESC)
+       $(PYTHON) $(srcdir)/$(GENERATE) $(srcdir)
+       touch gen_prog
+
+$(libvirmod_la_OBJECTS): $(GENERATED)
+
+else
+all: 
+endif
diff --git a/python/TODO b/python/TODO
new file mode 100644 (file)
index 0000000..e4e505a
--- /dev/null
@@ -0,0 +1,8 @@
+- Need to complete, add custom wrapper function for those
+  which could not be handled fully automatically
+- Check the names generated, iD is bad, fix the name generation routine
+- add examples, web page and python based test suite
+
+Daniel Veillard
+
+$date$
diff --git a/python/generator.py b/python/generator.py
new file mode 100755 (executable)
index 0000000..59b4267
--- /dev/null
@@ -0,0 +1,898 @@
+#!/usr/bin/python -u
+#
+# generate python wrappers from the XML API description
+#
+
+functions = {}
+enums = {} # { enumType: { enumConstant: enumValue } }
+
+import os
+import sys
+import string
+
+if __name__ == "__main__":
+    # launched as a script
+    srcPref = os.path.dirname(sys.argv[0])
+else:
+    # imported
+    srcPref = os.path.dirname(__file__)
+
+#######################################################################
+#
+#  That part if purely the API acquisition phase from the
+#  libvir API description
+#
+#######################################################################
+import os
+import xmllib
+try:
+    import sgmlop
+except ImportError:
+    sgmlop = None # accelerator not available
+
+debug = 0
+
+if sgmlop:
+    class FastParser:
+        """sgmlop based XML parser.  this is typically 15x faster
+           than SlowParser..."""
+
+        def __init__(self, target):
+
+            # setup callbacks
+            self.finish_starttag = target.start
+            self.finish_endtag = target.end
+            self.handle_data = target.data
+
+            # activate parser
+            self.parser = sgmlop.XMLParser()
+            self.parser.register(self)
+            self.feed = self.parser.feed
+            self.entity = {
+                "amp": "&", "gt": ">", "lt": "<",
+                "apos": "'", "quot": '"'
+                }
+
+        def close(self):
+            try:
+                self.parser.close()
+            finally:
+                self.parser = self.feed = None # nuke circular reference
+
+        def handle_entityref(self, entity):
+            # <string> entity
+            try:
+                self.handle_data(self.entity[entity])
+            except KeyError:
+                self.handle_data("&%s;" % entity)
+
+else:
+    FastParser = None
+
+
+class SlowParser(xmllib.XMLParser):
+    """slow but safe standard parser, based on the XML parser in
+       Python's standard library."""
+
+    def __init__(self, target):
+        self.unknown_starttag = target.start
+        self.handle_data = target.data
+        self.unknown_endtag = target.end
+        xmllib.XMLParser.__init__(self)
+
+def getparser(target = None):
+    # get the fastest available parser, and attach it to an
+    # unmarshalling object.  return both objects.
+    if target is None:
+        target = docParser()
+    if FastParser:
+        return FastParser(target), target
+    return SlowParser(target), target
+
+class docParser:
+    def __init__(self):
+        self._methodname = None
+        self._data = []
+        self.in_function = 0
+
+    def close(self):
+        if debug:
+            print "close"
+
+    def getmethodname(self):
+        return self._methodname
+
+    def data(self, text):
+        if debug:
+            print "data %s" % text
+        self._data.append(text)
+
+    def start(self, tag, attrs):
+        if debug:
+            print "start %s, %s" % (tag, attrs)
+        if tag == 'function':
+            self._data = []
+            self.in_function = 1
+            self.function = None
+            self.function_cond = None
+            self.function_args = []
+            self.function_descr = None
+            self.function_return = None
+            self.function_file = None
+            if attrs.has_key('name'):
+                self.function = attrs['name']
+            if attrs.has_key('file'):
+                self.function_file = attrs['file']
+        elif tag == 'cond':
+            self._data = []
+        elif tag == 'info':
+            self._data = []
+        elif tag == 'arg':
+            if self.in_function == 1:
+                self.function_arg_name = None
+                self.function_arg_type = None
+                self.function_arg_info = None
+                if attrs.has_key('name'):
+                    self.function_arg_name = attrs['name']
+                if attrs.has_key('type'):
+                    self.function_arg_type = attrs['type']
+                if attrs.has_key('info'):
+                    self.function_arg_info = attrs['info']
+        elif tag == 'return':
+            if self.in_function == 1:
+                self.function_return_type = None
+                self.function_return_info = None
+                self.function_return_field = None
+                if attrs.has_key('type'):
+                    self.function_return_type = attrs['type']
+                if attrs.has_key('info'):
+                    self.function_return_info = attrs['info']
+                if attrs.has_key('field'):
+                    self.function_return_field = attrs['field']
+        elif tag == 'enum':
+            enum(attrs['type'],attrs['name'],attrs['value'])
+
+    def end(self, tag):
+        if debug:
+            print "end %s" % tag
+        if tag == 'function':
+            if self.function != None:
+                function(self.function, self.function_descr,
+                         self.function_return, self.function_args,
+                         self.function_file, self.function_cond)
+                self.in_function = 0
+        elif tag == 'arg':
+            if self.in_function == 1:
+                self.function_args.append([self.function_arg_name,
+                                           self.function_arg_type,
+                                           self.function_arg_info])
+        elif tag == 'return':
+            if self.in_function == 1:
+                self.function_return = [self.function_return_type,
+                                        self.function_return_info,
+                                        self.function_return_field]
+        elif tag == 'info':
+            str = ''
+            for c in self._data:
+                str = str + c
+            if self.in_function == 1:
+                self.function_descr = str
+        elif tag == 'cond':
+            str = ''
+            for c in self._data:
+                str = str + c
+            if self.in_function == 1:
+                self.function_cond = str
+                
+                
+def function(name, desc, ret, args, file, cond):
+    functions[name] = (desc, ret, args, file, cond)
+
+def enum(type, name, value):
+    if not enums.has_key(type):
+        enums[type] = {}
+    enums[type][name] = value
+
+#######################################################################
+#
+#  Some filtering rukes to drop functions/types which should not
+#  be exposed as-is on the Python interface
+#
+#######################################################################
+
+skipped_modules = {
+}
+
+skipped_types = {
+    'int *': "usually a return type",
+}
+
+#######################################################################
+#
+#  Table of remapping to/from the python type or class to the C
+#  counterpart.
+#
+#######################################################################
+
+py_types = {
+    'void': (None, None, None, None),
+    'int':  ('i', None, "int", "int"),
+    'long':  ('i', None, "int", "int"),
+    'double':  ('d', None, "double", "double"),
+    'unsigned int':  ('i', None, "int", "int"),
+    'unsigned long':  ('i', None, "int", "int"),
+    'unsigned char *':  ('z', None, "charPtr", "char *"),
+    'char *':  ('z', None, "charPtr", "char *"),
+    'const char *':  ('z', None, "charPtrConst", "const char *"),
+    'virDomainPtr':  ('O', "virDomain", "virDomainPtr", "virDomainPtr"),
+    'const virDomainPtr':  ('O', "virDomain", "virDomainPtr", "virDomainPtr"),
+    'virDomain *':  ('O', "virDomain", "virDomainPtr", "virDomainPtr"),
+    'const virDomain *':  ('O', "virDomain", "virDomainPtr", "virDomainPtr"),
+    'virConnectPtr':  ('O', "virConnect", "virConnectPtr", "virConnectPtr"),
+    'const virConnectPtr':  ('O', "virConnect", "virConnectPtr", "virConnectPtr"),
+    'virConnect *':  ('O', "virConnect", "virConnectPtr", "virConnectPtr"),
+    'const virConnect *':  ('O', "virConnect", "virConnectPtr", "virConnectPtr"),
+}
+
+py_return_types = {
+}
+
+unknown_types = {}
+
+foreign_encoding_args = (
+)
+
+#######################################################################
+#
+#  This part writes the C <-> Python stubs libxml2-py.[ch] and
+#  the table libxml2-export.c to add when registrering the Python module
+#
+#######################################################################
+
+# Class methods which are written by hand in libvir.c but the Python-level
+# code is still automatically generated (so they are not in skip_function()).
+skip_impl = (
+    'xmlSaveFileTo',
+    'xmlSaveFormatFileTo',
+)
+
+def skip_function(name):
+    if name == "virConnectClose":
+        return 1
+    if name == "virDomainFree":
+        return 1
+
+    return 0
+
+def print_function_wrapper(name, output, export, include):
+    global py_types
+    global unknown_types
+    global functions
+    global skipped_modules
+
+    try:
+        (desc, ret, args, file, cond) = functions[name]
+    except:
+        print "failed to get function %s infos"
+        return
+
+    if skipped_modules.has_key(file):
+        return 0
+    if skip_function(name) == 1:
+        return 0
+    if name in skip_impl:
+       # Don't delete the function entry in the caller.
+       return 1
+
+    c_call = "";
+    format=""
+    format_args=""
+    c_args=""
+    c_return=""
+    c_convert=""
+    num_bufs=0
+    for arg in args:
+        # This should be correct
+        if arg[1][0:6] == "const ":
+            arg[1] = arg[1][6:]
+        c_args = c_args + "    %s %s;\n" % (arg[1], arg[0])
+        if py_types.has_key(arg[1]):
+            (f, t, n, c) = py_types[arg[1]]
+           if (f == 'z') and (name in foreign_encoding_args) and (num_bufs == 0):
+               f = 't#'
+            if f != None:
+                format = format + f
+            if t != None:
+                format_args = format_args + ", &pyobj_%s" % (arg[0])
+                c_args = c_args + "    PyObject *pyobj_%s;\n" % (arg[0])
+                c_convert = c_convert + \
+                   "    %s = (%s) Py%s_Get(pyobj_%s);\n" % (arg[0],
+                   arg[1], t, arg[0]);
+            else:
+                format_args = format_args + ", &%s" % (arg[0])
+           if f == 't#':
+               format_args = format_args + ", &py_buffsize%d" % num_bufs
+               c_args = c_args + "    int py_buffsize%d;\n" % num_bufs
+               num_bufs = num_bufs + 1
+            if c_call != "":
+                c_call = c_call + ", ";
+            c_call = c_call + "%s" % (arg[0])
+        else:
+            if skipped_types.has_key(arg[1]):
+                return 0
+            if unknown_types.has_key(arg[1]):
+                lst = unknown_types[arg[1]]
+                lst.append(name)
+            else:
+                unknown_types[arg[1]] = [name]
+            return -1
+    if format != "":
+        format = format + ":%s" % (name)
+
+    if ret[0] == 'void':
+        if file == "python_accessor":
+           if args[1][1] == "char *":
+               c_call = "\n    if (%s->%s != NULL) free(%s->%s);\n" % (
+                                args[0][0], args[1][0], args[0][0], args[1][0])
+               c_call = c_call + "    %s->%s = (%s)strdup((const xmlChar *)%s);\n" % (args[0][0],
+                                args[1][0], args[1][1], args[1][0])
+           else:
+               c_call = "\n    %s->%s = %s;\n" % (args[0][0], args[1][0],
+                                                  args[1][0])
+        else:
+            c_call = "\n    %s(%s);\n" % (name, c_call);
+        ret_convert = "    Py_INCREF(Py_None);\n    return(Py_None);\n"
+    elif py_types.has_key(ret[0]):
+        (f, t, n, c) = py_types[ret[0]]
+        c_return = "    %s c_retval;\n" % (ret[0])
+        if file == "python_accessor" and ret[2] != None:
+            c_call = "\n    c_retval = %s->%s;\n" % (args[0][0], ret[2])
+        else:
+            c_call = "\n    c_retval = %s(%s);\n" % (name, c_call);
+        ret_convert = "    py_retval = libvir_%sWrap((%s) c_retval);\n" % (n,c)
+        ret_convert = ret_convert + "    return(py_retval);\n"
+    elif py_return_types.has_key(ret[0]):
+        (f, t, n, c) = py_return_types[ret[0]]
+        c_return = "    %s c_retval;\n" % (ret[0])
+        c_call = "\n    c_retval = %s(%s);\n" % (name, c_call);
+        ret_convert = "    py_retval = libvir_%sWrap((%s) c_retval);\n" % (n,c)
+        ret_convert = ret_convert + "    return(py_retval);\n"
+    else:
+        if skipped_types.has_key(ret[0]):
+            return 0
+        if unknown_types.has_key(ret[0]):
+            lst = unknown_types[ret[0]]
+            lst.append(name)
+        else:
+            unknown_types[ret[0]] = [name]
+        return -1
+
+    if cond != None and cond != "":
+        include.write("#if %s\n" % cond)
+        export.write("#if %s\n" % cond)
+        output.write("#if %s\n" % cond)
+
+    include.write("PyObject * ")
+    include.write("libvir_%s(PyObject *self, PyObject *args);\n" % (name));
+
+    export.write("    { (char *)\"%s\", libvir_%s, METH_VARARGS, NULL },\n" %
+                 (name, name))
+
+    if file == "python":
+        # Those have been manually generated
+       if cond != None and cond != "":
+           include.write("#endif\n");
+           export.write("#endif\n");
+           output.write("#endif\n");
+        return 1
+    if file == "python_accessor" and ret[0] != "void" and ret[2] is None:
+        # Those have been manually generated
+       if cond != None and cond != "":
+           include.write("#endif\n");
+           export.write("#endif\n");
+           output.write("#endif\n");
+        return 1
+
+    output.write("PyObject *\n")
+    output.write("libvir_%s(PyObject *self ATTRIBUTE_UNUSED," % (name))
+    output.write(" PyObject *args")
+    if format == "":
+       output.write(" ATTRIBUTE_UNUSED")
+    output.write(") {\n")
+    if ret[0] != 'void':
+        output.write("    PyObject *py_retval;\n")
+    if c_return != "":
+        output.write(c_return)
+    if c_args != "":
+        output.write(c_args)
+    if format != "":
+        output.write("\n    if (!PyArg_ParseTuple(args, (char *)\"%s\"%s))\n" %
+                     (format, format_args))
+        output.write("        return(NULL);\n")
+    if c_convert != "":
+        output.write(c_convert)
+                                                              
+    output.write(c_call)
+    output.write(ret_convert)
+    output.write("}\n\n")
+    if cond != None and cond != "":
+        include.write("#endif /* %s */\n" % cond)
+        export.write("#endif /* %s */\n" % cond)
+        output.write("#endif /* %s */\n" % cond)
+    return 1
+
+def buildStubs():
+    global py_types
+    global py_return_types
+    global unknown_types
+
+    try:
+       f = open(os.path.join(srcPref,"libvir-api.xml"))
+       data = f.read()
+       (parser, target)  = getparser()
+       parser.feed(data)
+       parser.close()
+    except IOError, msg:
+       try:
+           f = open(os.path.join(srcPref,"..","docs","libvir-api.xml"))
+           data = f.read()
+           (parser, target)  = getparser()
+           parser.feed(data)
+           parser.close()
+       except IOError, msg:
+           print file, ":", msg
+           sys.exit(1)
+
+    n = len(functions.keys())
+    print "Found %d functions in libvir-api.xml" % (n)
+
+    py_types['pythonObject'] = ('O', "pythonObject", "pythonObject", "pythonObject")
+    try:
+       f = open(os.path.join(srcPref,"libvir-python-api.xml"))
+       data = f.read()
+       (parser, target)  = getparser()
+       parser.feed(data)
+       parser.close()
+    except IOError, msg:
+       print file, ":", msg
+
+
+    print "Found %d functions in libvir-python-api.xml" % (
+         len(functions.keys()) - n)
+    nb_wrap = 0
+    failed = 0
+    skipped = 0
+
+    include = open("libvir-py.h", "w")
+    include.write("/* Generated */\n\n")
+    export = open("libvir-export.c", "w")
+    export.write("/* Generated */\n\n")
+    wrapper = open("libvir-py.c", "w")
+    wrapper.write("/* Generated */\n\n")
+    wrapper.write("#include <Python.h>\n")
+    wrapper.write("#include <libvir.h>\n")
+    wrapper.write("#include \"libvir_wrap.h\"\n")
+    wrapper.write("#include \"libvir-py.h\"\n\n")
+    for function in functions.keys():
+       ret = print_function_wrapper(function, wrapper, export, include)
+       if ret < 0:
+           failed = failed + 1
+           del functions[function]
+       if ret == 0:
+           skipped = skipped + 1
+           del functions[function]
+       if ret == 1:
+           nb_wrap = nb_wrap + 1
+    include.close()
+    export.close()
+    wrapper.close()
+
+    print "Generated %d wrapper functions, %d failed, %d skipped\n" % (nb_wrap,
+                                                             failed, skipped);
+    print "Missing type converters: "
+    for type in unknown_types.keys():
+       print "%s:%d " % (type, len(unknown_types[type])),
+    print
+
+#######################################################################
+#
+#  This part writes part of the Python front-end classes based on
+#  mapping rules between types and classes and also based on function
+#  renaming to get consistent function names at the Python level
+#
+#######################################################################
+
+#
+# The type automatically remapped to generated classes
+#
+classes_type = {
+    "virDomainPtr": ("._o", "virDomain(_obj=%s)", "virDomain"),
+    "virDomain *": ("._o", "virDomain(_obj=%s)", "virDomain"),
+    "virConnectPtr": ("._o", "virConnect(_obj=%s)", "virConnect"),
+    "virConnect *": ("._o", "virConnect(_obj=%s)", "virConnect"),
+}
+
+converter_type = {
+}
+
+primary_classes = ["virDomain", "virConnect"]
+
+classes_ancestor = {
+}
+classes_destructors = {
+    "virDomain": "virDomainFree",
+    "virConnect": "virConnectClose",
+}
+
+functions_noexcept = {
+}
+
+reference_keepers = {
+}
+
+function_classes = {}
+
+function_classes["None"] = []
+
+def nameFixup(name, classe, type, file):
+    listname = classe + "List"
+    ll = len(listname)
+    l = len(classe)
+    if name[0:l] == listname:
+        func = name[l:]
+        func = string.lower(func[0:1]) + func[1:]
+    elif name[0:12] == "virDomainGet":
+        func = name[12:]
+        func = string.lower(func[0:1]) + func[1:]
+    elif name[0:9] == "virDomain":
+        func = name[9:]
+        func = string.lower(func[0:1]) + func[1:]
+    elif name[0:10] == "virConnect":
+        func = name[10:]
+        func = string.lower(func[0:1]) + func[1:]
+    elif name[0:3] == "xml":
+        func = name[3:]
+        func = string.lower(func[0:1]) + func[1:]
+    else:
+        func = name
+    return func
+
+
+def functionCompare(info1, info2):
+    (index1, func1, name1, ret1, args1, file1) = info1
+    (index2, func2, name2, ret2, args2, file2) = info2
+    if file1 == file2:
+        if func1 < func2:
+            return -1
+        if func1 > func2:
+            return 1
+    if file1 == "python_accessor":
+        return -1
+    if file2 == "python_accessor":
+        return 1
+    if file1 < file2:
+        return -1
+    if file1 > file2:
+        return 1
+    return 0
+
+def writeDoc(name, args, indent, output):
+     if functions[name][0] is None or functions[name][0] == "":
+         return
+     val = functions[name][0]
+     val = string.replace(val, "NULL", "None");
+     output.write(indent)
+     output.write('"""')
+     while len(val) > 60:
+         str = val[0:60]
+         i = string.rfind(str, " ");
+         if i < 0:
+             i = 60
+         str = val[0:i]
+         val = val[i:]
+         output.write(str)
+         output.write('\n  ');
+         output.write(indent)
+     output.write(val);
+     output.write(' """\n')
+
+def buildWrappers():
+    global ctypes
+    global py_types
+    global py_return_types
+    global unknown_types
+    global functions
+    global function_classes
+    global classes_type
+    global classes_list
+    global converter_type
+    global primary_classes
+    global converter_type
+    global classes_ancestor
+    global converter_type
+    global primary_classes
+    global classes_ancestor
+    global classes_destructors
+    global functions_noexcept
+
+    for type in classes_type.keys():
+       function_classes[classes_type[type][2]] = []
+
+    #
+    # Build the list of C types to look for ordered to start
+    # with primary classes
+    #
+    ctypes = []
+    classes_list = []
+    ctypes_processed = {}
+    classes_processed = {}
+    for classe in primary_classes:
+       classes_list.append(classe)
+       classes_processed[classe] = ()
+       for type in classes_type.keys():
+           tinfo = classes_type[type]
+           if tinfo[2] == classe:
+               ctypes.append(type)
+               ctypes_processed[type] = ()
+    for type in classes_type.keys():
+       if ctypes_processed.has_key(type):
+           continue
+       tinfo = classes_type[type]
+       if not classes_processed.has_key(tinfo[2]):
+           classes_list.append(tinfo[2])
+           classes_processed[tinfo[2]] = ()
+           
+       ctypes.append(type)
+       ctypes_processed[type] = ()
+
+    for name in functions.keys():
+       found = 0;
+       (desc, ret, args, file, cond) = functions[name]
+       for type in ctypes:
+           classe = classes_type[type][2]
+
+           if name[0:3] == "vir" and len(args) >= 1 and args[0][1] == type:
+               found = 1
+               func = nameFixup(name, classe, type, file)
+               info = (0, func, name, ret, args, file)
+               function_classes[classe].append(info)
+           elif name[0:3] == "vir" and len(args) >= 2 and args[1][1] == type \
+               and file != "python_accessor":
+               found = 1
+               func = nameFixup(name, classe, type, file)
+               info = (1, func, name, ret, args, file)
+               function_classes[classe].append(info)
+       if found == 1:
+           continue
+       func = nameFixup(name, "None", file, file)
+       info = (0, func, name, ret, args, file)
+       function_classes['None'].append(info)
+   
+    classes = open("libvir.py", "w")
+    classes.write("""#!/usr/bin/python -u
+#
+# Those are the autogenerated Python bindings for libvir.
+# Check python/generator.py in the source distribution of libvir
+# to find out more about the generation process
+#
+""")
+
+    classes.write("import libvirmod\n")
+    classes.write("import types\n\n")
+
+    txt = open("libvirclass.txt", "w")
+    txt.write("          Generated Classes for libvir-python\n\n")
+
+    txt.write("#\n# Global functions of the module\n#\n\n")
+    if function_classes.has_key("None"):
+       flist = function_classes["None"]
+       flist.sort(functionCompare)
+       oldfile = ""
+       for info in flist:
+           (index, func, name, ret, args, file) = info
+           if file != oldfile:
+               classes.write("#\n# Functions from module %s\n#\n\n" % file)
+               txt.write("\n# functions from module %s\n" % file)
+               oldfile = file
+           classes.write("def %s(" % func)
+           txt.write("%s()\n" % func);
+           n = 0
+           for arg in args:
+               if n != 0:
+                   classes.write(", ")
+               classes.write("%s" % arg[0])
+               n = n + 1
+           classes.write("):\n")
+           writeDoc(name, args, '    ', classes);
+
+           for arg in args:
+               if classes_type.has_key(arg[1]):
+                   classes.write("    if %s is None: %s__o = None\n" %
+                                 (arg[0], arg[0]))
+                   classes.write("    else: %s__o = %s%s\n" %
+                                 (arg[0], arg[0], classes_type[arg[1]][0]))
+           if ret[0] != "void":
+               classes.write("    ret = ");
+           else:
+               classes.write("    ");
+           classes.write("libvirmod.%s(" % name)
+           n = 0
+           for arg in args:
+               if n != 0:
+                   classes.write(", ");
+               classes.write("%s" % arg[0])
+               if classes_type.has_key(arg[1]):
+                   classes.write("__o");
+               n = n + 1
+           classes.write(")\n");
+           if ret[0] != "void":
+               if classes_type.has_key(ret[0]):
+                   #
+                   # Raise an exception
+                   #
+                   if functions_noexcept.has_key(name):
+                       classes.write("    if ret is None:return None\n");
+                   classes.write("    return ");
+                   classes.write(classes_type[ret[0]][1] % ("ret"));
+                   classes.write("\n");
+               else:
+                   classes.write("    return ret\n");
+           classes.write("\n");
+
+    txt.write("\n\n#\n# Set of classes of the module\n#\n\n")
+    for classname in classes_list:
+       if classname == "None":
+           pass
+       else:
+           if classes_ancestor.has_key(classname):
+               txt.write("\n\nClass %s(%s)\n" % (classname,
+                         classes_ancestor[classname]))
+               classes.write("class %s(%s):\n" % (classname,
+                             classes_ancestor[classname]))
+               classes.write("    def __init__(self, _obj=None):\n")
+               if reference_keepers.has_key(classname):
+                   rlist = reference_keepers[classname]
+                   for ref in rlist:
+                       classes.write("        self.%s = None\n" % ref[1])
+               classes.write("        self._o = _obj\n")
+               classes.write("        %s.__init__(self, _obj=_obj)\n\n" % (
+                             classes_ancestor[classname]))
+           else:
+               txt.write("Class %s()\n" % (classname))
+               classes.write("class %s:\n" % (classname))
+               classes.write("    def __init__(self, _obj=None):\n")
+               if reference_keepers.has_key(classname):
+                   list = reference_keepers[classname]
+                   for ref in list:
+                       classes.write("        self.%s = None\n" % ref[1])
+               classes.write("        if _obj != None:self._o = _obj;return\n")
+               classes.write("        self._o = None\n\n");
+           destruct=None
+           if classes_destructors.has_key(classname):
+               classes.write("    def __del__(self):\n")
+               classes.write("        if self._o != None:\n")
+               classes.write("            libvirmod.%s(self._o)\n" %
+                             classes_destructors[classname]);
+               classes.write("        self._o = None\n\n");
+               destruct=classes_destructors[classname]
+           flist = function_classes[classname]
+           flist.sort(functionCompare)
+           oldfile = ""
+           for info in flist:
+               (index, func, name, ret, args, file) = info
+               #
+               # Do not provide as method the destructors for the class
+               # to avoid double free
+               #
+               if name == destruct:
+                   continue;
+               if file != oldfile:
+                   if file == "python_accessor":
+                       classes.write("    # accessors for %s\n" % (classname))
+                       txt.write("    # accessors\n")
+                   else:
+                       classes.write("    #\n")
+                       classes.write("    # %s functions from module %s\n" % (
+                                     classname, file))
+                       txt.write("\n    # functions from module %s\n" % file)
+                       classes.write("    #\n\n")
+               oldfile = file
+               classes.write("    def %s(self" % func)
+               txt.write("    %s()\n" % func);
+               n = 0
+               for arg in args:
+                   if n != index:
+                       classes.write(", %s" % arg[0])
+                   n = n + 1
+               classes.write("):\n")
+               writeDoc(name, args, '        ', classes);
+               n = 0
+               for arg in args:
+                   if classes_type.has_key(arg[1]):
+                       if n != index:
+                           classes.write("        if %s is None: %s__o = None\n" %
+                                         (arg[0], arg[0]))
+                           classes.write("        else: %s__o = %s%s\n" %
+                                         (arg[0], arg[0], classes_type[arg[1]][0]))
+                   n = n + 1
+               if ret[0] != "void":
+                   classes.write("        ret = ");
+               else:
+                   classes.write("        ");
+               classes.write("libvirmod.%s(" % name)
+               n = 0
+               for arg in args:
+                   if n != 0:
+                       classes.write(", ");
+                   if n != index:
+                       classes.write("%s" % arg[0])
+                       if classes_type.has_key(arg[1]):
+                           classes.write("__o");
+                   else:
+                       classes.write("self");
+                       if classes_type.has_key(arg[1]):
+                           classes.write(classes_type[arg[1]][0])
+                   n = n + 1
+               classes.write(")\n");
+               if ret[0] != "void":
+                   if classes_type.has_key(ret[0]):
+                       #
+                       # Raise an exception
+                       #
+                       if functions_noexcept.has_key(name):
+                           classes.write(
+                               "        if ret is None:return None\n");
+
+                       #
+                       # generate the returned class wrapper for the object
+                       #
+                       classes.write("        __tmp = ");
+                       classes.write(classes_type[ret[0]][1] % ("ret"));
+                       classes.write("\n");
+
+                        #
+                       # Sometime one need to keep references of the source
+                       # class in the returned class object.
+                       # See reference_keepers for the list
+                       #
+                       tclass = classes_type[ret[0]][2]
+                       if reference_keepers.has_key(tclass):
+                           list = reference_keepers[tclass]
+                           for pref in list:
+                               if pref[0] == classname:
+                                   classes.write("        __tmp.%s = self\n" %
+                                                 pref[1])
+                       #
+                       # return the class
+                       #
+                       classes.write("        return __tmp\n");
+                   elif converter_type.has_key(ret[0]):
+                       #
+                       # Raise an exception
+                       #
+                       if functions_noexcept.has_key(name):
+                           classes.write(
+                               "        if ret is None:return None");
+                       classes.write("        return ");
+                       classes.write(converter_type[ret[0]] % ("ret"));
+                       classes.write("\n");
+                   else:
+                       classes.write("        return ret\n");
+               classes.write("\n");
+
+    #
+    # Generate enum constants
+    #
+    for type,enum in enums.items():
+        classes.write("# %s\n" % type)
+        items = enum.items()
+        items.sort(lambda i1,i2: cmp(long(i1[1]),long(i2[1])))
+        for name,value in items:
+            classes.write("%s = %s\n" % (name,value))
+        classes.write("\n");
+
+    txt.close()
+    classes.close()
+
+buildStubs()
+buildWrappers()
diff --git a/python/libvir-python-api.xml b/python/libvir-python-api.xml
new file mode 100644 (file)
index 0000000..45076f5
--- /dev/null
@@ -0,0 +1,3 @@
+<?xml version="1.0"?>
+<api name='libvir-python'>
+</api>
diff --git a/python/libvir.c b/python/libvir.c
new file mode 100644 (file)
index 0000000..7dc5100
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * libvir.c: this modules implements the main part of the glue of the
+ *           libvir library and the Python interpreter. It provides the
+ *           entry points where an automatically generated stub is
+ *           unpractical
+ *
+ * Copyright (C) 2005 Red Hat, Inc.
+ *
+ * Daniel Veillard <veillard@redhat.com>
+ */
+
+#include <Python.h>
+#include <libvir.h>
+#include "libvir_wrap.h"
+#include "libvir-py.h"
+
+void initlibvirmod(void);
+
+/************************************************************************
+ *                                                                     *
+ *                     The registration stuff                          *
+ *                                                                     *
+ ************************************************************************/
+static PyMethodDef libvirMethods[] = {
+#include "libvir-export.c"
+    {NULL, NULL, 0, NULL}
+};
+
+void
+initlibvirmod(void)
+{
+    static int initialized = 0;
+
+    if (initialized != 0)
+        return;
+
+    /* intialize the python extension module */
+    Py_InitModule((char *) "libvirmod", libvirMethods);
+
+    initialized = 1;
+}
diff --git a/python/libvir_wrap.h b/python/libvir_wrap.h
new file mode 100644 (file)
index 0000000..31771d7
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * libvir_wrap.h: type wrappers for libvir python bindings
+ *
+ * Copyright (C) 2005 Red Hat, Inc.
+ *
+ * Daniel Veillard <veillard@redhat.com>
+ */
+
+#include <Python.h>
+#include <libvir.h>
+
+#ifdef __GNUC__
+#ifdef ATTRIBUTE_UNUSED
+#undef ATTRIBUTE_UNUSED
+#endif
+#ifndef ATTRIBUTE_UNUSED
+#define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
+#endif /* ATTRIBUTE_UNUSED */
+#else
+#define ATTRIBUTE_UNUSED
+#endif
+
+#define PyvirConnect_Get(v) (((v) == Py_None) ? NULL : \
+       (((PyvirConnect_Object *)(v))->obj))
+
+typedef struct {
+    PyObject_HEAD
+    virConnectPtr obj;
+} PyvirConnect_Object;
+
+
+#define PyvirDomain_Get(v) (((v) == Py_None) ? NULL : \
+       (((PyvirDomain_Object *)(v))->obj))
+
+typedef struct {
+    PyObject_HEAD
+    virDomainPtr obj;
+} PyvirDomain_Object;
+
+
+PyObject * libvir_intWrap(int val);
+PyObject * libvir_longWrap(long val);
+PyObject * libvir_charPtrWrap(char *str);
+PyObject * libvir_constcharPtrWrap(const char *str);
+PyObject * libvir_charPtrConstWrap(const char *str);
+PyObject * libvir_virConnectPtrWrap(virConnectPtr node);
+PyObject * libvir_virDomainPtrWrap(virDomainPtr node);
+
diff --git a/python/types.c b/python/types.c
new file mode 100644 (file)
index 0000000..1f71198
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * types.c: converter functions between the internal representation
+ *          and the Python objects
+ *
+ * Copyright (C) 2005 Red Hat, Inc.
+ *
+ * Daniel Veillard <veillard@redhat.com>
+ */
+
+#include "libvir_wrap.h"
+
+PyObject *
+libvir_intWrap(int val)
+{
+    PyObject *ret;
+
+#ifdef DEBUG
+    printf("libvir_intWrap: val = %d\n", val);
+#endif
+    ret = PyInt_FromLong((long) val);
+    return (ret);
+}
+
+PyObject *
+libvir_longWrap(long val)
+{
+    PyObject *ret;
+
+#ifdef DEBUG
+    printf("libvir_longWrap: val = %ld\n", val);
+#endif
+    ret = PyInt_FromLong(val);
+    return (ret);
+}
+
+PyObject *
+libvir_charPtrWrap(char *str)
+{
+    PyObject *ret;
+
+#ifdef DEBUG
+    printf("libvir_xmlcharPtrWrap: str = %s\n", str);
+#endif
+    if (str == NULL) {
+        Py_INCREF(Py_None);
+        return (Py_None);
+    }
+    ret = PyString_FromString(str);
+    free(str);
+    return (ret);
+}
+
+PyObject *
+libvir_constcharPtrWrap(const char *str)
+{
+    PyObject *ret;
+
+#ifdef DEBUG
+    printf("libvir_xmlcharPtrWrap: str = %s\n", str);
+#endif
+    if (str == NULL) {
+        Py_INCREF(Py_None);
+        return (Py_None);
+    }
+    ret = PyString_FromString(str);
+    return (ret);
+}
+
+PyObject *
+libvir_charPtrConstWrap(const char *str)
+{
+    PyObject *ret;
+
+#ifdef DEBUG
+    printf("libvir_xmlcharPtrWrap: str = %s\n", str);
+#endif
+    if (str == NULL) {
+        Py_INCREF(Py_None);
+        return (Py_None);
+    }
+    ret = PyString_FromString(str);
+    return (ret);
+}
+
+PyObject *
+libvir_virDomainPtrWrap(virDomainPtr node)
+{
+    PyObject *ret;
+
+#ifdef DEBUG
+    printf("libvir_virDomainPtrWrap: node = %p\n", node);
+#endif
+    if (node == NULL) {
+        Py_INCREF(Py_None);
+        return (Py_None);
+    }
+    ret =
+        PyCObject_FromVoidPtrAndDesc((void *) node, (char *) "virDomainPtr",
+                                     NULL);
+    return (ret);
+}
+
+PyObject *
+libvir_virConnectPtrWrap(virConnectPtr node)
+{
+    PyObject *ret;
+
+#ifdef DEBUG
+    printf("libvir_virConnectPtrWrap: node = %p\n", node);
+#endif
+    if (node == NULL) {
+        Py_INCREF(Py_None);
+        return (Py_None);
+    }
+    ret =
+        PyCObject_FromVoidPtrAndDesc((void *) node, (char *) "virConnectPtr",
+                                     NULL);
+    return (ret);
+}
index d6eb42187da740a7a2d0ef0c3f21d5d89de13f69..fa1534f47e82b740ae92221ce8b1f036ccbd7942 100644 (file)
@@ -3,7 +3,7 @@
  * Description: This module implements the hash table support used in 
  *             various places in the library.
  *
- * Copy: See Copyright for the status of this software.
+ * Copy: Copyright (C) 2005 Red Hat, Inc.
  *
  * Author: Bjorn Reese <bjorn.reese@systematic.dk>
  */