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