]>
Commit | Line | Data |
---|---|---|
d14a1e28 RD |
1 | #!/usr/bin/env python |
2 | #--------------------------------------------------------------------------- | |
3 | """ | |
4 | Usage: build_renamers.py filename.i | |
5 | ||
6 | Run SWIG on file.i using the XML language module and then scan the XML | |
7 | file produced and generate the %rename directives needed to implement | |
8 | the new wx namespace. The rename directives are output in a file | |
9 | named _filename_rename.i in the same dir as filename.i. | |
10 | ||
11 | Also output a reverse 'renamer' Python module located in | |
12 | wxPython/filename.py (relative the the current dir) to make a | |
13 | backwards compatibility interface for the old wxPython packages. | |
14 | """ | |
15 | ||
16 | import sys, os, tempfile, pprint | |
17 | import xml.sax | |
18 | from distutils.spawn import spawn | |
19 | ||
20 | ||
21 | ||
22 | #--------------------------------------------------------------------------- | |
23 | ||
24 | DO_UNLINK = True | |
25 | ||
26 | wxPythonDir = "wxPython" | |
27 | swig_cmd = "/opt/swig/bin/swig" | |
28 | if os.name == 'nt': | |
29 | swig_cmd = 'e:/projects/SWIG-cvs/swig.exe' | |
30 | ||
31 | swig_args = ['-c++', | |
32 | '-Wall', | |
33 | '-nodefault', | |
34 | ||
35 | '-xml', | |
36 | '-xmllite', | |
37 | ||
38 | '-I./src', | |
98fb9b71 | 39 | '-noruntime' |
d14a1e28 RD |
40 | ] |
41 | ||
42 | ||
43 | renamerTemplateStart = """\ | |
44 | // A bunch of %%rename directives generated by %s | |
45 | // in order to remove the wx prefix from all global scope names. | |
46 | ||
47 | #ifndef SWIGXML | |
48 | ||
49 | """ | |
50 | ||
51 | renamerTemplateEnd = """ | |
52 | #endif | |
53 | """ | |
54 | ||
55 | wxPythonTemplateStart = """\ | |
56 | ## This file reverse renames symbols in the wx package to give | |
57 | ## them their wx prefix again, for backwards compatibility. | |
58 | ## | |
59 | ## Generated by %s | |
60 | ||
61 | # This silly stuff here is so the wxPython.wx module doesn't conflict | |
62 | # with the wx package. We need to import modules from the wx package | |
63 | # here, then we'll put the wxPython.wx entry back in sys.modules. | |
64 | import sys | |
65 | _wx = None | |
66 | if sys.modules.has_key('wxPython.wx'): | |
67 | _wx = sys.modules['wxPython.wx'] | |
68 | del sys.modules['wxPython.wx'] | |
69 | ||
70 | import wx.%s | |
71 | ||
72 | sys.modules['wxPython.wx'] = _wx | |
73 | del sys, _wx | |
74 | ||
75 | ||
76 | # Now assign all the reverse-renamed names: | |
77 | """ | |
78 | ||
79 | wxPythonTemplateEnd = """ | |
80 | ||
81 | """ | |
82 | ||
83 | ||
84 | ||
85 | #--------------------------------------------------------------------------- | |
86 | ||
87 | def main(args): | |
88 | # check args | |
89 | if len(args) < 1: | |
90 | print __doc__ | |
91 | sys.exit(1) | |
92 | ||
93 | # check location (there should be a wxPython subdir) | |
94 | if not os.path.exists(wxPythonDir) or not os.path.isdir(wxPythonDir): | |
95 | print __doc__ | |
96 | print "You should only run this script from the main wxPython source dir.\n" | |
97 | sys.exit(1) | |
98 | ||
99 | ||
100 | source = args[0] | |
101 | sourcePath, sourceBase = os.path.split(source) | |
102 | sourceBase = os.path.splitext(sourceBase)[0] | |
103 | ||
104 | tempfile.tempdir = sourcePath | |
105 | xmlDest = tempfile.mktemp('.xml') | |
106 | swigDest = os.path.join(sourcePath, "_"+sourceBase+"_rename.i") | |
107 | pyDest = os.path.join(wxPythonDir, sourceBase + '.py') | |
108 | ||
109 | #print "source: ", source | |
110 | #print "xmlDest: ", xmlDest | |
111 | #print "swigDest: ", swigDest | |
112 | #print "pyDest: ", pyDest | |
113 | ||
114 | cmd = [ swig_cmd ] + swig_args + args[1:] + ['-I'+sourcePath, '-o', xmlDest, source] | |
115 | print ' '.join(cmd) | |
116 | spawn(cmd) | |
117 | ||
118 | swigDestTemp = tempfile.mktemp('.tmp') | |
119 | swigFile = open(swigDestTemp, "w") | |
120 | swigFile.write(renamerTemplateStart % sys.argv[0]) | |
121 | ||
122 | pyFile = open(pyDest, "w") | |
123 | pyFile.write(wxPythonTemplateStart % (sys.argv[0], sourceBase)) | |
124 | ||
125 | print "Parsing and building renamers", | |
126 | try: | |
127 | ## try: | |
128 | ## import libxml2 | |
129 | ## print "using libxml2..." | |
130 | ## ctxt = libxml2.createPushParser(ContentHandler(source, sourceBase, swigFile, pyFile), | |
131 | ## '', 0, xmlDest) | |
132 | ## for line in file(xmlDest): | |
133 | ## if not line: | |
134 | ## ctxt.parseChunck('', 0, 1) | |
135 | ## break | |
136 | ## ctxt.parseChunk(line, len(line), 0) | |
137 | ||
138 | ## except ImportError: | |
139 | print "using xml.sax..." | |
140 | xml.sax.parse(xmlDest, ContentHandler(source, sourceBase, swigFile, pyFile)) | |
141 | ||
142 | finally: | |
143 | checkOtherNames(pyFile, sourceBase, | |
144 | os.path.join(sourcePath, '_'+sourceBase+'_reverse.txt')) | |
145 | pyFile.write(wxPythonTemplateEnd) | |
146 | pyFile.close() | |
147 | ||
148 | swigFile.write(renamerTemplateEnd) | |
149 | swigFile.close() | |
150 | ||
151 | # Compare the file just created with the existing one and | |
152 | # blow away the old one if they are different. | |
153 | if open(swigDest).read() != open(swigDestTemp).read(): | |
154 | os.unlink(swigDest) | |
155 | os.rename(swigDestTemp, swigDest) | |
156 | else: | |
157 | print swigDest + " not changed." | |
158 | os.unlink(swigDestTemp) | |
159 | ||
160 | if DO_UNLINK: | |
161 | os.unlink(xmlDest) | |
162 | ||
163 | ||
164 | #--------------------------------------------------------------------------- | |
165 | ||
166 | def checkOtherNames(pyFile, moduleName, filename): | |
167 | if os.path.exists(filename): | |
168 | prefixes = [] | |
169 | for line in file(filename): | |
170 | if line.endswith('\n'): | |
171 | line = line[:-1] | |
172 | if line and not line.startswith('#'): | |
173 | if line.endswith('*'): | |
174 | prefixes.append(line[:-1]) | |
175 | elif line.find('=') != -1: | |
176 | pyFile.write("%s\n" % line) | |
177 | else: | |
178 | wxname = 'wx' + line | |
179 | if line.startswith('wx') or line.startswith('WX') or line.startswith('EVT'): | |
180 | wxname = line | |
181 | pyFile.write("%s = wx.%s.%s\n" % (wxname, moduleName, line)) | |
182 | ||
183 | if prefixes: | |
184 | pyFile.write( | |
185 | "\n\nd = globals()\nfor k, v in wx.%s.__dict__.iteritems():" | |
186 | % moduleName) | |
187 | first = True | |
188 | for p in prefixes: | |
189 | if first: | |
190 | pyFile.write("\n if ") | |
191 | first = False | |
192 | else: | |
193 | pyFile.write("\n elif ") | |
194 | pyFile.write("k.startswith('%s'):\n d[k] = v" % p) | |
195 | pyFile.write("\ndel d, k, v\n\n") | |
196 | ||
197 | ||
198 | #--------------------------------------------------------------------------- | |
199 | ||
200 | interestingTypes = [ 'class', 'cdecl', 'enumitem', 'constructor', 'constant' ] | |
201 | interestingAttrs = [ 'name', 'sym_name', 'decl', 'feature_immutable', 'module', | |
202 | 'storage', 'type' ] | |
203 | ||
204 | ||
205 | class Element: | |
206 | def __init__(self, tagtype): | |
207 | self.tagtype = tagtype | |
208 | self.level = -1 | |
209 | self.name = None | |
210 | self.sym_name = None | |
211 | self.decl = None | |
212 | self.immutable = None | |
213 | self.klass = None | |
214 | self.module = None | |
215 | self.storage = None | |
216 | self.type = None | |
217 | self.startLine = -1 | |
218 | ||
219 | ||
220 | def write(self, moduleName, swigFile, pyFile): | |
221 | doRename = False | |
423af76e | 222 | doPtr = False |
d14a1e28 RD |
223 | addWX = False |
224 | revOnly = False | |
225 | ||
226 | #if self.name.find('DefaultPosition') != -1: | |
227 | # pprint.pprint(self.__dict__) | |
228 | ||
229 | if self.tagtype in ['cdecl', 'constant']: | |
230 | if self.storage == 'typedef': | |
231 | pass | |
232 | ||
233 | # top level functions | |
234 | elif self.level == 0 and self.decl != "": | |
235 | doRename = True | |
236 | ||
237 | # top level global vars | |
238 | elif self.level == 0 and self.immutable == '1': | |
239 | doRename = True | |
240 | ||
241 | # static methods | |
242 | elif self.storage == 'static': | |
243 | if not self.klass: | |
244 | pprint.pprint(self.__dict__) | |
245 | else: | |
246 | self.name = self.klass + '_' + self.name | |
247 | self.sym_name = self.sym_klass + '_' + self.sym_name | |
248 | # only output the reverse renamer in this case | |
249 | doRename = revOnly = True | |
250 | ||
251 | ||
252 | ||
253 | if doRename and self.name != self.sym_name: | |
254 | #print "%-25s %-25s" % (self.name, self.sym_name) | |
255 | self.name = self.sym_name | |
256 | addWX = True | |
257 | ||
258 | ||
259 | elif self.tagtype == 'class' and self.module == moduleName: | |
260 | doRename = True | |
423af76e | 261 | doPtr = True |
d14a1e28 RD |
262 | if self.sym_name != self.klass: |
263 | #print self.sym_name | |
264 | self.name = self.sym_name | |
265 | addWX = True | |
266 | ||
267 | elif self.tagtype == 'constructor': | |
268 | #print "%-25s %-25s" % (self.name, self.sym_name) | |
269 | if self.sym_name != self.klass: | |
270 | #print self.sym_name | |
271 | self.name = self.sym_name | |
272 | addWX = True | |
273 | doRename = True | |
274 | ||
275 | elif self.tagtype == 'enumitem' and self.level == 0: | |
276 | doRename = True | |
277 | ||
278 | ||
279 | if doRename: | |
280 | #print "%-25s %-25s" % (self.name, self.sym_name) | |
281 | old = new = self.name | |
282 | if old.startswith('wx') and not old.startswith('wxEVT_'): | |
283 | # remove all wx prefixes except wxEVT_ and write a %rename directive for it | |
284 | new = old[2:] | |
285 | if not revOnly: | |
286 | swigFile.write("%%rename(%s) %35s;\n" % (new, old)) | |
287 | ||
288 | # Write assignments to import into the old wxPython namespace | |
289 | if addWX and not old.startswith('wx'): | |
290 | old = 'wx'+old | |
291 | pyFile.write("%s = wx.%s.%s\n" % (old, moduleName, new)) | |
423af76e RD |
292 | if doPtr: |
293 | pyFile.write("%sPtr = wx.%s.%sPtr\n" % (old, moduleName, new)) | |
294 | ||
d14a1e28 RD |
295 | |
296 | ||
297 | #else: | |
298 | # text = "%07d %d %10s %-35s %s\n" % ( | |
299 | # self.startLine, self.level, self.tagtype, self.name, self.decl) | |
300 | # #rejects.write(text) | |
301 | # print text, | |
302 | ||
303 | ||
304 | #--------------------------------------------------------------------------- | |
305 | ||
306 | class ContentHandler(xml.sax.ContentHandler): | |
307 | def __init__(self, source, sourceBase, swigFile, pyFile): | |
308 | xml.sax.ContentHandler.__init__(self) | |
309 | self.source = source | |
310 | self.sourceBase = sourceBase | |
311 | self.swigFile = swigFile | |
312 | self.pyFile = pyFile | |
313 | self.elements = [] | |
314 | self.imports = 0 | |
315 | self.klass = None | |
316 | self.sym_klass = None | |
317 | ||
318 | ||
319 | def setDocumentLocator(self, locator): | |
320 | self.locator = locator | |
321 | ||
322 | ||
323 | ||
324 | def startElement(self, name, attrs): | |
325 | if name in interestingTypes: | |
326 | # start of a new element that we are interested in | |
327 | ce = Element(name) | |
328 | ce.startLine = self.locator.getLineNumber() | |
329 | ce.level = len(self.elements) | |
330 | if name == 'constructor': | |
331 | ce.klass = self.elements[0].name | |
332 | else: | |
333 | ce.klass = self.klass | |
334 | ce.sym_klass = self.sym_klass | |
335 | self.elements.insert(0, ce) | |
336 | ||
337 | ||
338 | elif len(self.elements) and name == 'attribute' and attrs['name'] in interestingAttrs: | |
339 | attrName = attrs['name'] | |
340 | attrVal = attrs['value'] | |
341 | if attrName.startswith('feature_'): | |
342 | attrName = attrName.replace('feature_', '') | |
343 | ce = self.elements[0] | |
344 | if getattr(ce, attrName) is None: | |
345 | setattr(ce, attrName, attrVal) | |
346 | if ce.tagtype == 'class' and attrName == 'name' and self.klass is None: | |
347 | self.klass = attrVal | |
348 | if ce.tagtype == 'class' and attrName == 'sym_name' and self.sym_klass is None: | |
349 | self.sym_klass = attrVal | |
350 | ||
351 | ||
352 | ## elif len(self.elements) and name == 'attribute' and attrs['name'] == 'name': | |
353 | ## # save the elements name | |
354 | ## ce = self.elements[0] | |
355 | ## if ce.name is None: | |
356 | ## ce.name = attrs['value'] | |
357 | ## ce.nameLine = self.locator.getLineNumber() | |
358 | ||
359 | ## elif len(self.elements) and name == 'attribute' and attrs['name'] == 'sym_name': | |
360 | ## # save the elements name | |
361 | ## ce = self.elements[0] | |
362 | ## if ce.sym_name is None: | |
363 | ## ce.sym_name = attrs['value'] | |
364 | ||
365 | ## elif len(self.elements) and name == 'attribute' and attrs['name'] == 'decl': | |
366 | ## # save the elements decl | |
367 | ## ce = self.elements[0] | |
368 | ## ce.decl = attrs['value'] | |
369 | ||
370 | ## elif len(self.elements) and name == 'attribute' and attrs['name'] == 'feature_immutable': | |
371 | ## # save the elements decl | |
372 | ## ce = self.elements[0] | |
373 | ## ce.immutable = int(attrs['value']) | |
374 | ||
375 | ## elif len(self.elements) and name == 'attribute' and attrs['name'] == 'module': | |
376 | ## # save the elements decl | |
377 | ## ce = self.elements[0] | |
378 | ## ce.module = attrs['value'] | |
379 | ||
380 | elif name == 'import': | |
381 | self.imports += 1 | |
382 | ||
383 | ## elif len(self.elements) and name == 'attribute' and attrs['name'] == 'storage': | |
384 | ## # save the elements decl | |
385 | ## ce = self.elements[0] | |
386 | ## ce.storage = attrs['value'] | |
387 | ||
388 | ## elif len(self.elements) and name == 'attribute' and attrs['name'] == 'type': | |
389 | ## # save the elements decl | |
390 | ## ce = self.elements[0] | |
391 | ## ce.type = attrs['value'] | |
392 | ||
393 | ||
394 | def endElement(self, name): | |
395 | if name in interestingTypes: | |
396 | # end of an element that we are interested in | |
397 | ce = self.elements.pop(0) | |
398 | ||
399 | if self.imports == 0: | |
400 | # only write for items that are in this file, not imported | |
401 | ce.write(self.sourceBase, self.swigFile, self.pyFile) | |
402 | ||
403 | if name == 'import': | |
404 | self.imports -= 1 | |
405 | ||
406 | if name == 'class': | |
407 | self.klass = None | |
408 | self.sym_klass = None | |
409 | ||
410 | ||
411 | #--------------------------------------------------------------------------- | |
412 | ||
413 | if __name__ == "__main__": | |
414 | main(sys.argv[1:]) | |
415 |