[libxslt] Initial support for Python 3



commit a2db8da1ac30d744eaa38e574bad9841af1d9b5d
Author: Suleyman Poyraz <zaryob dev gmail com>
Date:   Sun Jun 21 15:27:20 2020 +0300

    Initial support for Python 3
    
    Squashed merge of pull request !19.

 configure.ac               | 107 ++++++++++++++--------
 python/generator.py        | 217 +++++++++++++++++++++++++--------------------
 python/libxml_wrap.h       |  10 +++
 python/libxslt.c           |  93 ++++++++++++++++---
 python/tests/basic.py      |   8 +-
 python/tests/exslt.py      |  10 ++-
 python/tests/extelem.py    |  26 ++++--
 python/tests/extfunc.py    |  12 +--
 python/tests/pyxsltproc.py |  94 ++++++++++----------
 python/types.c             | 202 ++++++++++++++++++++++++++++++++---------
 10 files changed, 519 insertions(+), 260 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index d7142ff2..a3dd27bb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -204,7 +204,7 @@ dnl
 if test "${NEED_TRIO}" = "1" ; then
     echo Reusing trio library for string functions
     WITH_TRIO=1
-else    
+else
     WITH_TRIO=0
 fi
 AC_SUBST(WITH_TRIO)
@@ -230,76 +230,107 @@ dnl
 PYTHON_VERSION=
 PYTHON_INCLUDES=
 PYTHON_SITE_PACKAGES=
+PYTHON_TESTS=
 pythondir=
-AC_ARG_WITH(python, [  --with-python[=DIR]    Build Python bindings if found])
+AC_ARG_WITH(python,
+[  --with-python[[=DIR]]     build Python bindings if found])
+AC_ARG_WITH(python_install_dir,
+[  --with-python-install-dir=DIR
+                          install Python bindings in DIR])
 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"
+        if test -x "$with_python/python.exe"
+        then
+            echo Found python in $with_python/python.exe
+            PYTHON="$with_python/python.exe"
+        else
+            if test -x "$with_python"
             then
-                echo Found python in environment PYTHON=$PYTHON
-                with_python=`$PYTHON -c "import sys; print sys.exec_prefix"`
-           else
-               AC_PATH_PROG(PYTHON, python python2.4 python2.3 python2.2 python2.1 python2.0 python1.6 
python1.5)
+                echo Found python in $with_python
+                PYTHON="$with_python"
+            else
+                if test -x "$PYTHON"
+                then
+                    echo Found python in environment PYTHON=$PYTHON
+                    with_python=`$PYTHON -c "import sys; print(sys.exec_prefix)"`
+                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
     fi
     if test "$PYTHON" != ""
     then
-        echo "PYTHON is pointing at $PYTHON"
-        PYTHON_VERSION=`$PYTHON -c "import sys; print sys.version[[0:3]]"`
+        PYTHON_VERSION=`$PYTHON -c "from distutils import sysconfig; print(sysconfig.get_python_version())"`
+       PYTHON_INCLUDES=`$PYTHON -c "from distutils import sysconfig; print(sysconfig.get_python_inc())"`
+# does not work as it produce a /usr/lib/python path instead of/usr/lib64/python
+#
+#      PYTHON_SITE_PACKAGES=`$PYTHON -c "from distutils import sysconfig; print(sysconfig.get_python_lib())"`
        echo Found Python version $PYTHON_VERSION
-       LIBXML2_PYTHON=`$PYTHON -c "try : import libxml2 ; print 1
-except: print 0"`
+  LIBXML2_PYTHON=`$PYTHON -c "import sys
+try:
+    import libxml2
+    sys.stdout.write('1')
+except:
+    sys.stdout.write('0')
+"`
        if test "$LIBXML2_PYTHON" = "1"
        then
            echo Found libxml2-python module
        else
            echo Warning: Missing libxml2-python
-       fi
+  fi
     fi
-    if test "$PYTHON_VERSION" != ""
+    if test "$PYTHON_VERSION" != "" -a "$PYTHON_INCLUDES" = ""
     then
-       if test -r $with_python/include/python$PYTHON_VERSION/Python.h -a \
-          -d $with_python/lib/python$PYTHON_VERSION/site-packages
+       if test -r $with_python/include/python$PYTHON_VERSION/Python.h
        then
            PYTHON_INCLUDES=$with_python/include/python$PYTHON_VERSION
-           PYTHON_SITE_PACKAGES=$libdir/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
+                   if test -r $with_python/include/Python.h
+                   then
+                       PYTHON_INCLUDES=$with_python/include
+                   else
+                       echo could not find python$PYTHON_VERSION/Python.h or $with_python/include/Python.h
+                   fi
                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
-        PYTHON_LIBS=`python$PYTHON_VERSION-config --libs`
     fi
-    if test "$with_python" != ""
+    if test "$with_python_install_dir" != ""
     then
-        pythondir=$PYTHON_SITE_PACKAGES
-    else
-        pythondir=$libdir/python$PYTHON_VERSION/site-packages
+       PYTHON_SITE_PACKAGES="$with_python_install_dir"
     fi
+    if test "$PYTHON_VERSION" != "" -a "$PYTHON_SITE_PACKAGES" = ""
+    then
+       if test -d $libdir/python$PYTHON_VERSION/site-packages
+       then
+           PYTHON_SITE_PACKAGES=$libdir/python$PYTHON_VERSION/site-packages
+       else
+           if test -d $with_python/lib/site-packages
+           then
+               PYTHON_SITE_PACKAGES=$with_python/lib/site-packages
+           else
+               PYTHON_SITE_PACKAGES=`$PYTHON -c "from distutils import sysconfig; 
print(sysconfig.get_python_lib())"`
+           fi
+       fi
+    fi
+    pythondir='$(PYTHON_SITE_PACKAGES)'
+    PYTHON_LIBS=`python$PYTHON_VERSION-config --ldflags`
+else
+    PYTHON=
 fi
 AM_CONDITIONAL(WITH_PYTHON, test "$PYTHON_INCLUDES" != "")
 if test "$PYTHON_INCLUDES" != ""
@@ -374,7 +405,7 @@ AC_ARG_WITH(debug, [  --with-debug            Add the debugging code (on)])
 if test "$with_debug" = "no" ; then
     echo Disabling debug support
     WITH_XSLT_DEBUG=0
-else    
+else
     WITH_XSLT_DEBUG=1
 fi
 AC_SUBST(WITH_XSLT_DEBUG)
