]> git.saurik.com Git - wxWidgets.git/blobdiff - wxPython/distrib/build_renamers.py
added tech note about writing unit tests
[wxWidgets.git] / wxPython / distrib / build_renamers.py
index 03f043a8d60e8b86ce2536fece78a6ffc3ebd816..e99acb3a8f14aff093a628c46c744bed92a7fd42 100755 (executable)
@@ -1,12 +1,12 @@
 #!/usr/bin/env python
 #---------------------------------------------------------------------------
 """
-Usage:  build_renamers.py filename.i
+Usage:  build_renamers.py destdir modulename filename.xml
 
-Run SWIG on file.i using the XML language module and then scan the XML
-file produced and generate the %rename directives needed to implement
-the new wx namespace.  The rename directives are output in a file
-named _filename_rename.i in the same dir as filename.i.
+Scans the XML file produced by SWIG (see setup.py) and generate the
+%rename directives needed to implement the new wx namespace.  The
+rename directives are output in a file named _modulename_rename.i in
+the destdir given.
 
 Also output a reverse 'renamer' Python module located in
 wxPython/filename.py (relative the the current dir) to make a
@@ -14,37 +14,25 @@ backwards compatibility interface for the old wxPython packages.
 """
 
 import sys, os, tempfile, pprint
-import xml.sax
+import xml.sax            
 from distutils.spawn import spawn
 
-
-
-#---------------------------------------------------------------------------
-
-DO_UNLINK = True
+try:
+    import libxml2
+    USE_LIBXML2 = True
+except ImportError:
+    USE_LIBXML2 = False
 
 wxPythonDir = "wxPython"
-swig_cmd = "/opt/swig/bin/swig"
-if os.name == 'nt':
-    swig_cmd = 'e:/projects/SWIG-cvs/swig.exe'
 
-swig_args = ['-c++',
-             '-Wall',
-             '-nodefault',
-
-             '-xml',
-             '-xmllite',
-
-             '-I./src',
-             '-noruntime'
-             ]
+#---------------------------------------------------------------------------
 
 
 renamerTemplateStart = """\
 // A bunch of %%rename directives generated by %s
 // in order to remove the wx prefix from all global scope names.
 
-#ifndef SWIGXML
+#ifndef BUILDING_RENAMERS
 
 """
 
