]> git.saurik.com Git - wxWidgets.git/blame - wxPython/distrib/build_renamers.py
Added reverse renamers for the *Ptr classes
[wxWidgets.git] / wxPython / distrib / build_renamers.py
CommitLineData
d14a1e28
RD
1#!/usr/bin/env python
2#---------------------------------------------------------------------------
3"""
4Usage: build_renamers.py filename.i
5
6Run SWIG on file.i using the XML language module and then scan the XML
7file produced and generate the %rename directives needed to implement
8the new wx namespace. The rename directives are output in a file
9named _filename_rename.i in the same dir as filename.i.
10
11Also output a reverse 'renamer' Python module located in
12wxPython/filename.py (relative the the current dir) to make a
13backwards compatibility interface for the old wxPython packages.
14"""
15
16import sys, os, tempfile, pprint
17import xml.sax
18from distutils.spawn import spawn
19
20
21
22#---------------------------------------------------------------------------
23
24DO_UNLINK = True
25
26wxPythonDir = "wxPython"
27swig_cmd = "/opt/swig/bin/swig"
28if os.name == 'nt':
29 swig_cmd = 'e:/projects/SWIG-cvs/swig.exe'
30
31swig_args = ['-c++',
32 '-Wall',
33 '-nodefault',
34
35 '-xml',
36 '-xmllite',
37
38 '-I./src',
98fb9b71 39 '-noruntime'
d14a1e28
RD
40 ]
41
42
43renamerTemplateStart = """\
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
51renamerTemplateEnd = """
52#endif
53"""
54
55wxPythonTemplateStart = """\
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.
64import sys
65_wx = None
66if sys.modules.has_key('wxPython.wx'):
67 _wx = sys.modules['wxPython.wx']
68 del sys.modules['wxPython.wx']
69
70import wx.%s
71
72sys.modules['wxPython.wx'] = _wx
73del sys, _wx
74
75
76# Now assign all the reverse-renamed names:
77"""
78
79wxPythonTemplateEnd = """
80
81"""
82
83
84
85#---------------------------------------------------------------------------
86
87def 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
166def 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
200interestingTypes = [ 'class', 'cdecl', 'enumitem', 'constructor', 'constant' ]
201interestingAttrs = [ 'name', 'sym_name', 'decl', 'feature_immutable', 'module',
202 'storage', 'type' ]
203
204
205class 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
306class 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
413if __name__ == "__main__":
414 main(sys.argv[1:])
415