]>
git.saurik.com Git - wxWidgets.git/blob - wxPython/distrib/build_renamers.py
2 #---------------------------------------------------------------------------
4 Usage: build_renamers.py destdir modulename filename.xml
6 Scans the XML file produced by SWIG (see setup.py) and generate the
7 %rename directives needed to implement the new wx namespace. The
8 rename directives are output in a file named _modulename_rename.i in
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.
16 import sys
, os
, tempfile
, pprint
18 from distutils
.spawn
import spawn
26 wxPythonDir
= "wxPython"
28 #---------------------------------------------------------------------------
31 renamerTemplateStart
= """\
32 // A bunch of %%rename directives generated by %s
33 // in order to remove the wx prefix from all global scope names.
35 #ifndef BUILDING_RENAMERS
39 renamerTemplateEnd
= """
43 wxPythonTemplateStart
= """\
44 ## This file reverse renames symbols in the wx package to give
45 ## them their wx prefix again, for backwards compatibility.
49 # This silly stuff here is so the wxPython.wx module doesn't conflict
50 # with the wx package. We need to import modules from the wx package
51 # here, then we'll put the wxPython.wx entry back in sys.modules.
54 if sys.modules.has_key('wxPython.wx'):
55 _wx = sys.modules['wxPython.wx']
56 del sys.modules['wxPython.wx']
60 sys.modules['wxPython.wx'] = _wx
64 # Now assign all the reverse-renamed names:
67 wxPythonTemplateEnd
= """
73 #---------------------------------------------------------------------------
81 # check location (there should be a wxPython subdir)
82 if not os
.path
.exists(wxPythonDir
) or not os
.path
.isdir(wxPythonDir
):
84 print "You should only run this script from the main wxPython source dir.\n"
92 swigDest
= os
.path
.join(destdir
, "_"+modname
+"_rename.i")
93 pyDest
= os
.path
.join(wxPythonDir
, modname
+ '.py')
95 swigDestTemp
= tempfile
.mktemp('.tmp')
96 swigFile
= open(swigDestTemp
, "w")
97 swigFile
.write(renamerTemplateStart
% sys
.argv
[0])
99 pyDestTemp
= tempfile
.mktemp('.tmp')
100 pyFile
= open(pyDestTemp
, "w")
101 pyFile
.write(wxPythonTemplateStart
% (sys
.argv
[0], modname
))
104 print "Parsing and building renamers",
106 processXML(xmlfile
, modname
, swigFile
, pyFile
)
108 print "using xml.sax..."
109 xml
.sax
.parse(xmlfile
, ContentHandler(modname
, swigFile
, pyFile
))
113 checkOtherNames(pyFile
, modname
,
114 os
.path
.join(destdir
, '_'+modname
+'_reverse.txt'))
115 pyFile
.write(wxPythonTemplateEnd
)
118 swigFile
.write(renamerTemplateEnd
)
121 # Compare the files just created with the existing one and
122 # blow away the old one if they are different.
123 for dest
, temp
in [(swigDest
, swigDestTemp
),
124 (pyDest
, pyDestTemp
)]:
125 if not os
.path
.exists(dest
):
126 os
.rename(temp
, dest
)
127 elif open(dest
).read() != open(temp
).read():
129 os
.rename(temp
, dest
)
131 print dest
+ " not changed."
134 #---------------------------------------------------------------------------
137 def GetAttr(node
, name
):
138 path
= "./attributelist/attribute[@name='%s']/@value" % name
139 n
= node
.xpathEval2(path
)
146 def processXML(xmlfile
, modname
, swigFile
, pyFile
):
148 print "using libxml2..."
150 topnode
= libxml2
.parseFile(xmlfile
).children
152 # remove any import nodes as we don't need to do renamers for symbols found therein
153 imports
= topnode
.xpathEval2("*/import")
158 # do a depth first iteration over what's left
166 if node
.name
== "class":
167 lastClassName
= name
= GetAttr(node
, "name")
168 lastClassSymName
= sym_name
= GetAttr(node
, "sym_name")
175 # renamed constructors
176 elif node
.name
== "constructor":
177 name
= GetAttr(node
, "name")
178 sym_name
= GetAttr(node
, "sym_name")
184 # only enumitems at the top level
185 elif node
.name
== "enumitem" and node
.parent
.parent
.name
== "include":
186 name
= GetAttr(node
, "name")
187 sym_name
= GetAttr(node
, "sym_name")
191 elif node
.name
in ["cdecl", "constant"]:
192 name
= GetAttr(node
, "name")
193 sym_name
= GetAttr(node
, "sym_name")
194 toplevel
= node
.parent
.name
== "include"
196 # top-level functions
197 if toplevel
and GetAttr(node
, "view") == "globalfunctionHandler":
200 # top-level global vars
201 elif toplevel
and GetAttr(node
, "feature_immutable") == "1":
205 elif GetAttr(node
, "view") == "staticmemberfunctionHandler":
206 name
= lastClassName
+ '_' + name
207 sym_name
= lastClassSymName
+ '_' + sym_name
208 # only output the reverse renamer in this case
209 doRename
= revOnly
= True
211 if doRename
and name
!= sym_name
:
216 if doRename
and name
:
218 if old
.startswith('wx') and not old
.startswith('wxEVT_'):
219 # remove all wx prefixes except wxEVT_ and write a %rename directive for it
222 swigFile
.write("%%rename(%s) %35s;\n" % (new
, old
))
224 # Write assignments to import into the old wxPython namespace
225 if addWX
and not old
.startswith('wx'):
227 pyFile
.write("%s = wx.%s.%s\n" % (old
, modname
, new
))
229 pyFile
.write("%sPtr = wx.%s.%sPtr\n" % (old
, modname
, new
))
232 #---------------------------------------------------------------------------
234 def checkOtherNames(pyFile
, moduleName
, filename
):
235 if os
.path
.exists(filename
):
237 for line
in file(filename
):
238 if line
.endswith('\n'):
240 if line
and not line
.startswith('#'):
241 if line
.endswith('*'):
242 prefixes
.append(line
[:-1])
243 elif line
.find('=') != -1:
244 pyFile
.write("%s\n" % line
)
247 if line
.startswith('wx') or line
.startswith('WX') or line
.startswith('EVT'):
249 pyFile
.write("%s = wx.%s.%s\n" % (wxname
, moduleName
, line
))
253 "\n\nd = globals()\nfor k, v in wx.%s.__dict__.iteritems():"
258 pyFile
.write("\n if ")
261 pyFile
.write("\n elif ")
262 pyFile
.write("k.startswith('%s'):\n d[k] = v" % p
)
263 pyFile
.write("\ndel d, k, v\n\n")
266 #---------------------------------------------------------------------------
268 interestingTypes
= [ 'class', 'cdecl', 'enumitem', 'constructor', 'constant' ]
269 interestingAttrs
= [ 'name', 'sym_name', 'decl', 'feature_immutable', 'module',
274 def __init__(self
, tagtype
):
275 self
.tagtype
= tagtype
280 self
.immutable
= None
288 def write(self
, moduleName
, swigFile
, pyFile
):
294 #if self.name.find('DefaultPosition') != -1:
295 # pprint.pprint(self.__dict__)
297 if self
.tagtype
in ['cdecl', 'constant']:
298 if self
.storage
== 'typedef':
301 # top level functions
302 elif self
.level
== 0 and self
.decl
!= "":
305 # top level global vars
306 elif self
.level
== 0 and self
.immutable
== '1':
310 elif self
.storage
== 'static':
312 pprint
.pprint(self
.__dict
__)
314 self
.name
= self
.klass
+ '_' + self
.name
315 self
.sym_name
= self
.sym_klass
+ '_' + self
.sym_name
316 # only output the reverse renamer in this case
317 doRename
= revOnly
= True
321 if doRename
and self
.name
!= self
.sym_name
:
322 #print "%-25s %-25s" % (self.name, self.sym_name)
323 self
.name
= self
.sym_name
327 elif self
.tagtype
== 'class' and self
.module
== moduleName
:
330 if self
.sym_name
!= self
.klass
:
332 self
.name
= self
.sym_name
335 elif self
.tagtype
== 'constructor':
336 #print "%-25s %-25s" % (self.name, self.sym_name)
337 if self
.sym_name
!= self
.klass
:
339 self
.name
= self
.sym_name
343 elif self
.tagtype
== 'enumitem' and self
.level
== 0:
348 #print "%-25s %-25s" % (self.name, self.sym_name)
349 old
= new
= self
.name
350 if old
.startswith('wx') and not old
.startswith('wxEVT_'):
351 # remove all wx prefixes except wxEVT_ and write a %rename directive for it
354 swigFile
.write("%%rename(%s) %35s;\n" % (new
, old
))
356 # Write assignments to import into the old wxPython namespace
357 if addWX
and not old
.startswith('wx'):
359 pyFile
.write("%s = wx.%s.%s\n" % (old
, moduleName
, new
))
361 pyFile
.write("%sPtr = wx.%s.%sPtr\n" % (old
, moduleName
, new
))
366 # text = "%07d %d %10s %-35s %s\n" % (
367 # self.startLine, self.level, self.tagtype, self.name, self.decl)
368 # #rejects.write(text)
372 #---------------------------------------------------------------------------
374 class ContentHandler(xml
.sax
.ContentHandler
):
375 def __init__(self
, modname
, swigFile
, pyFile
):
376 xml
.sax
.ContentHandler
.__init
__(self
)
377 self
.modname
= modname
378 self
.swigFile
= swigFile
383 self
.sym_klass
= None
386 def setDocumentLocator(self
, locator
):
387 self
.locator
= locator
391 def startElement(self
, name
, attrs
):
392 if name
in interestingTypes
:
393 # start of a new element that we are interested in
395 ce
.startLine
= self
.locator
.getLineNumber()
396 ce
.level
= len(self
.elements
)
397 if name
== 'constructor':
398 ce
.klass
= self
.elements
[0].name
400 ce
.klass
= self
.klass
401 ce
.sym_klass
= self
.sym_klass
402 self
.elements
.insert(0, ce
)
405 elif len(self
.elements
) and name
== 'attribute' and attrs
['name'] in interestingAttrs
:
406 attrName
= attrs
['name']
407 attrVal
= attrs
['value']
408 if attrName
.startswith('feature_'):
409 attrName
= attrName
.replace('feature_', '')
410 ce
= self
.elements
[0]
411 if getattr(ce
, attrName
) is None:
412 setattr(ce
, attrName
, attrVal
)
413 if ce
.tagtype
== 'class' and attrName
== 'name' and self
.klass
is None:
415 if ce
.tagtype
== 'class' and attrName
== 'sym_name' and self
.sym_klass
is None:
416 self
.sym_klass
= attrVal
419 ## elif len(self.elements) and name == 'attribute' and attrs['name'] == 'name':
420 ## # save the elements name
421 ## ce = self.elements[0]
422 ## if ce.name is None:
423 ## ce.name = attrs['value']
424 ## ce.nameLine = self.locator.getLineNumber()
426 ## elif len(self.elements) and name == 'attribute' and attrs['name'] == 'sym_name':
427 ## # save the elements name
428 ## ce = self.elements[0]
429 ## if ce.sym_name is None:
430 ## ce.sym_name = attrs['value']
432 ## elif len(self.elements) and name == 'attribute' and attrs['name'] == 'decl':
433 ## # save the elements decl
434 ## ce = self.elements[0]
435 ## ce.decl = attrs['value']
437 ## elif len(self.elements) and name == 'attribute' and attrs['name'] == 'feature_immutable':
438 ## # save the elements decl
439 ## ce = self.elements[0]
440 ## ce.immutable = int(attrs['value'])
442 ## elif len(self.elements) and name == 'attribute' and attrs['name'] == 'module':
443 ## # save the elements decl
444 ## ce = self.elements[0]
445 ## ce.module = attrs['value']
447 elif name
== 'import':
450 ## elif len(self.elements) and name == 'attribute' and attrs['name'] == 'storage':
451 ## # save the elements decl
452 ## ce = self.elements[0]
453 ## ce.storage = attrs['value']
455 ## elif len(self.elements) and name == 'attribute' and attrs['name'] == 'type':
456 ## # save the elements decl
457 ## ce = self.elements[0]
458 ## ce.type = attrs['value']
461 def endElement(self
, name
):
462 if name
in interestingTypes
:
463 # end of an element that we are interested in
464 ce
= self
.elements
.pop(0)
466 if self
.imports
== 0:
467 # only write for items that are in this file, not imported
468 ce
.write(self
.modname
, self
.swigFile
, self
.pyFile
)
475 self
.sym_klass
= None
478 #---------------------------------------------------------------------------
480 if __name__
== "__main__":