]> git.saurik.com Git - wxWidgets.git/blob - wxPython/distrib/build_renamers.py
added obsolescence note
[wxWidgets.git] / wxPython / distrib / build_renamers.py
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',
39 '-c'
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
222 addWX = False
223 revOnly = False
224
225 #if self.name.find('DefaultPosition') != -1:
226 # pprint.pprint(self.__dict__)
227
228 if self.tagtype in ['cdecl', 'constant']:
229 if self.storage == 'typedef':
230 pass
231
232 # top level functions
233 elif self.level == 0 and self.decl != "":
234 doRename = True
235
236 # top level global vars
237 elif self.level == 0 and self.immutable == '1':
238 doRename = True
239
240 # static methods
241 elif self.storage == 'static':
242 if not self.klass:
243 pprint.pprint(self.__dict__)
244 else:
245 self.name = self.klass + '_' + self.name
246 self.sym_name = self.sym_klass + '_' + self.sym_name
247 # only output the reverse renamer in this case
248 doRename = revOnly = True
249
250
251
252 if doRename and self.name != self.sym_name:
253 #print "%-25s %-25s" % (self.name, self.sym_name)
254 self.name = self.sym_name
255 addWX = True
256
257
258 elif self.tagtype == 'class' and self.module == moduleName:
259 doRename = True
260 if self.sym_name != self.klass:
261 #print self.sym_name
262 self.name = self.sym_name
263 addWX = True
264
265 elif self.tagtype == 'constructor':
266 #print "%-25s %-25s" % (self.name, self.sym_name)
267 if self.sym_name != self.klass:
268 #print self.sym_name
269 self.name = self.sym_name
270 addWX = True
271 doRename = True
272
273 elif self.tagtype == 'enumitem' and self.level == 0:
274 doRename = True
275
276
277 if doRename:
278 #print "%-25s %-25s" % (self.name, self.sym_name)
279 old = new = self.name
280 if old.startswith('wx') and not old.startswith('wxEVT_'):
281 # remove all wx prefixes except wxEVT_ and write a %rename directive for it
282 new = old[2:]
283 if not revOnly:
284 swigFile.write("%%rename(%s) %35s;\n" % (new, old))
285
286 # Write assignments to import into the old wxPython namespace
287 if addWX and not old.startswith('wx'):
288 old = 'wx'+old
289 pyFile.write("%s = wx.%s.%s\n" % (old, moduleName, new))
290
291
292 #else:
293 # text = "%07d %d %10s %-35s %s\n" % (
294 # self.startLine, self.level, self.tagtype, self.name, self.decl)
295 # #rejects.write(text)
296 # print text,
297
298
299 #---------------------------------------------------------------------------
300
301 class ContentHandler(xml.sax.ContentHandler):
302 def __init__(self, source, sourceBase, swigFile, pyFile):
303 xml.sax.ContentHandler.__init__(self)
304 self.source = source
305 self.sourceBase = sourceBase
306 self.swigFile = swigFile
307 self.pyFile = pyFile
308 self.elements = []
309 self.imports = 0
310 self.klass = None
311 self.sym_klass = None
312
313
314 def setDocumentLocator(self, locator):
315 self.locator = locator
316
317
318
319 def startElement(self, name, attrs):
320 if name in interestingTypes:
321 # start of a new element that we are interested in
322 ce = Element(name)
323 ce.startLine = self.locator.getLineNumber()
324 ce.level = len(self.elements)
325 if name == 'constructor':
326 ce.klass = self.elements[0].name
327 else:
328 ce.klass = self.klass
329 ce.sym_klass = self.sym_klass
330 self.elements.insert(0, ce)
331
332
333 elif len(self.elements) and name == 'attribute' and attrs['name'] in interestingAttrs:
334 attrName = attrs['name']
335 attrVal = attrs['value']
336 if attrName.startswith('feature_'):
337 attrName = attrName.replace('feature_', '')
338 ce = self.elements[0]
339 if getattr(ce, attrName) is None:
340 setattr(ce, attrName, attrVal)
341 if ce.tagtype == 'class' and attrName == 'name' and self.klass is None:
342 self.klass = attrVal
343 if ce.tagtype == 'class' and attrName == 'sym_name' and self.sym_klass is None:
344 self.sym_klass = attrVal
345
346
347 ## elif len(self.elements) and name == 'attribute' and attrs['name'] == 'name':
348 ## # save the elements name
349 ## ce = self.elements[0]
350 ## if ce.name is None:
351 ## ce.name = attrs['value']
352 ## ce.nameLine = self.locator.getLineNumber()
353
354 ## elif len(self.elements) and name == 'attribute' and attrs['name'] == 'sym_name':
355 ## # save the elements name
356 ## ce = self.elements[0]
357 ## if ce.sym_name is None:
358 ## ce.sym_name = attrs['value']
359
360 ## elif len(self.elements) and name == 'attribute' and attrs['name'] == 'decl':
361 ## # save the elements decl
362 ## ce = self.elements[0]
363 ## ce.decl = attrs['value']
364
365 ## elif len(self.elements) and name == 'attribute' and attrs['name'] == 'feature_immutable':
366 ## # save the elements decl
367 ## ce = self.elements[0]
368 ## ce.immutable = int(attrs['value'])
369
370 ## elif len(self.elements) and name == 'attribute' and attrs['name'] == 'module':
371 ## # save the elements decl
372 ## ce = self.elements[0]
373 ## ce.module = attrs['value']
374
375 elif name == 'import':
376 self.imports += 1
377
378 ## elif len(self.elements) and name == 'attribute' and attrs['name'] == 'storage':
379 ## # save the elements decl
380 ## ce = self.elements[0]
381 ## ce.storage = attrs['value']
382
383 ## elif len(self.elements) and name == 'attribute' and attrs['name'] == 'type':
384 ## # save the elements decl
385 ## ce = self.elements[0]
386 ## ce.type = attrs['value']
387
388
389 def endElement(self, name):
390 if name in interestingTypes:
391 # end of an element that we are interested in
392 ce = self.elements.pop(0)
393
394 if self.imports == 0:
395 # only write for items that are in this file, not imported
396 ce.write(self.sourceBase, self.swigFile, self.pyFile)
397
398 if name == 'import':
399 self.imports -= 1
400
401 if name == 'class':
402 self.klass = None
403 self.sym_klass = None
404
405
406 #---------------------------------------------------------------------------
407
408 if __name__ == "__main__":
409 main(sys.argv[1:])
410