@@ -383,12 +414,12 @@ AC_ARG_WITH(mem_debug, [  --with-mem-debug        Add the memory debugging modul
 if test "$with_mem_debug" = "yes" ; then
     echo Enabling memory debug support
     WITH_MEM_DEBUG=1
-else    
+else
     WITH_MEM_DEBUG=0
 fi
 AC_SUBST(WITH_MEM_DEBUG)
 
-dnl 
+dnl
 dnl Is debugger support requested
 dnl
 AC_ARG_WITH(debugger, [  --with-debugger        Add the debugging support (on)])
@@ -432,7 +463,7 @@ AC_ARG_WITH(libxml-prefix,
         [  --with-libxml-prefix=[PFX]          Specify location of libxml config],
        LIBXML_CONFIG_PREFIX=$withval
 )
-        
+
 AC_ARG_WITH(libxml-include-prefix,
         [  --with-libxml-include-prefix=[PFX]  Specify location of libxml headers],
         LIBXML_CFLAGS="-I$withval"
@@ -462,7 +493,7 @@ else
 fi
 
 dnl
-dnl imported from libxml2, c.f. #77827 
+dnl imported from libxml2, c.f. #77827
 dnl
 if test "${GCC}" != "yes" ; then
     case "${host}" in
diff --git a/python/generator.py b/python/generator.py
index c13c8775..62d7f784 100755
--- a/python/generator.py
+++ b/python/generator.py
@@ -2,11 +2,15 @@
 #
 # generate python wrappers from the XML API description
 #
+from __future__ import print_function
 
 functions = {}
 enums = {} # { enumType: { enumConstant: enumValue } }
-
-import string
+import sys
+if sys.version_info < (3, 0):
+    import string as re_str
+else:
+    re_str=str
 
 #######################################################################
 #
@@ -39,19 +43,19 @@ class docParser(xml.sax.handler.ContentHandler):
 
     def close(self):
         if debug:
-            print "close"
+            print("close")
 
     def getmethodname(self):
         return self._methodname
 
     def data(self, text):
         if debug:
-            print "data %s" % text
+            print("data %s" % text)
         self._data.append(text)
 
     def start(self, tag, attrs):
         if debug:
-            print "start %s, %s" % (tag, attrs)
+            print("start %s, %s" % (tag, attrs))
         if tag == 'function':
             self._data = []
             self.in_function = 1
@@ -60,9 +64,9 @@ class docParser(xml.sax.handler.ContentHandler):
             self.function_descr = None
             self.function_return = None
             self.function_file = None
-            if attrs.has_key('name'):
+            if 'name' in attrs:
                 self.function = attrs['name']
-            if attrs.has_key('file'):
+            if 'file' in attrs:
                 self.function_file = attrs['file']
         elif tag == 'info':
             self._data = []
@@ -71,31 +75,31 @@ class docParser(xml.sax.handler.ContentHandler):
                 self.function_arg_name = None
                 self.function_arg_type = None
                 self.function_arg_info = None
-                if attrs.has_key('name'):
+                if 'name' in attrs:
                     self.function_arg_name = attrs['name']
-                if attrs.has_key('type'):
+                if 'type' in attrs:
                     self.function_arg_type = attrs['type']
-                if attrs.has_key('info'):
+                if 'info' in attrs:
                     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'):
+                if 'type' in attrs:
                     self.function_return_type = attrs['type']
-                if attrs.has_key('info'):
+                if 'info' in attrs:
                     self.function_return_info = attrs['info']
-                if attrs.has_key('field'):
+                if 'field' in attrs:
                     self.function_return_field = attrs['field']
         elif tag == 'enum':
-            enum(attrs['type'],attrs['name'],attrs['value']) 
-        
+            enum(attrs['type'],attrs['name'],attrs['value'])
+
 
 
     def end(self, tag):
         if debug:
-            print "end %s" % tag
+            print("end %s" % tag)
         if tag == 'function':
             if self.function != None:
                 function(self.function, self.function_descr,
@@ -118,15 +122,15 @@ class docParser(xml.sax.handler.ContentHandler):
                 str = str + c
             if self.in_function == 1:
                 self.function_descr = str
-                
-                
+
+
 def function(name, desc, ret, args, file):
     functions[name] = (desc, ret, args, file)
 
 def enum(type, name, value):
-    if not enums.has_key(type):
+    if type not in enums:
         enums[type] = {}
-    enums[type][name] = value 
+    enums[type][name] = value
 
 #######################################################################
 #
@@ -264,10 +268,10 @@ def print_function_wrapper(name, output, export, include):
     try:
         (desc, ret, args, file) = functions[name]
     except:
-        print "failed to get function %s infos"
+        print("failed to get function %s infos")
         return
 
-    if skipped_modules.has_key(file):
+    if file in skipped_modules:
         return 0
     if skip_function(name) == 1:
         return 0
@@ -283,7 +287,7 @@ def print_function_wrapper(name, output, export, include):
         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]):
+        if arg[1] in py_types:
             (f, t, n, c, p) = py_types[arg[1]]
             if f != None:
                 format = format + f
@@ -299,9 +303,9 @@ def print_function_wrapper(name, output, export, include):
                 c_call = c_call + ", "
             c_call = c_call + "%s" % (arg[0])
         else:
-            if skipped_types.has_key(arg[1]):
+            if arg[1] in skipped_types:
                 return 0
-            if unknown_types.has_key(arg[1]):
+            if arg[1] in unknown_types:
                 lst = unknown_types[arg[1]]
                 lst.append(name)
             else:
@@ -323,7 +327,7 @@ def print_function_wrapper(name, output, export, include):
         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]):
+    elif ret[0] in py_types:
         (f, t, n, c, p) = py_types[ret[0]]
         c_return = "    %s c_retval;\n" % (ret[0])
         if file == "python_accessor" and ret[2] != None:
@@ -332,7 +336,7 @@ def print_function_wrapper(name, output, export, include):
             c_call = "\n    c_retval = %s(%s);\n" % (name, c_call)
         ret_convert = "    py_retval = %s%sWrap((%s) c_retval);\n" % (p,n,c)
         ret_convert = ret_convert + "    return(py_retval);\n"
-    elif py_return_types.has_key(ret[0]):
+    elif ret[0] in py_return_types:
         (f, t, n, c, p) = py_return_types[ret[0]]
         c_return = "    %s c_retval;\n" % (ret[0])
         if file == "python_accessor" and ret[2] != None:
@@ -342,9 +346,9 @@ def print_function_wrapper(name, output, export, include):
         ret_convert = "    py_retval = %s%sWrap((%s) c_retval);\n" % (p,n,c)
         ret_convert = ret_convert + "    return(py_retval);\n"
     else:
-        if skipped_types.has_key(ret[0]):
+        if ret[0] in skipped_types:
             return 0
-        if unknown_types.has_key(ret[0]):
+        if ret[0] in unknown_types:
             lst = unknown_types[ret[0]]
             lst.append(name)
         else:
@@ -381,7 +385,7 @@ def print_function_wrapper(name, output, export, include):
         output.write("        return(NULL);\n")
     if c_convert != "":
         output.write(c_convert)
-                                                              
+
     output.write(c_call)
     output.write(ret_convert)
     output.write("}\n\n")
@@ -398,18 +402,18 @@ def buildStubs():
         (parser, target)  = getparser()
         parser.feed(data)
         parser.close()
-    except IOError, msg:
+    except IOError as msg:
         try:
             f = open("%s/../doc/libxslt-api.xml" % srcdir)
             data = f.read()
             (parser, target)  = getparser()
             parser.feed(data)
             parser.close()
-        except IOError, msg:
-            print "../doc/libxslt-api.xml", ":", msg
+        except IOError as msg:
+            print("../doc/libxslt-api.xml", ":", msg)
 
-    n = len(functions.keys())
-    print "Found %d functions in libxslt-api.xml" % (n)
+    n = len(list(functions.keys()))
+    print("Found %d functions in libxslt-api.xml" % (n))
 
     py_types['pythonObject'] = ('O', "pythonObject", "pythonObject",
                                 "pythonObject", "libxml_")
@@ -419,12 +423,12 @@ def buildStubs():
         (parser, target)  = getparser()
         parser.feed(data)
         parser.close()
-    except IOError, msg:
-        print "libxslt-python-api.xml", ":", msg
+    except IOError as msg:
+        print("libxslt-python-api.xml", ":", msg)
 
 
-    print "Found %d functions in libxslt-python-api.xml" % (
-          len(functions.keys()) - n)
+    print("Found %d functions in libxslt-python-api.xml" % (
+          len(list(functions.keys())) - n))
     nb_wrap = 0
     failed = 0
     skipped = 0
@@ -439,7 +443,7 @@ def buildStubs():
     wrapper.write("#include <libxslt/xsltconfig.h>\n")
     wrapper.write("#include \"libxslt_wrap.h\"\n")
     wrapper.write("#include \"libxslt-py.h\"\n\n")
-    for function in functions.keys():
+    for function in list(functions.keys()):
         ret = print_function_wrapper(function, wrapper, export, include)
         if ret < 0:
             failed = failed + 1
@@ -453,12 +457,12 @@ def buildStubs():
     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
+    print("Generated %d wrapper functions, %d failed, %d skipped\n" % (nb_wrap,
+                                                              failed, skipped))
+    print("Missing type converters:")
+    for type in list(unknown_types.keys()):
+        print("%s:%d " % (type, len(unknown_types[type])), end=' ')
+    print()
 
 #######################################################################
 #
@@ -533,55 +537,55 @@ def nameFixup(name, classe, type, file):
     l = len(classe)
     if name[0:l] == listname:
         func = name[l:]
-        func = string.lower(func[0:1]) + func[1:]
+        func = re_str.lower(func[0:1]) + func[1:]
     elif name[0:12] == "xmlParserGet" and file == "python_accessor":
         func = name[12:]
-        func = string.lower(func[0:1]) + func[1:]
+        func = re_str.lower(func[0:1]) + func[1:]
     elif name[0:12] == "xmlParserSet" and file == "python_accessor":
         func = name[12:]
-        func = string.lower(func[0:1]) + func[1:]
+        func = re_str.lower(func[0:1]) + func[1:]
     elif name[0:10] == "xmlNodeGet" and file == "python_accessor":
         func = name[10:]
