]> git.saurik.com Git - wxWidgets.git/blob - wxPython/docs/bin/simplify.py
build a tarball when building the new docs
[wxWidgets.git] / wxPython / docs / bin / simplify.py
1 #!/usr/bin/python
2 #---------------------------------------------------------------------------
3 #
4 # Like simplify.xsl but using Python so a few non-standard conversions can
5 # also be done. (Currently it is still about the same as simplify.xsl...)
6 #
7 #---------------------------------------------------------------------------
8
9 import sys
10 import os
11 import libxml2
12
13
14 DEST="docs/xml/wxPython-metadata.xml"
15 SRC="docs/xml-raw"
16
17
18 classMap = {
19 'wxString' : 'String',
20 'void' : '',
21 }
22
23
24 def getModuleNames():
25 """
26 Get the list of extension modules from setup.py
27 """
28 import setup
29 names = [e.name[1:] for e in setup.wxpExtensions]
30 return names
31
32
33
34 def getAttr(node, name):
35 """
36 Get a value by name from the <attribute> elements in the SWIG XML output
37 """
38 path = "./attributelist/attribute[@name='%s']/@value" % name
39 n = node.xpathEval2(path)
40 if len(n):
41 return n[0].content
42 else:
43 return None
44
45
46 def fixType(typeStr):
47 """
48 Fixup type string, dropping the swig pointer and other flags
49 """
50 pos = typeStr.rfind('.')
51 if pos != -1:
52 typeStr = typeStr[pos+1:]
53 return classMap.get(typeStr, typeStr)
54
55
56 def processModule(newDocNode, modulename):
57 """
58 Start processing a new XML file, create a module element and then
59 find the include elements
60 """
61 filename = os.path.join(SRC, "%s_swig.xml" % modulename)
62 print filename
63
64 doc = libxml2.parseFile(filename)
65 topNode = doc.getRootElement()
66
67 # make a module element
68 name = getAttr(topNode, "module")
69 ##assert name == modulename # sanity check
70
71 moduleNode = libxml2.newNode("module")
72 moduleNode.setProp("name", name)
73 newDocNode.addChild(moduleNode)
74
75 node = topNode.children
76 while node is not None:
77 if node.name == "include":
78 processInclude(moduleNode, node)
79 node = node.next
80
81 doc.freeDoc()
82
83
84
85 def processInclude(moduleNode, includeNode):
86 """
87 Almost everything we are interested in is inside an <include>,
88 which may also be nested.
89 """
90
91 # check first for imports
92 for node in includeNode.xpathEval2("import"):
93 try:
94 modNode = node.xpathEval2("module")[0]
95 name = getAttr(modNode, "name")
96 impNode = libxml2.newNode("import")
97 impNode.setProp("name", name)
98 moduleNode.addChild(impNode)
99 except IndexError:
100 pass
101
102 # then look through the child nodes for other things we need
103 node = includeNode.children
104 while node is not None:
105 if node.name == "insert":
106 processInsert(moduleNode, node)
107
108 elif node.name == "class":
109 processClass(moduleNode, node)
110
111 elif node.name == "cdecl" and getAttr(node, "view") == "globalfunctionHandler":
112 func = libxml2.newNode("method")
113 func.setProp("name", getAttr(node, "sym_name"))
114 func.setProp("oldname", getAttr(node, "name"))
115 func.setProp("type", fixType(getAttr(node, "type")))
116 doCheckOverloaded(func, node)
117 doDocStrings(func, node)
118 doParamList(func, node)
119 moduleNode.addChild(func)
120
121
122 elif node.name == "include":
123 processInclude(moduleNode, node)
124
125 node = node.next
126
127
128
129 def processInsert(parentNode, insertNode):
130 """
131 Check for pythoncode
132 """
133 if getAttr(insertNode, "section") == "python":
134 code = getAttr(insertNode, "code")
135 node = libxml2.newNode("pythoncode")
136 node.addChild(libxml2.newText(code))
137 parentNode.addChild(node)
138
139
140
141 def processClass(parentNode, classNode):
142 """
143 Handle classes, constructors, methods, etc.
144 """
145 # make class element
146 klass = libxml2.newNode("class")
147 name = getAttr(classNode, "sym_name")
148 oldname = getAttr(classNode, "name")
149 classMap[oldname] = name
150 klass.setProp("name", name)
151 klass.setProp("oldname", oldname)
152 klass.setProp("module", getAttr(classNode, "module"))
153 doDocStrings(klass, classNode)
154 parentNode.addChild(klass)
155
156 # check for baseclass(es)
157 for node in classNode.xpathEval2("attributelist/baselist/base"):
158 baseclass = libxml2.newNode("baseclass")
159 basename = node.prop("name")
160 baseclass.setProp("name", classMap.get(basename, basename))
161 klass.addChild(baseclass)
162
163 # check for constructors/destructors
164 for type in ["constructor", "destructor"]:
165 for node in classNode.xpathEval2("%s | extend/%s" % (type, type)):
166 func = libxml2.newNode(type)
167 func.setProp("name", getAttr(node, "sym_name"))
168 if parentNode.name != "destructor":
169 doCheckOverloaded(func, node)
170 doDocStrings(func, node)
171 doParamList(func, node)
172 klass.addChild(func)
173
174 # check for cdecl's. In class scope we are interested in methods,
175 # static methods, or properties
176 for node in classNode.xpathEval2("cdecl | extend/cdecl"):
177 view = getAttr(node, "view")
178 if view == "memberfunctionHandler":
179 func = libxml2.newNode("method")
180 func.setProp("name", getAttr(node, "sym_name"))
181 func.setProp("type", fixType(getAttr(node, "type")))
182 doCheckOverloaded(func, node)
183 doDocStrings(func, node)
184 doParamList(func, node)
185 klass.addChild(func)
186
187 elif view == "staticmemberfunctionHandler":
188 func = libxml2.newNode("staticmethod")
189 func.setProp("name", getAttr(node, "sym_name"))
190 func.setProp("type", fixType(getAttr(node, "type")))
191 doCheckOverloaded(func, node)
192 doDocStrings(func, node)
193 doParamList(func, node)
194 klass.addChild(func)
195
196 elif view == "variableHandler":
197 prop = libxml2.newNode("property")
198 prop.setProp("name", getAttr(node, "sym_name"))
199 prop.setProp("type", fixType(getAttr(node, "type")))
200 if getAttr(node, "feature_immutable"):
201 prop.setProp("readonly", "yes")
202 else:
203 prop.setProp("readonly", "no")
204 doDocStrings(prop, node)
205 klass.addChild(prop)
206
207
208
209 def doParamList(parentNode, srcNode):
210 """
211 Convert the parameter list
212 """
213 params = srcNode.xpathEval2("attributelist/parmlist/parm")
214 if params:
215 plist = libxml2.newNode("paramlist")
216 for p in params:
217 pnode = libxml2.newNode("param")
218 pnode.setProp("name", getAttr(p, "name"))
219 pnode.setProp("type", fixType(getAttr(p, "type")))
220 pnode.setProp("default", getAttr(p, "value"))
221 plist.addChild(pnode)
222 parentNode.addChild(plist)
223
224
225
226 def doCheckOverloaded(parentNode, srcNode):
227 """
228 Set an attribute indicating if the srcNode is tagged as being overloaded
229 """
230 if srcNode.xpathEval2("./attributelist/attribute[@name='sym_overloaded']"):
231 parentNode.setProp("overloaded", "yes")
232 else:
233 parentNode.setProp("overloaded", "no")
234
235
236
237 def doDocStrings(parentNode, srcNode):
238 """
239 Check for the various possible docstring attributes, and attach
240 coresponding child nodes if found.
241 """
242 def makeDocElement(name, content):
243 node = libxml2.newNode(name)
244 node.addChild(libxml2.newText(content))
245 return node
246
247 autodoc = getAttr(srcNode, "python_autodoc")
248 docstr = getAttr(srcNode, "feature_docstring")
249 if autodoc:
250 parentNode.addChild(makeDocElement("autodoc", autodoc))
251 if docstr:
252 parentNode.addChild(makeDocElement("docstring", docstr))
253
254
255
256
257
258 def main():
259 if not os.path.exists(SRC):
260 print "Unable to find %s, please run this script from the root wxPython directory." % SRC
261 sys.exit(1)
262
263 newDoc = libxml2.newDoc("1.0")
264 newTopNode = libxml2.newNode("wxPython-metadata")
265 newDoc.addChild(newTopNode)
266
267 for m in getModuleNames():
268 processModule(newTopNode, m)
269
270 newDoc.saveFormatFile(DEST, True)
271 print "Wrote simplified metadata to", DEST
272
273 #---------------------------------------------------------------------------
274
275 if __name__ == "__main__":
276 main()