added more informations in the libxml2-python package including docs.

* configure.in libxml.spec.in python/Makefile.am python/TODO
  python/generator.py python/libxml2class.txt: added more informations
  in the libxml2-python package including docs. Slightly changed
  the class hierarchy
* python/tests/*: added basic regression tests infrastructure too
Daniel
diff --git a/python/Makefile.am b/python/Makefile.am
index 158f149..43bc4b0 100644
--- a/python/Makefile.am
+++ b/python/Makefile.am
@@ -1,19 +1,25 @@
+SUBDIRS= . tests
+
 LIBS=-L../.libs -L.. $(XML_LIBS)
-INCLUDES=-I$(PYTHON_INCLUDES) -I$(top_srcdir)/include
+INCLUDES=-I/usr/include/python$(PYTHON_VERSION) -I$(PYTHON_INCLUDES) -I$(top_srcdir)/include
 SHCFLAGS=$(INCLUDES) -Wall -fPIC
 LINK_FLAGS= -shared
+DOCS_DIR = $(prefix)/share/doc/libxml2-python-$(LIBXML_VERSION)
+
+DOCS = TODO libxml2class.txt
 
 EXTRA_DIST = \
 	libxml.c	\
 	generator.py	\
 	libxml_wrap.h	\
-	libxml.py
+	libxml.py	\
+	$(DOCS)
 
 if WITH_PYTHON
 all: _libxml.so libxml2.py
 
-libxml2.py: libxml.py libxml2class.py
-	cat libxml.py libxml2class.py > libxml2.py
+libxml2.py: $(srcdir)/libxml.py libxml2class.py
+	cat $(srcdir)/libxml.py libxml2class.py > libxml2.py
 
 _libxml.so: libxml.o libxml2-py.o
 	$(CC) $(LINK_FLAGS) libxml2-py.o libxml.o $(LIBS) -o _libxml.so
@@ -39,3 +45,12 @@
 
 clean:
 	rm -f $(GENERATED) *.o _libxml.so *.pyc libxml2.py
+
+install-data-local:
+	$(mkinstalldirs) $(DESTDIR)$(PYTHON_SITE_PACKAGES)
+	-@INSTALL@ -m 0644 libxml2.py $(DESTDIR)$(PYTHON_SITE_PACKAGES)
+	-@INSTALL@ -m 0755 _libxml.so $(DESTDIR)$(PYTHON_SITE_PACKAGES)
+	$(mkinstalldirs) $(DESTDIR)$(DOCS_DIR)
+	-@(for doc in $(DOCS) ; \
+	   do @INSTALL@ -m 0644 $$doc $(DESTDIR)$(DOCS_DIR) ; done)
+
diff --git a/python/TODO b/python/TODO
new file mode 100644
index 0000000..b1fa734
--- /dev/null
+++ b/python/TODO
@@ -0,0 +1,41 @@
+             TODO for the libxml2 Python wrappers
+
+               $Id$
+
+Things to do:
+-------------
+
+- handling of node.content
+- SAX interfaces
+- error redirections and preformat
+- class hierarchy:
+  + get the generator to output a classes.txt description
+- extensions based on a python.xml description of the new specific
+  interfaces
+- memory debug interfaces
+- enums -> libxml.py
+- spec file: automatically generate for pythonX.Y if found
+- access to XPath variables
+- parserCtxt exposure:
+  - entry points
+  - wrappers
+  - decent interface for setting/getting behaviour
+- xmlBuffer exposure
+- xpathContext, being able to set/get info and clean it up
+- add regression tests
+   - check memory
+   - build tree
+   - saving
+   - SAX flow
+
+
+Done:
+-----
+- class hierarchy:
+  + make specific node type inherit from xmlNode
+- add regression tests
+   - tests/Makefile.am: export the Python class path
+   - xpath queries
+   - xpath extension
+
+Daniel Veillard
diff --git a/python/generator.py b/python/generator.py
index 13a5ae7..ee477b0 100755
--- a/python/generator.py
+++ b/python/generator.py
@@ -210,11 +210,11 @@
     'double':  ('d', None, "double", "double"),
     'unsigned int':  ('i', None, "int", "int"),
     'xmlChar':  ('c', None, "int", "int"),
-    'unsigned char *':  ('s', None, "charPtr", "char *"),
-    'char *':  ('s', None, "charPtr", "char *"),
-    'const char *':  ('s', None, "charPtr", "char *"),
-    'xmlChar *':  ('s', None, "xmlCharPtr", "xmlChar *"),
-    'const xmlChar *':  ('s', None, "xmlCharPtr", "xmlChar *"),
+    'unsigned char *':  ('z', None, "charPtr", "char *"),
+    'char *':  ('z', None, "charPtr", "char *"),
+    'const char *':  ('z', None, "charPtr", "char *"),
+    'xmlChar *':  ('z', None, "xmlCharPtr", "xmlChar *"),
+    'const xmlChar *':  ('z', None, "xmlCharPtr", "xmlChar *"),
     'xmlNodePtr':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
     'const xmlNodePtr':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
     'xmlNode *':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
@@ -465,13 +465,13 @@
 
 classes_ancestor = {
     "xmlNode" : "xmlCore",
-    "xmlDoc" : "xmlCore",
-    "xmlAttr" : "xmlCore",
-    "xmlNs" : "xmlCore",
-    "xmlDtd" : "xmlCore",
-    "xmlEntity" : "xmlCore",
-    "xmlElement" : "xmlCore",
-    "xmlAttribute" : "xmlCore",
+    "xmlDtd" : "xmlNode",
+    "xmlDoc" : "xmlNode",
+    "xmlAttr" : "xmlNode",
+    "xmlNs" : "xmlNode",
+    "xmlEntity" : "xmlNode",
+    "xmlElement" : "xmlNode",
+    "xmlAttribute" : "xmlNode",
 }
 classes_destructors = {
     "xpathContext": "xmlXPathFreeContext",
@@ -574,6 +574,8 @@
     function_classes['None'].append(info)
 
 classes = open("libxml2class.py", "w")
+txt = open("libxml2class.txt", "w")
+txt.write("          Generated Classes for libxml2-python\n\n")
 
 def functionCompare(info1, info2):
     (index1, func1, name1, ret1, args1, file1) = info1
@@ -608,6 +610,7 @@
      output.write(val);
      output.write('"""\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)
@@ -616,8 +619,10 @@
 	(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:
@@ -650,11 +655,14 @@
 		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 function_classes.keys():
     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")
@@ -662,6 +670,7 @@
 	    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")
 	    classes.write("        if _obj != None:self._o = _obj;return\n")
@@ -685,9 +694,11 @@
 		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:
@@ -727,4 +738,5 @@
 		    classes.write("        return ret\n");
 	    classes.write("\n");
 
+txt.close()
 classes.close()
diff --git a/python/libxml2class.txt b/python/libxml2class.txt
new file mode 100644
index 0000000..c8e2359
--- /dev/null
+++ b/python/libxml2class.txt
@@ -0,0 +1,330 @@
+          Generated Classes for libxml2-python
+
+#
+# Global functions of the module
+#
+
+
+# functions from module HTMLparser
+htmlHandleOmittedElem()
+htmlIsScriptAttribute()
+htmlParseDoc()
+htmlParseFile()
+
+# functions from module HTMLtree
+htmlNewDoc()
+htmlNewDocNoDtD()
+
+# functions from module catalog
+catalogAdd()
+catalogCleanup()
+catalogConvert()
+catalogGetPublic()
+catalogGetSystem()
+catalogRemove()
+catalogResolve()
+catalogResolvePublic()
+catalogResolveSystem()
+catalogResolveURI()
+catalogSetDebug()
+initializeCatalog()
+loadCatalog()
+loadCatalogs()
+parseCatalogFile()
+
+# functions from module debugXML
+shellPrintXPathError()
+
+# functions from module encoding
+UTF8Strlen()
+UTF8Strloc()
+UTF8Strndup()
+UTF8Strpos()
+UTF8Strsize()
+UTF8Strsub()
+addEncodingAlias()
+checkUTF8()
+cleanupCharEncodingHandlers()
+cleanupEncodingAliases()
+delEncodingAlias()
+encodingAlias()
+initCharEncodingHandlers()
+
+# functions from module entities
+cleanupPredefinedEntities()
+initializePredefinedEntities()
+predefinedEntity()
+
+# functions from module nanoftp
+nanoFTPCleanup()
+nanoFTPInit()
+nanoFTPProxy()
+nanoFTPScanProxy()
+
+# functions from module nanohttp
+nanoHTTPCleanup()
+nanoHTTPInit()
+nanoHTTPScanProxy()
+
+# functions from module parser
+cleanupParser()
+defaultSAXHandlerInit()
+htmlDefaultSAXHandlerInit()
+initParser()
+keepBlanksDefault()
+lineNumbersDefault()
+parseDTD()
+parseDoc()
+parseEntity()
+parseFile()
+parseMemory()
+pedanticParserDefault()
+recoverDoc()
+recoverFile()
+recoverMemory()
+substituteEntitiesDefault()
+
+# functions from module parserInternals
+checkLanguageID()
+copyChar()
+copyCharMultiByte()
+htmlInitAutoClose()
+isBaseChar()
+isBlank()
+isChar()
+isCombining()
+isDigit()
+isExtender()
+isIdeographic()
+isLetter()
+isPubidChar()
+
+# functions from module tree
+compressMode()
+newComment()
+newDoc()
+newPI()
+newText()
+newTextLen()
+setCompressMode()
+
+# functions from module uri
+URIEscape()
+URIEscapeStr()
+URIUnescapeString()
+buildURI()
+normalizeURIPath()
+
+# functions from module xmlIO
+cleanupInputCallbacks()
+cleanupOutputCallbacks()
+parserGetDirectory()
+registerDefaultInputCallbacks()
+registerDefaultOutputCallbacks()
+registerHTTPPostCallbacks()
+
+# functions from module xmlversion
+checkVersion()
+
+
+#
+# Set of classes of the module
+#
+
+Class xpathContext()
+
+    # functions from module xpath
+    xpathEval()
+    xpathEvalExpression()
+
+    # functions from module xpathInternals
+    xpathFreeContext()
+    xpathNsLookup()
+    xpathRegisterAllFunctions()
+    xpathRegisterNs()
+    xpathRegisteredFuncsCleanup()
+    xpathRegisteredNsCleanup()
+    xpathRegisteredVariablesCleanup()
+    xpathVariableLookup()
+    xpathVariableLookupNS()
+
+
+Class xmlDoc(xmlNode)
+
+    # functions from module HTMLparser
+    htmlAutoCloseTag()
+    htmlIsAutoClosed()
+
+    # functions from module HTMLtree
+    htmlGetMetaEncoding()
+    htmlSaveFile()
+    htmlSaveFileEnc()
+    htmlSaveFileFormat()
+    htmlSetMetaEncoding()
+
+    # functions from module entities
+    addDocEntity()
+    addDtdEntity()
+    docEntity()
+    dtdEntity()
+    encodeEntities()
+    encodeEntitiesReentrant()
+    encodeSpecialChars()
+    parameterEntity()
+
+    # functions from module tree
+    copyDoc()
+    createIntSubset()
+    docCompressMode()
+    freeDoc()
+    getRootElement()
+    intSubset()
+    newCDataBlock()
+    newCharRef()
+    newDocComment()
+    newDocFragment()
+    newDocNode()
+    newDocProp()
+    newDocRawNode()
+    newDocText()
+    newDocTextLen()
+    newDtd()
+    newGlobalNs()
+    newReference()
+    saveFile()
+    saveFileEnc()
+    saveFormatFile()
+    saveFormatFileEnc()
+    setDocCompressMode()
+    stringGetNodeList()
+    stringLenGetNodeList()
+
+    # functions from module valid
+    ID()
+    isMixedElement()
+    removeID()
+    removeRef()
+
+    # functions from module xinclude
+    xincludeProcess()
+
+    # functions from module xpathInternals
+    xpathNewContext()
+
+
+Class xmlNode(xmlCore)
+
+    # functions from module debugXML
+    lsCountNode()
+    shellPrintNode()
+
+    # functions from module tree
+    addChild()
+    addChildList()
+    addContent()
+    addContentLen()
+    addNextSibling()
+    addPrevSibling()
+    addSibling()
+    copyNode()
+    copyNodeList()
+    copyProp()
+    copyPropList()
+    docCopyNode()
+    docSetRootElement()
+    freeNode()
+    freeNodeList()
+    getBase()
+    getContent()
+    getLang()
+    getSpacePreserve()
+    hasNsProp()
+    hasProp()
+    isBlankNode()
+    isText()
+    lastChild()
+    lineNo()
+    listGetRawString()
+    listGetString()
+    newChild()
+    newNs()
+    newNsProp()
+    newProp()
+    newTextChild()
+    nodePath()
+    nsProp()
+    prop()
+    reconciliateNs()
+    replaceNode()
+    searchNs()
+    searchNsByHref()
+    setBase()
+    setContent()
+    setContentLen()
+    setLang()
+    setListDoc()
+    setName()
+    setNs()
+    setNsProp()
+    setProp()
+    setSpacePreserve()
+    setTreeDoc()
+    textConcat()
+    textMerge()
+    unlinkNode()
+    unsetNsProp()
+    unsetProp()
+
+    # functions from module valid
+    isID()
+    isRef()
+    validNormalizeAttributeValue()
+
+    # functions from module xpath
+    xpathCastNodeToNumber()
+    xpathCastNodeToString()
+    xpathCmpNodes()
+
+    # functions from module xpathInternals
+    xpathNewNodeSet()
+    xpathNewValueTree()
+
+
+Class xmlAttribute(xmlNode)
+
+
+Class xmlDtd(xmlNode)
+
+    # functions from module tree
+    copyDtd()
+    freeDtd()
+
+    # functions from module valid
+    dtdAttrDesc()
+    dtdElementDesc()
+    dtdQAttrDesc()
+    dtdQElementDesc()
+
+
+Class xmlAttr(xmlNode)
+
+    # functions from module tree
+    freeProp()
+    freePropList()
+    removeProp()
+
+
+Class xmlEntity(xmlNode)
+
+
+Class xmlElement(xmlNode)
+
+
+Class xmlNs(xmlNode)
+
+    # functions from module tree
+    copyNamespace()
+    copyNamespaceList()
+    freeNs()
+    freeNsList()
+    newNode()
diff --git a/python/tests/Makefile.am b/python/tests/Makefile.am
new file mode 100644
index 0000000..366ad06
--- /dev/null
+++ b/python/tests/Makefile.am
@@ -0,0 +1,26 @@
+EXAMPLE_DIR = $(prefix)/share/doc/libxml2-python-$(LIBXML_VERSION)/examples
+
+TESTS=		\
+    tst.py	\
+    tstxpath.py	\
+    xpathext.py	\
+    xpath.py
+
+XMLS=		\
+    tst.xml
+
+EXTRA_DIST = $(TESTS) $(XMLS)
+
+if WITH_PYTHON
+tests: $(TESTS)
+	-@(CLASSPATH=".." ; export CLASSPATH; \
+	   for test in $(TESTS) ; do echo "-- $$test" ; $(PYTHON) $$test ; done)
+else
+tests:
+endif
+
+install-data-local:
+	$(mkinstalldirs) $(DESTDIR)$(EXAMPLE_DIR)
+	-(for test in $(TESTS) $(XMLS); \
+	  do @INSTALL@ -m 0644 $$test $(DESTDIR)$(EXAMPLE_DIR) ; done)
+
diff --git a/python/tests/tst.py b/python/tests/tst.py
new file mode 100755
index 0000000..86ac64b
--- /dev/null
+++ b/python/tests/tst.py
@@ -0,0 +1,10 @@
+#!/usr/bin/python -u
+import libxml2
+
+doc = libxml2.parseFile("tst.xml")
+print doc.name
+root = doc.children
+print root.name
+child = root.children
+print child.name
+doc.freeDoc()
diff --git a/python/tests/tst.xml b/python/tests/tst.xml
new file mode 100644
index 0000000..751d46d
--- /dev/null
+++ b/python/tests/tst.xml
@@ -0,0 +1 @@
+<doc><foo>bar</foo></doc>
diff --git a/python/tests/tstxpath.py b/python/tests/tstxpath.py
new file mode 100755
index 0000000..f6c675a
--- /dev/null
+++ b/python/tests/tstxpath.py
@@ -0,0 +1,29 @@
+#!/usr/bin/python -u
+import libxml2
+
+def foo(x):
+    # print "foo called %s" % (x)
+    return x + 1
+
+def bar(x):
+    # print "foo called %s" % (x)
+    return "%s" % (x + 1)
+
+doc = libxml2.parseFile("tst.xml")
+ctxt = doc.xpathNewContext()
+res = ctxt.xpathEval("//*")
+print res
+
+libxml2.registerXPathFunction(ctxt._o, "foo", None, foo)
+libxml2.registerXPathFunction(ctxt._o, "bar", None, bar)
+i = 10000
+while i > 0:
+    res = ctxt.xpathEval("foo(1)")
+    i = i - 1
+print res
+i = 10000
+while i > 0:
+    res = ctxt.xpathEval("bar(1)")
+    i = i - 1
+print res
+doc.freeDoc()
diff --git a/python/tests/xpath.py b/python/tests/xpath.py
new file mode 100755
index 0000000..fdbd839
--- /dev/null
+++ b/python/tests/xpath.py
@@ -0,0 +1,21 @@
+#!/usr/bin/python -u
+#
+# this test exercise the XPath basic engine, parser, etc, and
+# allows to detect memory leaks
+#
+import libxml2
+
+doc = libxml2.parseFile("tst.xml")
+print doc
+i = 1000
+while i > 0:
+    doc = libxml2.parseFile("tst.xml")
+    ctxt = doc.xpathNewContext()
+    res = ctxt.xpathEval("//*")
+    doc.freeDoc()
+    i = i -1
+doc = libxml2.parseFile("tst.xml")
+ctxt = doc.xpathNewContext()
+res = ctxt.xpathEval("//*")
+print res
+doc.freeDoc()
diff --git a/python/tests/xpathext.py b/python/tests/xpathext.py
new file mode 100755
index 0000000..d6f0455
--- /dev/null
+++ b/python/tests/xpathext.py
@@ -0,0 +1,33 @@
+#!/usr/bin/python -u
+#
+# This test exercise the extension of the XPath engine with
+# functions defined in Python.
+#
+import libxml2
+
+def foo(x):
+    # print "foo called %s" % (x)
+    return x + 1
+
+def bar(x):
+    # print "foo called %s" % (x)
+    return "%s" % (x + 1)
+
+doc = libxml2.parseFile("tst.xml")
+ctxt = doc.xpathNewContext()
+res = ctxt.xpathEval("//*")
+print res
+
+libxml2.registerXPathFunction(ctxt._o, "foo", None, foo)
+libxml2.registerXPathFunction(ctxt._o, "bar", None, bar)
+i = 10000
+while i > 0:
+    res = ctxt.xpathEval("foo(1)")
+    i = i - 1
+print res
+i = 10000
+while i > 0:
+    res = ctxt.xpathEval("bar(1)")
+    i = i - 1
+print res
+doc.freeDoc()