-        func = string.lower(func[0:1]) + func[1:]
+        func = re_str.lower(func[0:1]) + func[1:]
     elif name[0:18] == "xsltXPathParserGet" and file == "python_accessor":
         func = name[18:]
-        func = string.lower(func[0:1]) + func[1:]
+        func = re_str.lower(func[0:1]) + func[1:]
     elif name[0:12] == "xsltXPathGet" and file == "python_accessor":
         func = name[12:]
-        func = string.lower(func[0:1]) + func[1:]
+        func = re_str.lower(func[0:1]) + func[1:]
     elif name[0:16] == "xsltTransformGet" and file == "python_accessor":
         func = name[16:]
-        func = string.lower(func[0:1]) + func[1:]
+        func = re_str.lower(func[0:1]) + func[1:]
     elif name[0:16] == "xsltTransformSet" and file == "python_accessor":
         func = name[13:]
-        func = string.lower(func[0:1]) + func[1:]
+        func = re_str.lower(func[0:1]) + func[1:]
     elif name[0:17] == "xsltStylesheetGet" and file == "python_accessor":
         func = name[17:]
-        func = string.lower(func[0:1]) + func[1:]
+        func = re_str.lower(func[0:1]) + func[1:]
     elif name[0:17] == "xsltStylesheetSet" and file == "python_accessor":
         func = name[14:]
-        func = string.lower(func[0:1]) + func[1:]
+        func = re_str.lower(func[0:1]) + func[1:]
     elif name[0:l] == classe:
         func = name[l:]
-        func = string.lower(func[0:1]) + func[1:]
+        func = re_str.lower(func[0:1]) + func[1:]
     elif name[0:7] == "libxml_":
         func = name[7:]
-        func = string.lower(func[0:1]) + func[1:]
+        func = re_str.lower(func[0:1]) + func[1:]
     elif name[0:8] == "libxslt_":
         func = name[8:]
-        func = string.lower(func[0:1]) + func[1:]
+        func = re_str.lower(func[0:1]) + func[1:]
     elif name[0:6] == "xmlGet":
         func = name[6:]
-        func = string.lower(func[0:1]) + func[1:]
+        func = re_str.lower(func[0:1]) + func[1:]
     elif name[0:3] == "xml":
         func = name[3:]
-        func = string.lower(func[0:1]) + func[1:]
+        func = re_str.lower(func[0:1]) + func[1:]
     elif name[0:7] == "xsltGet":
         func = name[7:]
-        func = string.lower(func[0:1]) + func[1:]
+        func = re_str.lower(func[0:1]) + func[1:]
     elif name[0:4] == "xslt":
         func = name[4:]
-        func = string.lower(func[0:1]) + func[1:]
+        func = re_str.lower(func[0:1]) + func[1:]
     else:
         func = name
     if func[0:5] == "xPath":
@@ -598,6 +602,25 @@ def nameFixup(name, classe, type, file):
         func = "UTF8" + func[4:]
     return func
 
+def cmp_to_key(mycmp):
+    'Convert a cmp= function into a key= function'
+    class K(object):
+        def __init__(self, obj, *args):
+            self.obj = obj
+        def __lt__(self, other):
+            return mycmp(self.obj, other.obj) < 0
+        def __gt__(self, other):
+            return mycmp(self.obj, other.obj) > 0
+        def __eq__(self, other):
+            return mycmp(self.obj, other.obj) == 0
+        def __le__(self, other):
+            return mycmp(self.obj, other.obj) <= 0
+        def __ge__(self, other):
+            return mycmp(self.obj, other.obj) >= 0
+        def __ne__(self, other):
+            return mycmp(self.obj, other.obj) != 0
+    return K
+
 def functionCompare(info1, info2):
     (index1, func1, name1, ret1, args1, file1) = info1
     (index2, func2, name2, ret2, args2, file2) = info2
@@ -620,7 +643,7 @@ def writeDoc(name, args, indent, output):
      if functions[name][0] == None or functions[name][0] == "":
          return
      val = functions[name][0]
-     val = string.replace(val, "NULL", "None")
+     val = val.replace("NULL", "None")
      output.write(indent)
      output.write('"""')
      while len(val) > 60:
@@ -628,7 +651,7 @@ def writeDoc(name, args, indent, output):
              val = val[1:]
              continue
          str = val[0:60]
-         i = string.rfind(str, " ")
+         i = str.rfind(" ")
          if i < 0:
              i = 60
          str = val[0:i]
@@ -659,9 +682,9 @@ def buildWrappers():
     global classes_destructors
 
     function_classes["None"] = []
-    for type in classes_type.keys():
+    for type in list(classes_type.keys()):
         function_classes[classes_type[type][2]] = []
-        
+
     #
     # Build the list of C types to look for ordered to start with
     # primary classes
@@ -671,23 +694,23 @@ def buildWrappers():
     for classe in primary_classes:
         classes_list.append(classe)
         classes_processed[classe] = ()
-        for type in classes_type.keys():
+        for type in list(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):
+    for type in list(classes_type.keys()):
+        if type in ctypes_processed:
             continue
         tinfo = classes_type[type]
-        if not classes_processed.has_key(tinfo[2]):
+        if tinfo[2] not in classes_processed:
             classes_list.append(tinfo[2])
             classes_processed[tinfo[2]] = ()
-            
+
         ctypes.append(type)
         ctypes_processed[type] = ()
 
-    for name in functions.keys():
+    for name in list(functions.keys()):
         found = 0
         (desc, ret, args, file) = functions[name]
         for type in ctypes:
@@ -725,9 +748,9 @@ def buildWrappers():
     txt.write("          Generated Classes for libxslt-python\n\n")
 
     txt.write("#\n# Global functions of the module\n#\n\n")
-    if function_classes.has_key("None"):
+    if "None" in function_classes:
         flist = function_classes["None"]
-        flist.sort(functionCompare)
+        flist.sort(key=cmp_to_key(functionCompare))
         oldfile = ""
         for info in flist:
             (index, func, name, ret, args, file) = info
@@ -747,12 +770,12 @@ def buildWrappers():
             writeDoc(name, args, '    ', classes)
 
             for arg in args:
