]>
Commit | Line | Data |
---|---|---|
685d8985 RD |
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 | ||
6f401080 RD |
18 | classMap = { |
19 | 'wxString' : 'String', | |
20 | 'void' : '', | |
21 | } | |
22 | ||
685d8985 RD |
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 | ||
6f401080 RD |
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) | |
685d8985 RD |
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") | |
781d2982 | 69 | ##assert name == modulename # sanity check |
685d8985 RD |
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": | |
0dd25e81 | 78 | processInclude(moduleNode, node) |
685d8985 RD |
79 | node = node.next |
80 | ||
81 | doc.freeDoc() | |
82 | ||
83 | ||
84 | ||
0dd25e81 | 85 | def processInclude(moduleNode, includeNode): |
685d8985 RD |
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": | |
0dd25e81 | 106 | processInsert(moduleNode, node) |
685d8985 RD |
107 | |
108 | elif node.name == "class": | |
0dd25e81 | 109 | processClass(moduleNode, node) |
685d8985 RD |
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")) | |
6f401080 | 115 | func.setProp("type", fixType(getAttr(node, "type"))) |
685d8985 RD |
116 | doCheckOverloaded(func, node) |
117 | doDocStrings(func, node) | |
118 | doParamList(func, node) | |
119 | moduleNode.addChild(func) | |
120 | ||
121 | ||
122 | elif node.name == "include": | |
0dd25e81 | 123 | processInclude(moduleNode, node) |
685d8985 RD |
124 | |
125 | node = node.next | |
126 | ||
127 | ||
128 | ||
0dd25e81 | 129 | def processInsert(parentNode, insertNode): |
685d8985 RD |
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 | ||
0dd25e81 | 141 | def processClass(parentNode, classNode): |
685d8985 RD |
142 | """ |
143 | Handle classes, constructors, methods, etc. | |
144 | """ | |
145 | # make class element | |
146 | klass = libxml2.newNode("class") | |
6f401080 RD |
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) | |
685d8985 RD |
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") | |
6f401080 RD |
159 | basename = node.prop("name") |
160 | baseclass.setProp("name", classMap.get(basename, basename)) | |
685d8985 RD |
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")) | |
6f401080 | 181 | func.setProp("type", fixType(getAttr(node, "type"))) |
685d8985 RD |
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")) | |
6f401080 | 190 | func.setProp("type", fixType(getAttr(node, "type"))) |
685d8985 RD |
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")) | |
6f401080 | 199 | prop.setProp("type", fixType(getAttr(node, "type"))) |
685d8985 RD |
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") | |
6f401080 RD |
218 | pnode.setProp("name", getAttr(p, "name")) |
219 | pnode.setProp("type", fixType(getAttr(p, "type"))) | |
685d8985 RD |
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") | |
685d8985 RD |
249 | if autodoc: |
250 | parentNode.addChild(makeDocElement("autodoc", autodoc)) | |
251 | if docstr: | |
252 | parentNode.addChild(makeDocElement("docstring", docstr)) | |
685d8985 RD |
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) | |
6f401080 | 271 | print "Wrote simplified metadata to", DEST |
685d8985 RD |
272 | |
273 | #--------------------------------------------------------------------------- | |
274 | ||
275 | if __name__ == "__main__": | |
276 | main() |