2003-12-23 12:45:54 -05:00
|
|
|
#!/usr/bin/python
|
|
|
|
#---------------------------------------------------------------------------
|
|
|
|
#
|
|
|
|
# Like simplify.xsl but using Python so a few non-standard conversions can
|
|
|
|
# also be done. (Currently it is still about the same as simplify.xsl...)
|
|
|
|
#
|
|
|
|
#---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
import sys
|
|
|
|
import os
|
|
|
|
import libxml2
|
|
|
|
|
|
|
|
|
|
|
|
DEST="docs/xml/wxPython-metadata.xml"
|
|
|
|
SRC="docs/xml-raw"
|
|
|
|
|
|
|
|
|
2003-12-31 15:49:08 -05:00
|
|
|
classMap = {
|
|
|
|
'wxString' : 'String',
|
|
|
|
'void' : '',
|
|
|
|
}
|
|
|
|
|
2003-12-23 12:45:54 -05:00
|
|
|
|
|
|
|
def getModuleNames():
|
|
|
|
"""
|
|
|
|
Get the list of extension modules from setup.py
|
|
|
|
"""
|
|
|
|
import setup
|
|
|
|
names = [e.name[1:] for e in setup.wxpExtensions]
|
|
|
|
return names
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def getAttr(node, name):
|
|
|
|
"""
|
|
|
|
Get a value by name from the <attribute> elements in the SWIG XML output
|
|
|
|
"""
|
|
|
|
path = "./attributelist/attribute[@name='%s']/@value" % name
|
|
|
|
n = node.xpathEval2(path)
|
|
|
|
if len(n):
|
|
|
|
return n[0].content
|
|
|
|
else:
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
2003-12-31 15:49:08 -05:00
|
|
|
def fixType(typeStr):
|
|
|
|
"""
|
|
|
|
Fixup type string, dropping the swig pointer and other flags
|
|
|
|
"""
|
|
|
|
pos = typeStr.rfind('.')
|
|
|
|
if pos != -1:
|
|
|
|
typeStr = typeStr[pos+1:]
|
|
|
|
return classMap.get(typeStr, typeStr)
|
2003-12-23 12:45:54 -05:00
|
|
|
|
|
|
|
|
|
|
|
def processModule(newDocNode, modulename):
|
|
|
|
"""
|
|
|
|
Start processing a new XML file, create a module element and then
|
|
|
|
find the include elements
|
|
|
|
"""
|
|
|
|
filename = os.path.join(SRC, "%s_swig.xml" % modulename)
|
|
|
|
print filename
|
|
|
|
|
|
|
|
doc = libxml2.parseFile(filename)
|
|
|
|
topNode = doc.getRootElement()
|
|
|
|
|
|
|
|
# make a module element
|
|
|
|
name = getAttr(topNode, "module")
|
2004-06-09 01:43:02 -04:00
|
|
|
##assert name == modulename # sanity check
|
2003-12-23 12:45:54 -05:00
|
|
|
|
|
|
|
moduleNode = libxml2.newNode("module")
|
|
|
|
moduleNode.setProp("name", name)
|
|
|
|
newDocNode.addChild(moduleNode)
|
|
|
|
|
|
|
|
node = topNode.children
|
|
|
|
while node is not None:
|
|
|
|
if node.name == "include":
|
2003-12-23 20:09:51 -05:00
|
|
|
processInclude(moduleNode, node)
|
2003-12-23 12:45:54 -05:00
|
|
|
node = node.next
|
|
|
|
|
|
|
|
doc.freeDoc()
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-12-23 20:09:51 -05:00
|
|
|
def processInclude(moduleNode, includeNode):
|
2003-12-23 12:45:54 -05:00
|
|
|
"""
|
|
|
|
Almost everything we are interested in is inside an <include>,
|
|
|
|
which may also be nested.
|
|
|
|
"""
|
|
|
|
|
|
|
|
# check first for imports
|
|
|
|
for node in includeNode.xpathEval2("import"):
|
|
|
|
try:
|
|
|
|
modNode = node.xpathEval2("module")[0]
|
|
|
|
name = getAttr(modNode, "name")
|
|
|
|
impNode = libxml2.newNode("import")
|
|
|
|
impNode.setProp("name", name)
|
|
|
|
moduleNode.addChild(impNode)
|
|
|
|
except IndexError:
|
|
|
|
pass
|
|
|
|
|
|
|
|
# then look through the child nodes for other things we need
|
|
|
|
node = includeNode.children
|
|
|
|
while node is not None:
|
|
|
|
if node.name == "insert":
|
2003-12-23 20:09:51 -05:00
|
|
|
processInsert(moduleNode, node)
|
2003-12-23 12:45:54 -05:00
|
|
|
|
|
|
|
elif node.name == "class":
|
2003-12-23 20:09:51 -05:00
|
|
|
processClass(moduleNode, node)
|
2003-12-23 12:45:54 -05:00
|
|
|
|
|
|
|
elif node.name == "cdecl" and getAttr(node, "view") == "globalfunctionHandler":
|
|
|
|
func = libxml2.newNode("method")
|
|
|
|
func.setProp("name", getAttr(node, "sym_name"))
|
|
|
|
func.setProp("oldname", getAttr(node, "name"))
|
2003-12-31 15:49:08 -05:00
|
|
|
func.setProp("type", fixType(getAttr(node, "type")))
|
2003-12-23 12:45:54 -05:00
|
|
|
doCheckOverloaded(func, node)
|
|
|
|
doDocStrings(func, node)
|
|
|
|
doParamList(func, node)
|
|
|
|
moduleNode.addChild(func)
|
|
|
|
|
|
|
|
|
|
|
|
elif node.name == "include":
|
2003-12-23 20:09:51 -05:00
|
|
|
processInclude(moduleNode, node)
|
2003-12-23 12:45:54 -05:00
|
|
|
|
|
|
|
node = node.next
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-12-23 20:09:51 -05:00
|
|
|
def processInsert(parentNode, insertNode):
|
2003-12-23 12:45:54 -05:00
|
|
|
"""
|
|
|
|
Check for pythoncode
|
|
|
|
"""
|
|
|
|
if getAttr(insertNode, "section") == "python":
|
|
|
|
code = getAttr(insertNode, "code")
|
|
|
|
node = libxml2.newNode("pythoncode")
|
|
|
|
node.addChild(libxml2.newText(code))
|
|
|
|
parentNode.addChild(node)
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-12-23 20:09:51 -05:00
|
|
|
def processClass(parentNode, classNode):
|
2003-12-23 12:45:54 -05:00
|
|
|
"""
|
|
|
|
Handle classes, constructors, methods, etc.
|
|
|
|
"""
|
|
|
|
# make class element
|
|
|
|
klass = libxml2.newNode("class")
|
2003-12-31 15:49:08 -05:00
|
|
|
name = getAttr(classNode, "sym_name")
|
|
|
|
oldname = getAttr(classNode, "name")
|
|
|
|
classMap[oldname] = name
|
|
|
|
klass.setProp("name", name)
|
|
|
|
klass.setProp("oldname", oldname)
|
2003-12-23 12:45:54 -05:00
|
|
|
klass.setProp("module", getAttr(classNode, "module"))
|
|
|
|
doDocStrings(klass, classNode)
|
|
|
|
parentNode.addChild(klass)
|
|
|
|
|
|
|
|
# check for baseclass(es)
|
|
|
|
for node in classNode.xpathEval2("attributelist/baselist/base"):
|
|
|
|
baseclass = libxml2.newNode("baseclass")
|
2003-12-31 15:49:08 -05:00
|
|
|
basename = node.prop("name")
|
|
|
|
baseclass.setProp("name", classMap.get(basename, basename))
|
2003-12-23 12:45:54 -05:00
|
|
|
klass.addChild(baseclass)
|
|
|
|
|
|
|
|
# check for constructors/destructors
|
|
|
|
for type in ["constructor", "destructor"]:
|
|
|
|
for node in classNode.xpathEval2("%s | extend/%s" % (type, type)):
|
|
|
|
func = libxml2.newNode(type)
|
|
|
|
func.setProp("name", getAttr(node, "sym_name"))
|
|
|
|
if parentNode.name != "destructor":
|
|
|
|
doCheckOverloaded(func, node)
|
|
|
|
doDocStrings(func, node)
|
|
|
|
doParamList(func, node)
|
|
|
|
klass.addChild(func)
|
|
|
|
|
|
|
|
# check for cdecl's. In class scope we are interested in methods,
|
|
|
|
# static methods, or properties
|
|
|
|
for node in classNode.xpathEval2("cdecl | extend/cdecl"):
|
|
|
|
view = getAttr(node, "view")
|
|
|
|
if view == "memberfunctionHandler":
|
|
|
|
func = libxml2.newNode("method")
|
|
|
|
func.setProp("name", getAttr(node, "sym_name"))
|
2003-12-31 15:49:08 -05:00
|
|
|
func.setProp("type", fixType(getAttr(node, "type")))
|
2003-12-23 12:45:54 -05:00
|
|
|
doCheckOverloaded(func, node)
|
|
|
|
doDocStrings(func, node)
|
|
|
|
doParamList(func, node)
|
|
|
|
klass.addChild(func)
|
|
|
|
|
|
|
|
elif view == "staticmemberfunctionHandler":
|
|
|
|
func = libxml2.newNode("staticmethod")
|
|
|
|
func.setProp("name", getAttr(node, "sym_name"))
|
2003-12-31 15:49:08 -05:00
|
|
|
func.setProp("type", fixType(getAttr(node, "type")))
|
2003-12-23 12:45:54 -05:00
|
|
|
doCheckOverloaded(func, node)
|
|
|
|
doDocStrings(func, node)
|
|
|
|
doParamList(func, node)
|
|
|
|
klass.addChild(func)
|
|
|
|
|
|
|
|
elif view == "variableHandler":
|
|
|
|
prop = libxml2.newNode("property")
|
|
|
|
prop.setProp("name", getAttr(node, "sym_name"))
|
2003-12-31 15:49:08 -05:00
|
|
|
prop.setProp("type", fixType(getAttr(node, "type")))
|
2003-12-23 12:45:54 -05:00
|
|
|
if getAttr(node, "feature_immutable"):
|
|
|
|
prop.setProp("readonly", "yes")
|
|
|
|
else:
|
|
|
|
prop.setProp("readonly", "no")
|
|
|
|
doDocStrings(prop, node)
|
|
|
|
klass.addChild(prop)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def doParamList(parentNode, srcNode):
|
|
|
|
"""
|
|
|
|
Convert the parameter list
|
|
|
|
"""
|
|
|
|
params = srcNode.xpathEval2("attributelist/parmlist/parm")
|
|
|
|
if params:
|
|
|
|
plist = libxml2.newNode("paramlist")
|
|
|
|
for p in params:
|
|
|
|
pnode = libxml2.newNode("param")
|
2003-12-31 15:49:08 -05:00
|
|
|
pnode.setProp("name", getAttr(p, "name"))
|
|
|
|
pnode.setProp("type", fixType(getAttr(p, "type")))
|
2003-12-23 12:45:54 -05:00
|
|
|
pnode.setProp("default", getAttr(p, "value"))
|
|
|
|
plist.addChild(pnode)
|
|
|
|
parentNode.addChild(plist)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def doCheckOverloaded(parentNode, srcNode):
|
|
|
|
"""
|
|
|
|
Set an attribute indicating if the srcNode is tagged as being overloaded
|
|
|
|
"""
|
|
|
|
if srcNode.xpathEval2("./attributelist/attribute[@name='sym_overloaded']"):
|
|
|
|
parentNode.setProp("overloaded", "yes")
|
|
|
|
else:
|
|
|
|
parentNode.setProp("overloaded", "no")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def doDocStrings(parentNode, srcNode):
|
|
|
|
"""
|
|
|
|
Check for the various possible docstring attributes, and attach
|
|
|
|
coresponding child nodes if found.
|
|
|
|
"""
|
|
|
|
def makeDocElement(name, content):
|
|
|
|
node = libxml2.newNode(name)
|
|
|
|
node.addChild(libxml2.newText(content))
|
|
|
|
return node
|
|
|
|
|
|
|
|
autodoc = getAttr(srcNode, "python_autodoc")
|
|
|
|
docstr = getAttr(srcNode, "feature_docstring")
|
|
|
|
if autodoc:
|
|
|
|
parentNode.addChild(makeDocElement("autodoc", autodoc))
|
|
|
|
if docstr:
|
|
|
|
parentNode.addChild(makeDocElement("docstring", docstr))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
if not os.path.exists(SRC):
|
|
|
|
print "Unable to find %s, please run this script from the root wxPython directory." % SRC
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
newDoc = libxml2.newDoc("1.0")
|
|
|
|
newTopNode = libxml2.newNode("wxPython-metadata")
|
|
|
|
newDoc.addChild(newTopNode)
|
|
|
|
|
|
|
|
for m in getModuleNames():
|
|
|
|
processModule(newTopNode, m)
|
|
|
|
|
|
|
|
newDoc.saveFormatFile(DEST, True)
|
2003-12-31 15:49:08 -05:00
|
|
|
print "Wrote simplified metadata to", DEST
|
2003-12-23 12:45:54 -05:00
|
|
|
|
|
|
|
#---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
main()
|