-                if classes_type.has_key(arg[1]):
+                if arg[1] in classes_type:
                     classes.write("    if %s == 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]))
-                elif libxml2_classes_type.has_key(arg[1]):
+                elif arg[1] in libxml2_classes_type:
                     classes.write("    if %s == None: %s__o = None\n" %
                                   (arg[0], arg[0]))
                     classes.write("    else: %s__o = %s%s\n" %
@@ -767,19 +790,19 @@ def buildWrappers():
                 if n != 0:
                     classes.write(", ")
                 classes.write("%s" % arg[0])
-                if classes_type.has_key(arg[1]):
+                if arg[1] in classes_type:
                     classes.write("__o")
-                if libxml2_classes_type.has_key(arg[1]):
+                if arg[1] in libxml2_classes_type:
                     classes.write("__o")
                 n = n + 1
             classes.write(")\n")
             if ret[0] != "void":
-                if classes_type.has_key(ret[0]):
+                if ret[0] in classes_type:
                     classes.write("    if ret == None: return None\n")
                     classes.write("    return ")
                     classes.write(classes_type[ret[0]][1] % ("ret"))
                     classes.write("\n")
-                elif libxml2_classes_type.has_key(ret[0]):
+                elif ret[0] in libxml2_classes_type:
                     classes.write("    if ret == None: return None\n")
                     classes.write("    return libxml2.")
                     classes.write(libxml2_classes_type[ret[0]][1] % ("ret"))
@@ -793,7 +816,7 @@ def buildWrappers():
         if classname == "None":
             pass
         else:
-            if classes_ancestor.has_key(classname):
+            if classname in classes_ancestor:
                 txt.write("\n\nClass %s(%s)\n" % (classname,
                           classes_ancestor[classname]))
                 classes.write("class %s(%s):\n" % (classname,
@@ -814,7 +837,7 @@ def buildWrappers():
                 classes.write("    def __init__(self, _obj=None):\n")
                 classes.write("        if _obj != None:self._o = _obj;return\n")
                 classes.write("        self._o = None\n\n")
-            if classes_destructors.has_key(classname):
+            if classname in classes_destructors:
                 classes.write("    def __del__(self):\n")
                 if classes_destructors[classname] == "pass":
                     classes.write("        pass\n")
@@ -824,7 +847,7 @@ def buildWrappers():
                                   classes_destructors[classname])
                     classes.write("        self._o = None\n\n")
             flist = function_classes[classname]
-            flist.sort(functionCompare)
+            flist.sort(key=cmp_to_key(functionCompare))
             oldfile = ""
             for info in flist:
                 (index, func, name, ret, args, file) = info
@@ -850,13 +873,13 @@ def buildWrappers():
                 writeDoc(name, args, '        ', classes)
                 n = 0
                 for arg in args:
-                    if classes_type.has_key(arg[1]):
+                    if arg[1] in classes_type:
                         if n != index:
                             classes.write("        if %s == 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]))
-                    elif libxml2_classes_type.has_key(arg[1]):
+                    elif arg[1] in libxml2_classes_type:
                         classes.write("        if %s == None: %s__o = None\n" %
                                       (arg[0], arg[0]))
                         classes.write("        else: %s__o = %s%s\n" %
@@ -874,30 +897,30 @@ def buildWrappers():
                         classes.write(", ")
                     if n != index:
                         classes.write("%s" % arg[0])
-                        if classes_type.has_key(arg[1]):
+                        if arg[1] in classes_type:
                             classes.write("__o")
-                        elif libxml2_classes_type.has_key(arg[1]):
+                        elif arg[1] in libxml2_classes_type:
                             classes.write("__o")
                     else:
                         classes.write("self")
-                        if classes_type.has_key(arg[1]):
+                        if arg[1] in classes_type:
                             classes.write(classes_type[arg[1]][0])
-                        elif libxml2_classes_type.has_key(arg[1]):
+                        elif arg[1] in libxml2_classes_type:
                             classes.write(libxml2_classes_type[arg[1]][0])
                     n = n + 1
                 classes.write(")\n")
                 if ret[0] != "void":
-                    if classes_type.has_key(ret[0]):
+                    if ret[0] in classes_type:
                         classes.write("        if ret == None: return None\n")
                         classes.write("        return ")
                         classes.write(classes_type[ret[0]][1] % ("ret"))
                         classes.write("\n")
-                    elif libxml2_classes_type.has_key(ret[0]):
+                    elif ret[0] in libxml2_classes_type:
                         classes.write("        if ret == None: return None\n")
                         classes.write("        return libxml2.")
                         classes.write(libxml2_classes_type[ret[0]][1] % ("ret"))
                         classes.write("\n")
-                    elif converter_type.has_key(ret[0]):
+                    elif ret[0] in converter_type:
                         classes.write("        if ret == None: return None\n")
                         classes.write("        return ")
                         classes.write(converter_type[ret[0]] % ("ret"))
@@ -909,13 +932,13 @@ def buildWrappers():
     #
     # Generate enum constants
     #
-    for type,enum in enums.items():
+    for type,enum in list(enums.items()):
         classes.write("# %s\n" % type)
-        items = enum.items()
-        items.sort(lambda i1,i2: cmp(long(i1[1]),long(i2[1])))
+        items = list(enum.items())
+        items.sort(key=lambda x: x[1])
         for name,value in items:
             classes.write("%s = %s\n" % (name,value))
-        classes.write("\n"); 
+        classes.write("\n");
 
     txt.close()
     classes.close()
diff --git a/python/libxml_wrap.h b/python/libxml_wrap.h
index 53777d98..eb8c5753 100644
--- a/python/libxml_wrap.h
+++ b/python/libxml_wrap.h
@@ -15,6 +15,16 @@
 #include <libxml/xinclude.h>
 #include <libxml/xpointer.h>
 
+PyObject* PY_IMPORT_INT(long ival);
+PyObject* PY_IMPORT_STRING(const char *u);
+PyObject* PY_IMPORT_CPTRD(void *po, const char *na, void *de);
+int PY_IMPORT_LONG_CHECK(PyObject *o);
+int PY_IMPORT_STRING_CHECK(PyObject *o);
+int PY_IMPORT_CPTR_CHECK(PyObject *o);
+Py_ssize_t PY_IMPORT_STRING_GET_SIZE(PyObject *o);
+char* PY_IMPORT_AS_STRING(PyObject *o);
+long PY_IMPORT_AS_LONG(PyObject *io);
+
 #define PyxmlNode_Get(v) (((v) == Py_None) ? NULL : \
        (((PyxmlNode_Object *)(v))->obj))
 
diff --git a/python/libxslt.c b/python/libxslt.c
index f8371b7b..a174fafe 100644
--- a/python/libxslt.c
+++ b/python/libxslt.c
@@ -28,6 +28,7 @@
 /* snprintf emulation taken from http://stackoverflow.com/a/8712996/1956010 */
 #if _MSC_VER < 1900
 
+
 #include <stdarg.h>
 
 #define vsnprintf c99_vsnprintf
@@ -77,9 +78,8 @@ libxslt_xsltStylesheetPtrWrap(xsltStylesheetPtr style) {
        Py_INCREF(Py_None);
        return(Py_None);
     }
-    ret = PyCObject_FromVoidPtrAndDesc((void *) style,
-                                      (char *)"xsltStylesheetPtr", NULL);
-
+    ret = PY_IMPORT_CPTRD((void *) style,
+                        (char *)"xsltStylesheetPtr", NULL);
     return(ret);
 }
 
@@ -94,8 +94,9 @@ libxslt_xsltTransformContextPtrWrap(xsltTransformContextPtr ctxt) {
        Py_INCREF(Py_None);
        return(Py_None);
     }
-    ret = PyCObject_FromVoidPtrAndDesc((void *) ctxt,
-                                      (char *)"xsltTransformContextPtr", NULL);
+    ret = PY_IMPORT_CPTRD((void *) ctxt,
+                        (char *)"xsltTransformContextPtr", NULL);
+
     return(ret);
 }
 
@@ -110,8 +111,8 @@ libxslt_xsltElemPreCompPtrWrap(xsltElemPreCompPtr ctxt) {
        Py_INCREF(Py_None);
        return(Py_None);
     }
-    ret = PyCObject_FromVoidPtrAndDesc((void *) ctxt,
-                                      (char *)"xsltElemPreCompPtr", NULL);
+    ret = PY_IMPORT_CPTRD((void *) ctxt,
+                        (char *)"xsltElemPreCompPtr", NULL);
     return(ret);
 }
 
@@ -128,8 +129,7 @@ libxslt_xsltGetTransformContextHashCode(PyObject *self ATTRIBUTE_UNUSED, PyObjec
 
     tctxt =  (xsltTransformContextPtr) PytransformCtxt_Get(py_tctxt);
     hash_code = (ptrdiff_t) tctxt;
-
-    ret = PyInt_FromLong(hash_code);
+    ret = PY_IMPORT_INT(hash_code);
     return ret;
 }
 
@@ -166,7 +166,8 @@ libxslt_xsltGetStylesheetHashCode(PyObject *self ATTRIBUTE_UNUSED, PyObject *arg
     style =  (xsltStylesheetPtr) Pystylesheet_Get(py_style);
     hash_code = (ptrdiff_t) style;
 
-    ret = PyInt_FromLong(hash_code);
+    ret = PY_IMPORT_INT(hash_code);
+
     return ret;
 }
 
@@ -620,7 +621,8 @@ libxslt_xsltSetLoaderFunc(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
     pythonDocLoaderObject = loader;
     xsltSetLoaderFunc(pythonDocLoaderFuncWrapper);
 
-    py_retval = PyInt_FromLong(0);
+    py_retval = PY_IMPORT_INT(0);
+
     return(py_retval);
 }
 
@@ -713,12 +715,23 @@ libxslt_xsltApplyStylesheetUser(PyObject *self ATTRIBUTE_UNUSED, PyObject *args)
                    const char *tmp;
                    int size;
 
+#if PY_MAJOR_VERSION >= 3
+                   tmp = PyUnicode_AsUTF8AndSize(name, &size);
+#else
+
                    tmp = PyString_AS_STRING(name);
                    size = PyString_GET_SIZE(name);
+#endif
                    params[j * 2] = (char *) xmlCharStrndup(tmp, size);
+
+#if PY_MAJOR_VERSION >= 3
+                   if (PyUnicode_Check(value)) {
+                       tmp = PyUnicode_AsUTF8AndSize(value, &size);
+#else
                    if (PyString_Check(value)) {
                        tmp = PyString_AS_STRING(value);
                        size = PyString_GET_SIZE(value);
+#endif
                        params[(j * 2) + 1] = (char *)
                            xmlCharStrndup(tmp, size);
                    } else {
@@ -789,12 +802,22 @@ libxslt_xsltApplyStylesheet(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
                    const char *tmp;
                    int size;
 
+#if PY_MAJOR_VERSION >= 3
+                   tmp = PyUnicode_AsUTF8AndSize(name, &size);
+#else
                    tmp = PyString_AS_STRING(name);
                    size = PyString_GET_SIZE(name);
+#endif
                    params[j * 2] = (char *) xmlCharStrndup(tmp, size);
+
+#if PY_MAJOR_VERSION >= 3
+                   if (PyUnicode_Check(value)) {
+                       tmp = PyUnicode_AsUTF8AndSize(value, &size);
+#else
                    if (PyString_Check(value)) {
                        tmp = PyString_AS_STRING(value);
                        size = PyString_GET_SIZE(value);
+#endif
                        params[(j * 2) + 1] = (char *)
                            xmlCharStrndup(tmp, size);
                    } else {
@@ -859,11 +882,19 @@ libxslt_xsltSaveResultToString(PyObject *self ATTRIBUTE_UNUSED, PyObject *args)
     if(size)
       {
       buffer[size] = '\0';
+#if PY_MAJOR_VERSION >= 3
+      py_retval = PyUnicode_DecodeUTF8((char *) buffer, size, NULL);
+#else
       py_retval = PyString_FromString((char *) buffer);
+#endif
       xmlFree(buffer);
       }
     else
+#if PY_MAJOR_VERSION >= 3
+      py_retval = PyUnicode_DecodeUTF8("", 0, NULL);
+#else
       py_retval = PyString_FromString("");
+#endif
     return(py_retval);
  FAIL:
     return(0);
@@ -1197,19 +1228,52 @@ static PyMethodDef libxsltMethods[] = {
 };
 
 #ifdef MERGED_MODULES
+#if PY_MAJOR_VERSION >= 3
+extern PyObject*  PyInit_libxml2mod(void);
+#else
 extern void initlibxml2mod(void);
 #endif
+#endif
 
+#if PY_MAJOR_VERSION >= 3
+static struct PyModuleDef moduledef = {
+    PyModuleDef_HEAD_INIT,
+    "libxsltmod",
+    NULL,
+    -1,
+    libxsltMethods,
+    NULL,
+    NULL,
+    NULL,
+    NULL
+};
+#endif
+
+#if PY_MAJOR_VERSION >= 3
+PyObject* PyInit_libxsltmod(void){
+#else
 void initlibxsltmod(void) {
+#endif
     static int initialized = 0;
+    PyObject *m;
 
 #ifdef MERGED_MODULES
+#if PY_MAJOR_VERSION >= 3
+    PyInit_libxml2mod();
+#else
     initlibxml2mod();
+#endif
 #endif
 
     if (initialized != 0)
        return;
-    Py_InitModule((char *)"libxsltmod", libxsltMethods);
+#if PY_MAJOR_VERSION >= 3
+    m = PyModule_Create(&moduledef);
+#else
+    m = Py_InitModule((char *)"libxsltmod", libxsltMethods);
+#endif
+    if (!m)
+       return;
     initialized = 1;
     /*
      * Specific XSLT initializations
@@ -1222,6 +1286,7 @@ void initlibxsltmod(void) {
      * Register the EXSLT extensions and the test module
      */
     exsltRegisterAll();
+#if PY_MAJOR_VERSION >= 3
+    return m;
+#endif
 }
-
-
diff --git a/python/tests/basic.py b/python/tests/basic.py
index 4a60590b..56cdf145 100755
--- a/python/tests/basic.py
+++ b/python/tests/basic.py
@@ -1,4 +1,6 @@
 #!/usr/bin/python -u
+from __future__ import print_function
+
 import sys
 import libxml2
 # Memory debug specific
@@ -14,7 +16,7 @@ result = style.applyStylesheet(doc, None)
 style.saveResultToFilename("foo", result, 0)
 stringval = style.saveResultToString(result)
 if (len(stringval) != 68):
-  print "Error in saveResultToString"
+  print("Error in saveResultToString")
   sys.exit(255)
 style.freeStylesheet()
 doc.freeDoc()
@@ -23,8 +25,8 @@ result.freeDoc()
 # Memory debug specific
 libxslt.cleanup()
 if libxml2.debugMemory(1) == 0:
-    print "OK"
+    print("OK")
 else:
-    print "Memory leak %d bytes" % (libxml2.debugMemory(1))
+    print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
     libxml2.dumpMemory()
     sys.exit(255)
diff --git a/python/tests/exslt.py b/python/tests/exslt.py
index c7333efb..1368fff2 100755
--- a/python/tests/exslt.py
+++ b/python/tests/exslt.py
@@ -1,4 +1,6 @@
 #!/usr/bin/python -u
+from __future__ import print_function
+
 import sys
 import libxml2
 # Memory debug specific
@@ -44,14 +46,14 @@ expect="""<?xml version="1.0"?>
 """
 
 if stringval != expect:
-  print "Exslt processing failed"
+  print("Exslt processing failed")
   sys.exit(255)
-    
+
 # Memory debug specific
 libxslt.cleanup()
 if libxml2.debugMemory(1) == 0:
-    print "OK"
+    print("OK")
 else:
-    print "Memory leak %d bytes" % (libxml2.debugMemory(1))
+    print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
     libxml2.dumpMemory()
     sys.exit(255)
diff --git a/python/tests/extelem.py b/python/tests/extelem.py
index 16635174..2f3e047a 100644
--- a/python/tests/extelem.py
+++ b/python/tests/extelem.py
@@ -1,7 +1,15 @@
 #!/usr/bin/python -u
+from __future__ import print_function
+
 import sys
 import string
-import StringIO
+import sys
+
+if sys.version_info < (3, 0):
+    import StringIO as io
+else:
+    import io
+
 import libxml2
 # Memory debug specific
 libxml2.debugMemory(1)
@@ -34,7 +42,7 @@ def transform_test(ctx, node, inst, comp):
         pass
 
     tctxt.insertNode().addContent('SUCCESS')
-    
+
 
 
 styledoc = libxml2.parseDoc("""
@@ -58,23 +66,23 @@ style.freeStylesheet()
 doc.freeDoc()
 
 
-extensions = StringIO.StringIO()
+extensions = io.StringIO()
 libxslt.debugDumpExtensions(extensions)
 
 if 0 and extensions.buf.find(EXT_URL) < 0:
-    print "Element extension not registered (or dumping broken)"
+    print("Element extension not registered (or dumping broken)")
     sys.exit(1)
 
 root = result.children
 
 if root.name != "article":
-    print "Unexpected root node name"
+    print("Unexpected root node name")
     sys.exit(1)
 if root.content != "SUCCESS":
-    print "Unexpected root node content, extension function failed"
+    print("Unexpected root node content, extension function failed")
     sys.exit(1)
 if insertNodeName != 'article':
-    print "The function callback failed to access its context"
+    print("The function callback failed to access its context")
     sys.exit(1)
 
 result.dump(sys.stdout)
@@ -83,8 +91,8 @@ result.freeDoc()
 # Memory debug specific
 libxslt.cleanup()
 if libxml2.debugMemory(1) == 0:
-    print "OK"
+    print("OK")
 else:
-    print "Memory leak %d bytes" % (libxml2.debugMemory(1))
+    print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
     libxml2.dumpMemory()
     sys.exit(255)
diff --git a/python/tests/extfunc.py b/python/tests/extfunc.py
index fc6040b3..2bb6bea2 100755
--- a/python/tests/extfunc.py
+++ b/python/tests/extfunc.py
@@ -1,4 +1,6 @@
 #!/usr/bin/python -u
+from __future__ import print_function
+
 import sys
 import string
 import libxml2
@@ -46,13 +48,13 @@ doc.freeDoc()
 
 root = result.children
 if root.name != "article":
-    print "Unexpected root node name"
+    print("Unexpected root node name")
     sys.exit(1)
 if root.content != "SUCCESS":
-    print "Unexpected root node content, extension function failed"
+    print("Unexpected root node content, extension function failed")
     sys.exit(1)
 if nodeName != 'article':
-    print "The function callback failed to access its context"
+    print("The function callback failed to access its context")
     sys.exit(1)
 
 result.freeDoc()
@@ -60,8 +62,8 @@ result.freeDoc()
 # Memory debug specific
 libxslt.cleanup()
 if libxml2.debugMemory(1) == 0:
-    print "OK"
+    print("OK")
 else:
-    print "Memory leak %d bytes" % (libxml2.debugMemory(1))
+    print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
     libxml2.dumpMemory()
     sys.exit(255)
diff --git a/python/tests/pyxsltproc.py b/python/tests/pyxsltproc.py
index 58434709..d9871cc0 100755
--- a/python/tests/pyxsltproc.py
+++ b/python/tests/pyxsltproc.py
@@ -4,6 +4,8 @@
 # bindings, not complete yet and shows up the things missing
 # from the existing python interfaces
 #
+from __future__ import print_function
+
 import sys
 import time
 import os
@@ -41,7 +43,7 @@ def endTimer(msg):
     global endtime
 
     endtime = time.time()
-    print "%s took %d ms" % (msg, (endtime - begin) * 1000)
+    print("%s took %d ms" % (msg, (endtime - begin) * 1000))
 
 def xsltProcess(doc, cur, filename):
     global timing
@@ -72,7 +74,7 @@ def xsltProcess(doc, cur, filename):
 #        if ctxt == None:
 #            return
         if profile:
-            print "TODO: Profiling not yet supported"
+            print("TODO: Profiling not yet supported")
         else:
             res = cur.applyStylesheet(doc, params)
         if timing:
@@ -82,7 +84,7 @@ def xsltProcess(doc, cur, filename):
                 endTimer("Applying stylesheet")
         doc.freeDoc()
         if res == None:
-            print "no result for %s" % (filename)
+            print("no result for %s" % (filename))
             return
         if noout != 0:
             res.freeDoc()
@@ -97,35 +99,35 @@ def xsltProcess(doc, cur, filename):
                 endTimer("Saving result")
         res.freeDoc()
     else:
-        print "TODO: xsltRunStylesheet not yet mapped"
+        print("TODO: xsltRunStylesheet not yet mapped")
 
 def usage(name = 'pyxsltproc'):
-    print "Usage: %s [options] stylesheet file [file ...]" % (name)
-    print "a reimplementation of xsltproc(1) on top of libxslt-python"
-    print "   Options:"
-    print "\t--version or -V: show the version of libxml and libxslt used"
-    print "\t--verbose or -v: show logs of what's happening"
-    print "\t--output file or -o file: save to a given file"
-    print "\t--timing: display the time used"
-    print "\t--repeat: run the transformation 20 times"
-    print "\t--debug: dump the tree of the result instead"
-    print "\t--novalid skip the Dtd loading phase"
-    print "\t--noout: do not dump the result"
-    print "\t--maxdepth val : increase the maximum depth"
-    print "\t--html: the input document is(are) an HTML file(s)"
-    print "\t--param name value : pass a (parameter,value) pair"
-    print "\t       value is an XPath expression."
-    print "\t       string values must be quoted like \"'string'\""
-    print "\t       or use stringparam to avoid it"
-    print "\t--stringparam name value : pass a (parameter,string value) pair"
-    print "\t--nonet refuse to fetch DTDs or entities over network"
-    print "\t--catalogs : use SGML catalogs from $SGML_CATALOG_FILES"
-    print "\t             otherwise XML Catalogs starting from "
-    print "\t         file:///etc/xml/catalog are activated by default"
-    print "\t--xinclude : do XInclude processing on document input"
-    print "\t--profile or --norman : dump profiling information "
-    print "\nProject libxslt home page: http://xmlsoft.org/XSLT/";
-    print "To report bugs and get help: http://xmlsoft.org/XSLT/bugs.html";
+    print("Usage: %s [options] stylesheet file [file ...]" % (name))
+    print("a reimplementation of xsltproc(1) on top of libxslt-python")
+    print("   Options:")
+    print("\t--version or -V: show the version of libxml and libxslt used")
+    print("\t--verbose or -v: show logs of what's happening")
+    print("\t--output file or -o file: save to a given file")
+    print("\t--timing: display the time used")
+    print("\t--repeat: run the transformation 20 times")
+    print("\t--debug: dump the tree of the result instead")
+    print("\t--novalid skip the Dtd loading phase")
+    print("\t--noout: do not dump the result")
+    print("\t--maxdepth val : increase the maximum depth")
+    print("\t--html: the input document is(are) an HTML file(s)")
+    print("\t--param name value : pass a (parameter,value) pair")
+    print("\t       value is an XPath expression.")
+    print("\t       string values must be quoted like \"'string'\"")
+    print("\t       or use stringparam to avoid it")
+    print("\t--stringparam name value : pass a (parameter,string value) pair")
+    print("\t--nonet refuse to fetch DTDs or entities over network")
+    print("\t--catalogs : use SGML catalogs from $SGML_CATALOG_FILES")
+    print("\t             otherwise XML Catalogs starting from ")
+    print("\t         file:///etc/xml/catalog are activated by default")
+    print("\t--xinclude : do XInclude processing on document input")
+    print("\t--profile or --norman : dump profiling information ")
+    print("\nProject libxslt home page: http://xmlsoft.org/XSLT/";)
+    print("To report bugs and get help: http://xmlsoft.org/XSLT/bugs.html";)
 
 def main(args = None):
     global debug
@@ -148,7 +150,7 @@ def main(args = None):
         args = sys.argv[1:]
         if len(args) <= 0:
             usage(sys.argv[0])
-            
+
 
     i = 0
     while i < len(args):
@@ -163,10 +165,10 @@ def main(args = None):
             debug = 1
         elif args[i] == "-verbose" or args[i] == "--verbose" or \
              args[i] == "-v":
-            print "TODO: xsltSetGenericDebugFunc() mapping missing"
+            print("TODO: xsltSetGenericDebugFunc() mapping missing")
         elif args[i] == "-version" or args[i] == "--version" or \
              args[i] == "-V":
-            print "TODO: version information mapping missing"
+            print("TODO: version information mapping missing")
         elif args[i] == "-verbose" or args[i] == "--verbose" or \
              args[i] == "-v":
             if repeat == 0:
@@ -174,14 +176,14 @@ def main(args = None):
             else:
                 repeat = 100
         elif args[i] == "-novalid" or args[i] == "--novalid":
-            print "TODO: xmlLoadExtDtdDefaultValue mapping missing"
+            print("TODO: xmlLoadExtDtdDefaultValue mapping missing")
             novalid = 1
         elif args[i] == "-noout" or args[i] == "--noout":
             noout = 1
         elif args[i] == "-html" or args[i] == "--html":
             html = 1
         elif args[i] == "-nonet" or args[i] == "--nonet":
-            print "TODO: xmlSetExternalEntityLoader mapping missing"
+            print("TODO: xmlSetExternalEntityLoader mapping missing")
             nonet = 1
         elif args[i] == "-catalogs" or args[i] == "--catalogs":
             try:
@@ -191,7 +193,7 @@ def main(args = None):
             if catalogs != none:
                 libxml2.xmlLoadCatalogs(catalogs)
             else:
-                print "Variable $SGML_CATALOG_FILES not set"
+                print("Variable $SGML_CATALOG_FILES not set")
         elif args[i] == "-xinclude" or args[i] == "--xinclude":
             xinclude = 1
             libxslt.setXIncludeDefault(1)
@@ -204,17 +206,17 @@ def main(args = None):
             params[args[i]] = "'%s'" % (args[i + 1])
             i = i + 1
         elif args[i] == "-maxdepth" or args[i] == "--maxdepth":
-            print "TODO: xsltMaxDepth mapping missing"
+            print("TODO: xsltMaxDepth mapping missing")
         else:
-            print "Unknown option %s" % (args[i])
+            print("Unknown option %s" % (args[i]))
             usage()
             return(3)
-        
-        
-        
-        
+
+
+
+
         i = i + 1
-        
+
     libxml2.lineNumbersDefault(1)
     libxml2.substituteEntitiesDefault(1)
     # TODO: xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS
@@ -247,7 +249,7 @@ def main(args = None):
         if timing:
             endTimer("Parsing stylesheet %s" % (args[i]))
         if style == None:
-            print "cannot parse %s" % (args[i])
+            print("cannot parse %s" % (args[i]))
             cur = None
             errorno = 4
             done = 1
@@ -273,7 +275,7 @@ def main(args = None):
         else:
             doc = libxml2.parseFile(args[i])
         if doc == None:
-            print "unable to parse %s" % (args[i])
+            print("unable to parse %s" % (args[i]))
             errorno = 6
             i = i + 1
             continue
@@ -292,7 +294,7 @@ if __name__ == "__main__":
 # Memory debug specific
 libxslt.cleanup()
 if libxml2.debugMemory(1) != 0:
-    print "Memory leak %d bytes" % (libxml2.debugMemory(1))
+    print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
     libxml2.dumpMemory()
 
 sys.exit(errorno)
diff --git a/python/types.c b/python/types.c
index 1beee75f..d076a2bb 100644
--- a/python/types.c
+++ b/python/types.c
@@ -13,6 +13,102 @@ xmlParserInputPtr xmlNoNetExternalEntityLoader(const char *URL,
 #include "libxml_wrap.h"
 #include <libxml/xpathInternals.h>
 
+/* Helper functions */
+
+PyObject* PY_IMPORT_INT(long ival){
+  PyObject *ret;
+  #if PY_MAJOR_VERSION >= 3
+  ret=PyLong_FromLong(ival);
+  #else
+  ret=PyInt_FromLong(ival);
+  #endif
+  return ret;
+}
+
+PyObject* PY_IMPORT_STRING(const char *u){
+  PyObject *ret;
+  #if PY_MAJOR_VERSION >= 3
+  ret=PyUnicode_FromString(u);
+  #else
+  ret=PyString_FromString(u);
+  #endif
+  return ret;
+}
+
+PyObject* PY_IMPORT_CPTRD(void *po,
+                        const char *na,
+                        void *de){
+  PyObject *ret;
+  #if PY_MAJOR_VERSION >= 3
+  ret=PyCapsule_New(po,na,de);
+  #else
+  ret=PyCObject_FromVoidPtrAndDesc(po,(void *)na,de);
+  #endif
+  return ret;
+}
+
+int PY_IMPORT_LONG_CHECK(PyObject *o){
+       int ret;
+       #if PY_MAJOR_VERSION >= 3
+       ret=PyLong_Check(o);
+       #else
+       ret=PyInt_Check(o);
+       #endif
+       return ret;
+}
+
+int PY_IMPORT_STRING_CHECK(PyObject *o){
+       int ret;
+       #if PY_MAJOR_VERSION >= 3
+       ret=PyUnicode_Check(o);
+       #else
+       ret=PyString_Check(o);
+       #endif
+       return ret;
+}
+
+int PY_IMPORT_CPTR_CHECK(PyObject *o){
+       int ret;
+       #if PY_MAJOR_VERSION >= 3
+       ret=PyCapsule_CheckExact(o);
+       #else
+       ret=PyCObject_Check(o);
+       #endif
+       return ret;
+}
+
+Py_ssize_t PY_IMPORT_STRING_GET_SIZE(PyObject *o){
+       Py_ssize_t ret;
+       #if PY_MAJOR_VERSION >= 3
+       ret=PyUnicode_GET_SIZE(o);
+       #else
+       ret=PyString_GET_SIZE(o);
+       #endif
+       return ret;
+}
+
+char* PY_IMPORT_AS_STRING(PyObject *o){
+       char *ret;
+       #if PY_MAJOR_VERSION >= 3
+       ret=PyUnicode_AS_DATA(o);
+       #else
+       ret=PyString_AS_STRING(o);
+       #endif
+       return ret;
+}
+
+long PY_IMPORT_AS_LONG(PyObject *io){
+       long ret;
+       #if PY_MAJOR_VERSION >= 3
+       ret=PyLong_AS_LONG(io);
+       #else
+       ret=PyInt_AS_LONG(io);
+       #endif
+       return ret;
+}
+
+/* */
+
 PyObject *
 libxml_intWrap(int val)
 {
@@ -21,7 +117,7 @@ libxml_intWrap(int val)
 #ifdef DEBUG
     printf("libxml_intWrap: val = %d\n", val);
 #endif
-    ret = PyInt_FromLong((long) val);
+    ret = PY_IMPORT_INT((long) val);
     return (ret);
 }
 
@@ -33,7 +129,9 @@ libxml_longWrap(long val)
 #ifdef DEBUG
     printf("libxml_longWrap: val = %ld\n", val);
 #endif
-    ret = PyInt_FromLong(val);
+
+    ret = PY_IMPORT_INT(val);
+
     return (ret);
 }
 
@@ -62,7 +160,7 @@ libxml_charPtrWrap(char *str)
         return (Py_None);
     }
     /* TODO: look at deallocation */
-    ret = PyString_FromString(str);
+    ret = PY_IMPORT_STRING(str);
     xmlFree(str);
     return (ret);
 }
@@ -79,8 +177,7 @@ libxml_charPtrConstWrap(const char *str)
         Py_INCREF(Py_None);
         return (Py_None);
     }
-    /* TODO: look at deallocation */
-    ret = PyString_FromString(str);
+    ret = PY_IMPORT_STRING(str);
     return (ret);
 }
 
@@ -97,7 +194,7 @@ libxml_xmlCharPtrWrap(xmlChar * str)
         return (Py_None);
     }
     /* TODO: look at deallocation */
-    ret = PyString_FromString((char *) str);
+    ret = PY_IMPORT_STRING((char *) str);
     xmlFree(str);
     return (ret);
 }
@@ -115,7 +212,7 @@ libxml_xmlCharPtrConstWrap(const xmlChar * str)
         return (Py_None);
     }
     /* TODO: look at deallocation */
-    ret = PyString_FromString((char *) str);
+    ret = PY_IMPORT_STRING((char *) str);
     return (ret);
 }
 
@@ -132,7 +229,7 @@ libxml_constcharPtrWrap(const char *str)
         return (Py_None);
     }
     /* TODO: look at deallocation */
-    ret = PyString_FromString(str);
+    ret = PY_IMPORT_STRING((char *) str);
     return (ret);
 }
 
@@ -149,7 +246,7 @@ libxml_constxmlCharPtrWrap(const xmlChar * str)
         return (Py_None);
     }
     /* TODO: look at deallocation */
-    ret = PyString_FromString((char *) str);
+    ret = PY_IMPORT_STRING((char *) str);
     return (ret);
 }
 
@@ -166,8 +263,7 @@ libxml_xmlDocPtrWrap(xmlDocPtr doc)
         return (Py_None);
     }
     /* TODO: look at deallocation */
-    ret =
-        PyCObject_FromVoidPtrAndDesc((void *) doc, (char *) "xmlDocPtr",
+        ret = PY_IMPORT_CPTRD((void *) doc, (char *) "xmlDocPtr",
                                      NULL);
     return (ret);
 }
@@ -185,8 +281,9 @@ libxml_xmlNodePtrWrap(xmlNodePtr node)
         return (Py_None);
     }
     ret =
-        PyCObject_FromVoidPtrAndDesc((void *) node, (char *) "xmlNodePtr",
+        PY_IMPORT_CPTRD((void *) node, (char *) "xmlNodePtr",
                                      NULL);
+
     return (ret);
 }
 
@@ -203,8 +300,9 @@ libxml_xmlURIPtrWrap(xmlURIPtr uri)
         return (Py_None);
     }
     ret =
-        PyCObject_FromVoidPtrAndDesc((void *) uri, (char *) "xmlURIPtr",
+        PY_IMPORT_CPTRD((void *) uri, (char *) "xmlURIPtr",
                                      NULL);
+
     return (ret);
 }
 
@@ -221,7 +319,7 @@ libxml_xmlNsPtrWrap(xmlNsPtr ns)
         return (Py_None);
     }
     ret =
-        PyCObject_FromVoidPtrAndDesc((void *) ns, (char *) "xmlNsPtr",
+        PY_IMPORT_CPTRD((void *) ns, (char *) "xmlNsPtr",
                                      NULL);
     return (ret);
 }
@@ -239,8 +337,9 @@ libxml_xmlAttrPtrWrap(xmlAttrPtr attr)
         return (Py_None);
     }
     ret =
-        PyCObject_FromVoidPtrAndDesc((void *) attr, (char *) "xmlAttrPtr",
+        PY_IMPORT_CPTRD((void *) attr, (char *) "xmlAttrPtr",
                                      NULL);
+
     return (ret);
 }
 
@@ -257,8 +356,9 @@ libxml_xmlAttributePtrWrap(xmlAttributePtr attr)
         return (Py_None);
     }
     ret =
-        PyCObject_FromVoidPtrAndDesc((void *) attr,
+        PY_IMPORT_CPTRD((void *) attr,
                                      (char *) "xmlAttributePtr", NULL);
+
     return (ret);
 }
 
@@ -275,7 +375,7 @@ libxml_xmlElementPtrWrap(xmlElementPtr elem)
         return (Py_None);
     }
     ret =
-        PyCObject_FromVoidPtrAndDesc((void *) elem,
+        PY_IMPORT_CPTRD((void *) elem,
                                      (char *) "xmlElementPtr", NULL);
     return (ret);
 }
@@ -292,9 +392,11 @@ libxml_xmlXPathContextPtrWrap(xmlXPathContextPtr ctxt)
         Py_INCREF(Py_None);
         return (Py_None);
     }
+
     ret =
-        PyCObject_FromVoidPtrAndDesc((void *) ctxt,
+        PY_IMPORT_CPTRD((void *) ctxt,
                                      (char *) "xmlXPathContextPtr", NULL);
+
     return (ret);
 }
 
@@ -310,7 +412,7 @@ libxml_xmlXPathParserContextPtrWrap(xmlXPathParserContextPtr ctxt)
         Py_INCREF(Py_None);
         return (Py_None);
     }
-    ret = PyCObject_FromVoidPtrAndDesc((void *) ctxt,
+    ret = PY_IMPORT_CPTRD((void *) ctxt,
                                        (char *) "xmlXPathParserContextPtr",
                                        NULL);
     return (ret);
@@ -329,7 +431,7 @@ libxml_xmlParserCtxtPtrWrap(xmlParserCtxtPtr ctxt)
         return (Py_None);
     }
     ret =
-        PyCObject_FromVoidPtrAndDesc((void *) ctxt,
+        PY_IMPORT_CPTRD((void *) ctxt,
                                      (char *) "xmlParserCtxtPtr", NULL);
     return (ret);
 }
@@ -404,9 +506,9 @@ libxml_xmlXPathObjectPtrWrap(xmlXPathObjectPtr obj)
                     node = obj->nodesetval->nodeTab[i];
                     if (node->type == XML_NAMESPACE_DECL) {
                        PyObject *ns =
-                           PyCObject_FromVoidPtrAndDesc((void *) node,
+          PY_IMPORT_CPTRD((void *) node,
                                      (char *) "xmlNsPtr",
-                                    libxml_xmlXPathDestructNsNode);
+             libxml_xmlXPathDestructNsNode);
                        PyList_SetItem(ret, i, ns);
                        /* make sure the xmlNsPtr is not destroyed now */
                        obj->nodesetval->nodeTab[i] = NULL;
@@ -417,13 +519,13 @@ libxml_xmlXPathObjectPtrWrap(xmlXPathObjectPtr obj)
             }
             break;
         case XPATH_BOOLEAN:
-            ret = PyInt_FromLong((long) obj->boolval);
+            ret = PY_IMPORT_INT((long) obj->boolval);
             break;
         case XPATH_NUMBER:
             ret = PyFloat_FromDouble(obj->floatval);
             break;
         case XPATH_STRING:
-            ret = PyString_FromString((char *) obj->stringval);
+            ret = PY_IMPORT_STRING((char *) obj->stringval);
             break;
         case XPATH_POINT:
         case XPATH_RANGE:
@@ -453,11 +555,9 @@ libxml_xmlXPathObjectPtrConvert(PyObject * obj)
     if PyFloat_Check
         (obj) {
         ret = xmlXPathNewFloat((double) PyFloat_AS_DOUBLE(obj));
-    } else if PyInt_Check(obj) {
-
-        ret = xmlXPathNewFloat((double) PyInt_AS_LONG(obj));
-
-    } else if PyBool_Check (obj) {
+    } else if (PY_IMPORT_LONG_CHECK (obj)) {
+        ret = xmlXPathNewFloat((double) PY_IMPORT_AS_LONG(obj));
+    } else if (PyBool_Check (obj)) {
 
         if (obj == Py_True) {
           ret = xmlXPathNewBoolean(1);
@@ -465,16 +565,13 @@ libxml_xmlXPathObjectPtrConvert(PyObject * obj)
         else {
           ret = xmlXPathNewBoolean(0);
         }
-
-    } else if PyString_Check
-        (obj) {
+    } else if (PY_IMPORT_STRING_CHECK(obj)) {
         xmlChar *str;
 
-        str = xmlStrndup((const xmlChar *) PyString_AS_STRING(obj),
-                         PyString_GET_SIZE(obj));
+        str = xmlStrndup((const xmlChar *) PY_IMPORT_AS_STRING(obj),
+                         PY_IMPORT_STRING_GET_SIZE(obj));
         ret = xmlXPathWrapString(str);
-    } else if PyList_Check
-        (obj) {
+    } else if (PyList_Check(obj)) {
         int i;
         PyObject *node;
         xmlNodePtr cur;
@@ -488,17 +585,29 @@ libxml_xmlXPathObjectPtrConvert(PyObject * obj)
                 continue;
 
             cur = NULL;
-            if (PyCObject_Check(node)) {
+            if (PY_IMPORT_CPTR_CHECK(node)) {
 #ifdef DEBUG
                 printf("Got a CObject\n");
 #endif
                 cur = PyxmlNode_Get(node);
-            } else if (PyInstance_Check(node)) {
+          }
+#if PY_MAJOR_VERSION >= 3
+            else if ((PyObject_HasAttrString(node, (char *) "_o")) &&
+                            (PyObject_HasAttrString(node, (char *) "get_doc"))) {
+                               PyObject *wrapper;
+
+                               wrapper = PyObject_GetAttrString(node, (char *) "_o");
+                               if (wrapper != NULL)
+                                       cur = PyxmlNode_Get(wrapper);
+                    }
+#else
+             else if (PyInstance_Check(node)) {
                 PyInstanceObject *inst = (PyInstanceObject *) node;
                 PyObject *name = inst->in_class->cl_name;
 
                 if PyString_Check
                     (name) {
+
                     char *type = PyString_AS_STRING(name);
                     PyObject *wrapper;
 
@@ -509,8 +618,10 @@ libxml_xmlXPathObjectPtrConvert(PyObject * obj)
                             cur = PyxmlNode_Get(wrapper);
                         }
                     }
-                    }
-            } else {
+                  }
+                }
+#endif
+             else {
 #ifdef DEBUG
                 printf("Unknown object in Python return list\n");
 #endif
@@ -542,7 +653,7 @@ libxml_xmlCatalogPtrWrap(xmlCatalogPtr catal)
         return (Py_None);
     }
     ret =
-        PyCObject_FromVoidPtrAndDesc((void *) catal,
+        PY_IMPORT_CPTRD((void *) catal,
                                      (char *) "xmlCatalogPtr", NULL);
     return (ret);
 }
@@ -560,8 +671,9 @@ libxml_xmlOutputBufferPtrWrap(xmlOutputBufferPtr buffer)
         return (Py_None);
     }
     ret =
-        PyCObject_FromVoidPtrAndDesc((void *) buffer,
+        PY_IMPORT_CPTRD((void *) buffer,
                                      (char *) "xmlOutputBufferPtr", NULL);
+
     return (ret);
 }
 
@@ -578,8 +690,9 @@ libxml_xmlParserInputBufferPtrWrap(xmlParserInputBufferPtr buffer)
         return (Py_None);
     }
     ret =
-        PyCObject_FromVoidPtrAndDesc((void *) buffer,
+        PY_IMPORT_CPTRD((void *) buffer,
                                      (char *) "xmlParserInputBufferPtr", NULL);
+
     return (ret);
 }
 
@@ -596,7 +709,8 @@ libxml_xmlRegexpPtrWrap(xmlRegexpPtr regexp)
         return (Py_None);
     }
     ret =
-        PyCObject_FromVoidPtrAndDesc((void *) regexp,
+        PY_IMPORT_CPTRD((void *) regexp,
                                      (char *) "xmlRegexpPtr", NULL);
+
     return (ret);
 }


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