diff --git a/wxPython/distrib/build_renamers.py b/wxPython/distrib/build_renamers.py index 03f043a8d6..022051b8dc 100755 --- a/wxPython/distrib/build_renamers.py +++ b/wxPython/distrib/build_renamers.py @@ -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,70 +85,148 @@ 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 open(dest).read() != open(temp).read(): + os.unlink(dest) + os.rename(temp, dest) + else: + print dest + " not changed." + os.unlink(temp) - if DO_UNLINK: - os.unlink(xmlDest) +#--------------------------------------------------------------------------- +def GetAttr(node, name): + path = "./attributelist/attribute[@name='%s']/@value" % name + n = node.xpathEval(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.xpathEval("*/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 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: + 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)) + + #--------------------------------------------------------------------------- def checkOtherNames(pyFile, moduleName, filename): @@ -304,10 +370,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 +463,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 diff --git a/wxPython/setup.py b/wxPython/setup.py index 09b44e2192..ba32bc46af 100755 --- a/wxPython/setup.py +++ b/wxPython/setup.py @@ -246,6 +246,9 @@ def run_swig(files, dir, gendir, package, USE_SWIG, force, swig_args, swig_deps= if not os.path.exists(os.path.join(dir, gendir)): os.mkdir(os.path.join(dir, gendir)) + if not os.path.exists(os.path.join("docs", "xml-raw")): + os.mkdir(os.path.join("docs", "xml-raw")) + sources = [] for file in files: @@ -253,6 +256,7 @@ def run_swig(files, dir, gendir, package, USE_SWIG, force, swig_args, swig_deps= i_file = os.path.join(dir, file) py_file = os.path.join(dir, gendir, basefile+'.py') cpp_file = os.path.join(dir, gendir, basefile+'_wrap.cpp') + xml_file = os.path.join("docs", "xml-raw", basefile+'_swig.xml') sources.append(cpp_file) @@ -268,14 +272,28 @@ def run_swig(files, dir, gendir, package, USE_SWIG, force, swig_args, swig_deps= #i_file = opj(i_file) #'/'.join(i_file.split('\\')) if BUILD_RENAMERS: - # first run build_renamers - cmd = [ sys.executable, '-u', - './distrib/build_renamers.py', - i_file, '-D'+WXPLAT, ] + \ - [x for x in swig_args if x.startswith('-I')] + #info_file = "./distrib/swig_info" + #info_dict = { 'cmd' : swig_cmd, + # 'args' : swig_args + ['-I'+dir] + # } + #open(info_file, "w").write(str(args_dict)) + + # First run swig to produce the XML file, adding + # an extra -D that prevents the old rename + # directives from being used + cmd = [ swig_cmd ] + swig_args + \ + [ '-DBUILDING_RENAMERS', '-xmlout', xml_file ] + \ + ['-I'+dir, '-o', cpp_file, i_file] msg(' '.join(cmd)) spawn(cmd) + # Next run build_renamers to process the XML + cmd = [ sys.executable, '-u', + './distrib/build_renamers.py', dir, basefile, xml_file] + msg(' '.join(cmd)) + spawn(cmd) + #os.remove(info_file) + # Then run swig for real cmd = [ swig_cmd ] + swig_args + ['-I'+dir, '-o', cpp_file, i_file] msg(' '.join(cmd))