@@ -86,7 +74,7 @@ wxPythonTemplateEnd = """
 
 def main(args):
     # check args
-    if len(args) < 1:
+    if len(args) < 3:
         print __doc__
         sys.exit(1)
 
@@ -97,69 +85,149 @@ def main(args):
         sys.exit(1)
         
 
-    source = args[0]
-    sourcePath, sourceBase = os.path.split(source)
-    sourceBase = os.path.splitext(sourceBase)[0]
-
-    tempfile.tempdir = sourcePath
-    xmlDest = tempfile.mktemp('.xml')
-    swigDest = os.path.join(sourcePath, "_"+sourceBase+"_rename.i")
-    pyDest = os.path.join(wxPythonDir, sourceBase + '.py')
-
-    #print "source:      ", source
-    #print "xmlDest:     ", xmlDest
-    #print "swigDest:    ", swigDest
-    #print "pyDest:      ", pyDest
-
-    cmd = [ swig_cmd ] + swig_args + args[1:] + ['-I'+sourcePath, '-o', xmlDest, source]
-    print ' '.join(cmd)
-    spawn(cmd)
+    destdir = args[0]
+    modname = args[1]
+    xmlfile = args[2]
+    
+    swigDest = os.path.join(destdir, "_"+modname+"_rename.i")
+    pyDest = os.path.join(wxPythonDir, modname + '.py')
 
     swigDestTemp = tempfile.mktemp('.tmp')
     swigFile = open(swigDestTemp, "w")
     swigFile.write(renamerTemplateStart % sys.argv[0])
 
-    pyFile = open(pyDest, "w")
-    pyFile.write(wxPythonTemplateStart % (sys.argv[0], sourceBase))
-    
-    print "Parsing and building renamers", 
+    pyDestTemp = tempfile.mktemp('.tmp')
+    pyFile = open(pyDestTemp, "w")
+    pyFile.write(wxPythonTemplateStart % (sys.argv[0], modname))
+
     try:
-##         try:
-##             import libxml2
-##             print "using libxml2..."
-##             ctxt = libxml2.createPushParser(ContentHandler(source, sourceBase, swigFile, pyFile),
-##                                             '', 0, xmlDest)
-##             for line in file(xmlDest):
-##                 if not line:
-##                     ctxt.parseChunck('', 0, 1)
-##                     break
-##                 ctxt.parseChunk(line, len(line), 0)
-                
-##         except ImportError:
-        print "using xml.sax..."
-        xml.sax.parse(xmlDest, ContentHandler(source, sourceBase, swigFile, pyFile))
+        print "Parsing and building renamers", 
+        if USE_LIBXML2:
+            processXML(xmlfile, modname, swigFile, pyFile)
+        else:
+            print "using xml.sax..."
+            xml.sax.parse(xmlfile, ContentHandler(modname, swigFile, pyFile))
 
     finally:
-        checkOtherNames(pyFile, sourceBase,
-                        os.path.join(sourcePath, '_'+sourceBase+'_reverse.txt'))
+
+        checkOtherNames(pyFile, modname,
+                        os.path.join(destdir, '_'+modname+'_reverse.txt'))
         pyFile.write(wxPythonTemplateEnd)        
         pyFile.close()
 
         swigFile.write(renamerTemplateEnd)
         swigFile.close()
 
-        # Compare the file just created with the existing one and
+        # Compare the files just created with the existing one and
         # blow away the old one if they are different.
-        if open(swigDest).read() != open(swigDestTemp).read():
-            os.unlink(swigDest)
-            os.rename(swigDestTemp, swigDest)
-        else:
-            print swigDest + " not changed."
-            os.unlink(swigDestTemp)
+        for dest, temp in [(swigDest, swigDestTemp),
+                           (pyDest, pyDestTemp)]:
+            if not os.path.exists(dest):
+                os.rename(temp, dest)
+            elif open(dest).read() != open(temp).read():
+                os.unlink(dest)
+                os.rename(temp, dest)
+            else:
+                print dest + " not changed."
+                os.unlink(temp)
+
+#---------------------------------------------------------------------------
+
+
+def GetAttr(node, name):
+    path = "./attributelist/attribute[@name='%s']/@value" % name
+    n = node.xpathEval2(path)
+    if len(n):
+        return n[0].content
+    else:
+        return None
+    
+
+def processXML(xmlfile, modname, swigFile, pyFile):
+    import libxml2
+    print "using libxml2..."
+
+    topnode = libxml2.parseFile(xmlfile).children
+
+    # remove any import nodes as we don't need to do renamers for symbols found therein
+    imports = topnode.xpathEval2("*/import")
+    for n in imports:
+        n.unlinkNode()
+        n.freeNode()
+
+    # do a depth first iteration over what's left
+    for node in topnode:
+        doRename = False
+        doPtr = False
+        addWX = False
+        revOnly = False
 
-        if DO_UNLINK:
-            os.unlink(xmlDest)
 
+        if node.name == "class":
+            lastClassName = name = GetAttr(node, "name")
+            lastClassSymName = sym_name = GetAttr(node, "sym_name")
+            doRename = True
+            doPtr = True
+            if sym_name != name:
+                name = sym_name
+                addWX = True
+
+        # renamed constructors
+        elif node.name == "constructor":
+            name     = GetAttr(node, "name")
+            sym_name = GetAttr(node, "sym_name")
+            if sym_name != name:
+                name = sym_name
+                addWX = True
+                doRename = True
+
+        # only enumitems at the top level
+        elif node.name == "enumitem" and node.parent.parent.name == "include":
+            name     = GetAttr(node, "name")
+            sym_name = GetAttr(node, "sym_name")
+            doRename = True
+
+
+        elif node.name in ["cdecl", "constant"]:
+            name      = GetAttr(node, "name")
+            sym_name  = GetAttr(node, "sym_name")
+            toplevel  = node.parent.name == "include"
+
+            # top-level functions
+            if toplevel and GetAttr(node, "view") == "globalfunctionHandler":
+                doRename = True
+
+            # top-level global vars
+            elif toplevel and GetAttr(node, "feature_immutable") == "1":
+                doRename = True
+
+            # static methods
+            elif GetAttr(node, "view") == "staticmemberfunctionHandler":
+                name     = lastClassName + '_' + name
+                sym_name = lastClassSymName + '_' + sym_name
+                # only output the reverse renamer in this case
+                doRename = revOnly = True
+       
+            if doRename and name != sym_name:
+                name = sym_name
+                addWX = True
+               
+
+        if doRename and name:
+            old = new = name
+            if old.startswith('wx') and not old.startswith('wxEVT_'):
+                # remove all wx prefixes except wxEVT_ and write a %rename directive for it
+                new = old[2:]
+                if not revOnly:
+                    swigFile.write("%%rename(%s)  %35s;\n" % (new, old))
+
+            # Write assignments to import into the old wxPython namespace
+            if addWX and not old.startswith('wx'):
+                old = 'wx'+old
+            pyFile.write("%s = wx.%s.%s\n" % (old, modname, new))
+            if doPtr:
+                pyFile.write("%sPtr = wx.%s.%sPtr\n" % (old, modname, new))
+            
 
 #---------------------------------------------------------------------------
 
@@ -304,10 +372,9 @@ class Element:
 #---------------------------------------------------------------------------
 
 class ContentHandler(xml.sax.ContentHandler):
-    def __init__(self, source, sourceBase, swigFile, pyFile):
+    def __init__(self, modname, swigFile, pyFile):
         xml.sax.ContentHandler.__init__(self)
-        self.source = source
-        self.sourceBase = sourceBase
+        self.modname = modname
         self.swigFile = swigFile
         self.pyFile   = pyFile
         self.elements = []
@@ -398,7 +465,7 @@ class ContentHandler(xml.sax.ContentHandler):
             
             if self.imports == 0:
                 # only write for items that are in this file, not imported
-                ce.write(self.sourceBase, self.swigFile, self.pyFile)
+                ce.write(self.modname, self.swigFile, self.pyFile)
             
         if name == 'import':
             self.imports -= 1