]>
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 open(dest
).read() != open(temp
).read():
127 os
.rename(temp
, dest
)
129 print dest
+ " not changed."
132 #---------------------------------------------------------------------------
135 def GetAttr(node
, name
):
136 path
= "./attributelist/attribute[@name='%s']/@value" % name
137 n
= node
.xpathEval2(path
)
144 def processXML(xmlfile
, modname
, swigFile
, pyFile
):
146 print "using libxml2..."
148 topnode
= libxml2
.parseFile(xmlfile
).children
150 # remove any import nodes as we don't need to do renamers for symbols found therein
151 imports
= topnode
.xpathEval2("*/import")
156 # do a depth first iteration over what's left
164 if node
.name
== "class":
165 lastClassName
= name
= GetAttr(node
, "name")
166 lastClassSymName
= sym_name
= GetAttr(node
, "sym_name")
173 # renamed constructors
174 elif node
.name
== "constructor":
175 name
= GetAttr(node
, "name")
176 sym_name
= GetAttr(node
, "sym_name")
182 # only enumitems at the top level
183 elif node
.name
== "enumitem" and node
.parent
.parent
.name
== "include":
184 name
= GetAttr(node
, "name")
185 sym_name
= GetAttr(node
, "sym_name")
189 elif node
.name
in ["cdecl", "constant"]:
190 name
= GetAttr(node
, "name")
191 sym_name
= GetAttr(node
, "sym_name")
192 toplevel
= node
.parent
.name
== "include"
194 # top-level functions
195 if toplevel
and GetAttr(node
, "view") == "globalfunctionHandler":
198 # top-level global vars
199 elif toplevel
and GetAttr(node
, "feature_immutable") == "1":
203 elif GetAttr(node
, "view") == "staticmemberfunctionHandler":
204 name
= lastClassName
+ '_' + name
205 sym_name
= lastClassSymName
+ '_' + sym_name
206 # only output the reverse renamer in this case
207 doRename
= revOnly
= True
209 if doRename
and name
!= sym_name
:
214 if doRename
and name
:
216 if old
.startswith('wx') and not old
.startswith('wxEVT_'):
217 # remove all wx prefixes except wxEVT_ and write a %rename directive for it
220 swigFile
.write("%%rename(%s) %35s;\n" % (new
, old
))
222 # Write assignments to import into the old wxPython namespace
223 if addWX
and not old
.startswith('wx'):
225 pyFile
.write("%s = wx.%s.%s\n" % (old
, modname
, new
))
227 pyFile
.write("%sPtr = wx.%s.%sPtr\n" % (old
, modname
, new
))
230 #---------------------------------------------------------------------------
232 def checkOtherNames(pyFile
, moduleName
, filename
):
233 if os
.path
.exists(filename
):
235 for line
in file(filename
):
236 if line
.endswith('\n'):
238 if line
and not line
.startswith('#'):
239 if line
.endswith('*'):
240 prefixes
.append(line
[:-1])
241 elif line
.find('=') != -1:
242 pyFile
.write("%s\n" % line
)
245 if line
.startswith('wx') or line
.startswith('WX') or line
.startswith('EVT'):
247 pyFile
.write("%s = wx.%s.%s\n" % (wxname
, moduleName
, line
))
251 "\n\nd = globals()\nfor k, v in wx.%s.__dict__.iteritems():"
256 pyFile
.write("\n if ")
259 pyFile
.write("\n elif ")
260 pyFile
.write("k.startswith('%s'):\n d[k] = v" % p
)
261 pyFile
.write("\ndel d, k, v\n\n")
264 #---------------------------------------------------------------------------
266 interestingTypes
= [ 'class', 'cdecl', 'enumitem', 'constructor', 'constant' ]
267 interestingAttrs
= [ 'name', 'sym_name', 'decl', 'feature_immutable', 'module',
272 def __init__(self
, tagtype
):
273 self
.tagtype
= tagtype
278 self
.immutable
= None
286 def write(self
, moduleName
, swigFile
, pyFile
):
292 #if self.name.find('DefaultPosition') != -1:
293 # pprint.pprint(self.__dict__)
295 if self
.tagtype
in ['cdecl', 'constant']:
296 if self
.storage
== 'typedef':
299 # top level functions
300 elif self
.level
== 0 and self
.decl
!= "":
303 # top level global vars
304 elif self
.level
== 0 and self
.immutable
== '1':
308 elif self
.storage
== 'static':
310 pprint
.pprint(self
.__dict
__)
312 self
.name
= self
.klass
+ '_' + self
.name
313 self
.sym_name
= self
.sym_klass
+ '_' + self
.sym_name
314 # only output the reverse renamer in this case
315 doRename
= revOnly
= True
319 if doRename
and self
.name
!= self
.sym_name
:
320 #print "%-25s %-25s" % (self.name, self.sym_name)
321 self
.name
= self
.sym_name
325 elif self
.tagtype
== 'class' and self
.module
== moduleName
:
328 if self
.sym_name
!= self
.klass
:
330 self
.name
= self
.sym_name
333 elif self
.tagtype
== 'constructor':
334 #print "%-25s %-25s" % (self.name, self.sym_name)
335 if self
.sym_name
!= self
.klass
:
337 self
.name
= self
.sym_name
341 elif self
.tagtype
== 'enumitem' and self
.level
== 0:
346 #print "%-25s %-25s" % (self.name, self.sym_name)
347 old
= new
= self
.name
348 if old
.startswith('wx') and not old
.startswith('wxEVT_'):
349 # remove all wx prefixes except wxEVT_ and write a %rename directive for it
352 swigFile
.write("%%rename(%s) %35s;\n" % (new
, old
))
354 # Write assignments to import into the old wxPython namespace
355 if addWX
and not old
.startswith('wx'):
357 pyFile
.write("%s = wx.%s.%s\n" % (old
, moduleName
, new
))
359 pyFile
.write("%sPtr = wx.%s.%sPtr\n" % (old
, moduleName
, new
))
364 # text = "%07d %d %10s %-35s %s\n" % (
365 # self.startLine, self.level, self.tagtype, self.name, self.decl)
366 # #rejects.write(text)
370 #---------------------------------------------------------------------------
372 class ContentHandler(xml
.sax
.ContentHandler
):
373 def __init__(self
, modname
, swigFile
, pyFile
):
374 xml
.sax
.ContentHandler
.__init
__(self
)
375 self
.modname
= modname
376 self
.swigFile
= swigFile
381 self
.sym_klass
= None
384 def setDocumentLocator(self
, locator
):
385 self
.locator
= locator
389 def startElement(self
, name
, attrs
):
390 if name
in interestingTypes
:
391 # start of a new element that we are interested in
393 ce
.startLine
= self
.locator
.getLineNumber()
394 ce
.level
= len(self
.elements
)
395 if name
== 'constructor':
396 ce
.klass
= self
.elements
[0].name
398 ce
.klass
= self
.klass
399 ce
.sym_klass
= self
.sym_klass
400 self
.elements
.insert(0, ce
)
403 elif len(self
.elements
) and name
== 'attribute' and attrs
['name'] in interestingAttrs
:
404 attrName
= attrs
['name']
405 attrVal
= attrs
['value']
406 if attrName
.startswith('feature_'):
407 attrName
= attrName
.replace('feature_', '')
408 ce
= self
.elements
[0]
409 if getattr(ce
, attrName
) is None:
410 setattr(ce
, attrName
, attrVal
)
411 if ce
.tagtype
== 'class' and attrName
== 'name' and self
.klass
is None:
413 if ce
.tagtype
== 'class' and attrName
== 'sym_name' and self
.sym_klass
is None:
414 self
.sym_klass
= attrVal
417 ## elif len(self.elements) and name == 'attribute' and attrs['name'] == 'name':
418 ## # save the elements name
419 ## ce = self.elements[0]
420 ## if ce.name is None:
421 ## ce.name = attrs['value']
422 ## ce.nameLine = self.locator.getLineNumber()
424 ## elif len(self.elements) and name == 'attribute' and attrs['name'] == 'sym_name':
425 ## # save the elements name
426 ## ce = self.elements[0]
427 ## if ce.sym_name is None:
428 ## ce.sym_name = attrs['value']
430 ## elif len(self.elements) and name == 'attribute' and attrs['name'] == 'decl':
431 ## # save the elements decl
432 ## ce = self.elements[0]
433 ## ce.decl = attrs['value']
435 ## elif len(self.elements) and name == 'attribute' and attrs['name'] == 'feature_immutable':
436 ## # save the elements decl
437 ## ce = self.elements[0]
438 ## ce.immutable = int(attrs['value'])
440 ## elif len(self.elements) and name == 'attribute' and attrs['name'] == 'module':
441 ## # save the elements decl
442 ## ce = self.elements[0]
443 ## ce.module = attrs['value']
445 elif name
== 'import':
448 ## elif len(self.elements) and name == 'attribute' and attrs['name'] == 'storage':
449 ## # save the elements decl
450 ## ce = self.elements[0]
451 ## ce.storage = attrs['value']
453 ## elif len(self.elements) and name == 'attribute' and attrs['name'] == 'type':
454 ## # save the elements decl
455 ## ce = self.elements[0]
456 ## ce.type = attrs['value']
459 def endElement(self
, name
):
460 if name
in interestingTypes
:
461 # end of an element that we are interested in
462 ce
= self
.elements
.pop(0)
464 if self
.imports
== 0:
465 # only write for items that are in this file, not imported
466 ce
.write(self
.modname
, self
.swigFile
, self
.pyFile
)
473 self
.sym_klass
= None
476 #---------------------------------------------------------------------------
478 if __name__
== "__main__":