home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2010 May / maximum-cd-2010-05.iso / DiscContents / boxee-0.9.20.10711.exe / system / python / Lib / plat-mac / gensuitemodule.pyo (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2009-07-20  |  38.8 KB  |  1,311 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyo (Python 2.4)
  3.  
  4. '''
  5. gensuitemodule - Generate an AE suite module from an aete/aeut resource
  6.  
  7. Based on aete.py.
  8.  
  9. Reading and understanding this code is left as an exercise to the reader.
  10. '''
  11. import MacOS
  12. import EasyDialogs
  13. import os
  14. import string
  15. import sys
  16. import types
  17. import StringIO
  18. import keyword
  19. import macresource
  20. import aetools
  21. import distutils.sysconfig as distutils
  22. import OSATerminology
  23. from Carbon.Res import *
  24. import Carbon.Folder as Carbon
  25. import MacOS
  26. import getopt
  27. import plistlib
  28. _MAC_LIB_FOLDER = os.path.dirname(aetools.__file__)
  29. DEFAULT_STANDARD_PACKAGEFOLDER = os.path.join(_MAC_LIB_FOLDER, 'lib-scriptpackages')
  30. DEFAULT_USER_PACKAGEFOLDER = distutils.sysconfig.get_python_lib()
  31.  
  32. def usage():
  33.     sys.stderr.write('Usage: %s [opts] application-or-resource-file\n' % sys.argv[0])
  34.     sys.stderr.write('Options:\n--output pkgdir  Pathname of the output package (short: -o)\n--resource       Parse resource file in stead of launching application (-r)\n--base package   Use another base package in stead of default StdSuites (-b)\n--edit old=new   Edit suite names, use empty new to skip a suite (-e)\n--creator code   Set creator code for package (-c)\n--dump           Dump aete resource to stdout in stead of creating module (-d)\n--verbose        Tell us what happens (-v)\n')
  35.     sys.exit(1)
  36.  
  37.  
  38. def main():
  39.     if len(sys.argv) > 1:
  40.         SHORTOPTS = 'rb:o:e:c:dv'
  41.         LONGOPTS = ('resource', 'base=', 'output=', 'edit=', 'creator=', 'dump', 'verbose')
  42.         
  43.         try:
  44.             (opts, args) = getopt.getopt(sys.argv[1:], SHORTOPTS, LONGOPTS)
  45.         except getopt.GetoptError:
  46.             usage()
  47.  
  48.         process_func = processfile
  49.         basepkgname = 'StdSuites'
  50.         output = None
  51.         edit_modnames = []
  52.         creatorsignature = None
  53.         dump = None
  54.         verbose = None
  55.         for o, a in opts:
  56.             if o in ('-r', '--resource'):
  57.                 process_func = processfile_fromresource
  58.             
  59.             if o in ('-b', '--base'):
  60.                 basepkgname = a
  61.             
  62.             if o in ('-o', '--output'):
  63.                 output = a
  64.             
  65.             if o in ('-e', '--edit'):
  66.                 split = a.split('=')
  67.                 if len(split) != 2:
  68.                     usage()
  69.                 
  70.                 edit_modnames.append(split)
  71.             
  72.             if o in ('-c', '--creator'):
  73.                 if len(a) != 4:
  74.                     sys.stderr.write('creator must be 4-char string\n')
  75.                     sys.exit(1)
  76.                 
  77.                 creatorsignature = a
  78.             
  79.             if o in ('-d', '--dump'):
  80.                 dump = sys.stdout
  81.             
  82.             if o in ('-v', '--verbose'):
  83.                 verbose = sys.stderr
  84.                 continue
  85.         
  86.         if output and len(args) > 1:
  87.             sys.stderr.write('%s: cannot specify --output with multiple inputs\n' % sys.argv[0])
  88.             sys.exit(1)
  89.         
  90.         for filename in args:
  91.             process_func(filename, output = output, basepkgname = basepkgname, edit_modnames = edit_modnames, creatorsignature = creatorsignature, dump = dump, verbose = verbose)
  92.         
  93.     else:
  94.         main_interactive()
  95.  
  96.  
  97. def main_interactive(interact = 0, basepkgname = 'StdSuites'):
  98.     if interact:
  99.         edit_modnames = None
  100.     else:
  101.         edit_modnames = []
  102.     appsfolder = Carbon.Folder.FSFindFolder(-32765, 'apps', 0)
  103.     filename = EasyDialogs.AskFileForOpen(message = 'Select scriptable application', dialogOptionFlags = 4182, defaultLocation = appsfolder)
  104.     if not filename:
  105.         return None
  106.     
  107.     if not is_scriptable(filename):
  108.         if EasyDialogs.AskYesNoCancel('Warning: application does not seem scriptable', yes = 'Continue', default = 2, no = '') <= 0:
  109.             return None
  110.         
  111.     
  112.     
  113.     try:
  114.         processfile(filename, edit_modnames = edit_modnames, basepkgname = basepkgname, verbose = sys.stderr)
  115.     except MacOS.Error:
  116.         arg = None
  117.         print 'Error getting terminology:', arg
  118.         print 'Retry, manually parsing resources'
  119.         processfile_fromresource(filename, edit_modnames = edit_modnames, basepkgname = basepkgname, verbose = sys.stderr)
  120.  
  121.  
  122.  
  123. def is_scriptable(application):
  124.     '''Return true if the application is scriptable'''
  125.     if os.path.isdir(application):
  126.         plistfile = os.path.join(application, 'Contents', 'Info.plist')
  127.         if not os.path.exists(plistfile):
  128.             return False
  129.         
  130.         plist = plistlib.Plist.fromFile(plistfile)
  131.         return plist.get('NSAppleScriptEnabled', False)
  132.     
  133.     currf = CurResFile()
  134.     
  135.     try:
  136.         refno = macresource.open_pathname(application)
  137.     except MacOS.Error:
  138.         return False
  139.  
  140.     UseResFile(refno)
  141.     n_terminology = Count1Resources('aete') + Count1Resources('aeut') + Count1Resources('scsz') + Count1Resources('osiz')
  142.     CloseResFile(refno)
  143.     UseResFile(currf)
  144.     return n_terminology > 0
  145.  
  146.  
  147. def processfile_fromresource(fullname, output = None, basepkgname = None, edit_modnames = None, creatorsignature = None, dump = None, verbose = None):
  148.     '''Process all resources in a single file'''
  149.     if not is_scriptable(fullname) and verbose:
  150.         print >>verbose, 'Warning: app does not seem scriptable: %s' % fullname
  151.     
  152.     cur = CurResFile()
  153.     if verbose:
  154.         print >>verbose, 'Processing', fullname
  155.     
  156.     rf = macresource.open_pathname(fullname)
  157.     
  158.     try:
  159.         UseResFile(rf)
  160.         resources = []
  161.         for i in range(Count1Resources('aete')):
  162.             res = Get1IndResource('aete', 1 + i)
  163.             resources.append(res)
  164.         
  165.         for i in range(Count1Resources('aeut')):
  166.             res = Get1IndResource('aeut', 1 + i)
  167.             resources.append(res)
  168.         
  169.         if verbose:
  170.             print >>verbose, '\nLISTING aete+aeut RESOURCES IN', repr(fullname)
  171.         
  172.         aetelist = []
  173.         for res in resources:
  174.             if verbose:
  175.                 print >>verbose, 'decoding', res.GetResInfo(), '...'
  176.             
  177.             data = res.data
  178.             aete = decode(data, verbose)
  179.             aetelist.append((aete, res.GetResInfo()))
  180.     finally:
  181.         if rf != cur:
  182.             CloseResFile(rf)
  183.             UseResFile(cur)
  184.         
  185.  
  186.     UseResFile(cur)
  187.     if dump:
  188.         dumpaetelist(aetelist, dump)
  189.     
  190.     compileaetelist(aetelist, fullname, output = output, basepkgname = basepkgname, edit_modnames = edit_modnames, creatorsignature = creatorsignature, verbose = verbose)
  191.  
  192.  
  193. def processfile(fullname, output = None, basepkgname = None, edit_modnames = None, creatorsignature = None, dump = None, verbose = None):
  194.     '''Ask an application for its terminology and process that'''
  195.     if not is_scriptable(fullname) and verbose:
  196.         print >>verbose, 'Warning: app does not seem scriptable: %s' % fullname
  197.     
  198.     if verbose:
  199.         print >>verbose, '\nASKING FOR aete DICTIONARY IN', repr(fullname)
  200.     
  201.     
  202.     try:
  203.         (aedescobj, launched) = OSATerminology.GetAppTerminology(fullname)
  204.     except MacOS.Error:
  205.         arg = None
  206.         if arg[0] in (-1701, -192):
  207.             if verbose:
  208.                 print >>verbose, 'GetAppTerminology failed with errAEDescNotFound/resNotFound, trying manually'
  209.             
  210.             (aedata, sig) = getappterminology(fullname, verbose = verbose)
  211.             if not creatorsignature:
  212.                 creatorsignature = sig
  213.             
  214.         else:
  215.             raise 
  216.     except:
  217.         arg[0] in (-1701, -192)
  218.  
  219.     if launched:
  220.         if verbose:
  221.             print >>verbose, 'Launched', fullname
  222.         
  223.     
  224.     raw = aetools.unpack(aedescobj)
  225.     if not raw:
  226.         if verbose:
  227.             print >>verbose, 'Unpack returned empty value:', raw
  228.         
  229.         return None
  230.     
  231.     if not raw[0].data:
  232.         if verbose:
  233.             print >>verbose, 'Unpack returned value without data:', raw
  234.         
  235.         return None
  236.     
  237.     aedata = raw[0]
  238.     aete = decode(aedata.data, verbose)
  239.     if dump:
  240.         dumpaetelist([
  241.             aete], dump)
  242.         return None
  243.     
  244.     compileaete(aete, None, fullname, output = output, basepkgname = basepkgname, creatorsignature = creatorsignature, edit_modnames = edit_modnames, verbose = verbose)
  245.  
  246.  
  247. def getappterminology(fullname, verbose = None):
  248.     '''Get application terminology by sending an AppleEvent'''
  249.     if not MacOS.WMAvailable():
  250.         raise RuntimeError, 'Cannot send AppleEvents, no access to window manager'
  251.     
  252.     import Carbon.Evt as Carbon
  253.     Carbon.Evt.WaitNextEvent(0, 0)
  254.     if os.path.isdir(fullname):
  255.         pkginfo = os.path.join(fullname, 'Contents', 'PkgInfo')
  256.         if not os.path.exists(pkginfo):
  257.             raise RuntimeError, 'No PkgInfo file found'
  258.         
  259.         tp_cr = open(pkginfo, 'rb').read()
  260.         cr = tp_cr[4:8]
  261.     else:
  262.         (cr, tp) = MacOS.GetCreatorAndType(fullname)
  263.     talker = aetools.TalkTo(cr)
  264.     
  265.     try:
  266.         talker._start()
  267.     except (MacOS.Error, aetools.Error):
  268.         arg = None
  269.         if verbose:
  270.             print >>verbose, 'Warning: start() failed, continuing anyway:', arg
  271.         
  272.     except:
  273.         verbose
  274.  
  275.     reply = talker.send('ascr', 'gdte')
  276.     return (reply[1]['----'], cr)
  277.  
  278.  
  279. def compileaetelist(aetelist, fullname, output = None, basepkgname = None, edit_modnames = None, creatorsignature = None, verbose = None):
  280.     for aete, resinfo in aetelist:
  281.         compileaete(aete, resinfo, fullname, output = output, basepkgname = basepkgname, edit_modnames = edit_modnames, creatorsignature = creatorsignature, verbose = verbose)
  282.     
  283.  
  284.  
  285. def dumpaetelist(aetelist, output):
  286.     import pprint
  287.     pprint.pprint(aetelist, output)
  288.  
  289.  
  290. def decode(data, verbose = None):
  291.     '''Decode a resource into a python data structure'''
  292.     f = StringIO.StringIO(data)
  293.     aete = generic(getaete, f)
  294.     aete = simplify(aete)
  295.     processed = f.tell()
  296.     unprocessed = len(f.read())
  297.     total = f.tell()
  298.     if unprocessed and verbose:
  299.         verbose.write('%d processed + %d unprocessed = %d total\n' % (processed, unprocessed, total))
  300.     
  301.     return aete
  302.  
  303.  
  304. def simplify(item):
  305.     '''Recursively replace singleton tuples by their constituent item'''
  306.     if type(item) is types.ListType:
  307.         return map(simplify, item)
  308.     elif type(item) == types.TupleType and len(item) == 2:
  309.         return simplify(item[1])
  310.     else:
  311.         return item
  312.  
  313.  
  314. def getbyte(f, *args):
  315.     c = f.read(1)
  316.     if not c:
  317.         raise EOFError, 'in getbyte' + str(args)
  318.     
  319.     return ord(c)
  320.  
  321.  
  322. def getword(f, *args):
  323.     getalign(f)
  324.     s = f.read(2)
  325.     if len(s) < 2:
  326.         raise EOFError, 'in getword' + str(args)
  327.     
  328.     return ord(s[0]) << 8 | ord(s[1])
  329.  
  330.  
  331. def getlong(f, *args):
  332.     getalign(f)
  333.     s = f.read(4)
  334.     if len(s) < 4:
  335.         raise EOFError, 'in getlong' + str(args)
  336.     
  337.     return ord(s[0]) << 24 | ord(s[1]) << 16 | ord(s[2]) << 8 | ord(s[3])
  338.  
  339.  
  340. def getostype(f, *args):
  341.     getalign(f)
  342.     s = f.read(4)
  343.     if len(s) < 4:
  344.         raise EOFError, 'in getostype' + str(args)
  345.     
  346.     return s
  347.  
  348.  
  349. def getpstr(f, *args):
  350.     c = f.read(1)
  351.     if len(c) < 1:
  352.         raise EOFError, 'in getpstr[1]' + str(args)
  353.     
  354.     nbytes = ord(c)
  355.     if nbytes == 0:
  356.         return ''
  357.     
  358.     s = f.read(nbytes)
  359.     if len(s) < nbytes:
  360.         raise EOFError, 'in getpstr[2]' + str(args)
  361.     
  362.     return s
  363.  
  364.  
  365. def getalign(f):
  366.     if f.tell() & 1:
  367.         c = f.read(1)
  368.     
  369.  
  370.  
  371. def getlist(f, description, getitem):
  372.     count = getword(f)
  373.     list = []
  374.     for i in range(count):
  375.         list.append(generic(getitem, f))
  376.         getalign(f)
  377.     
  378.     return list
  379.  
  380.  
  381. def alt_generic(what, f, *args):
  382.     print 'generic', repr(what), args
  383.     res = vageneric(what, f, args)
  384.     print '->', repr(res)
  385.     return res
  386.  
  387.  
  388. def generic(what, f, *args):
  389.     if type(what) == types.FunctionType:
  390.         return apply(what, (f,) + args)
  391.     
  392.     if type(what) == types.ListType:
  393.         record = []
  394.         for thing in what:
  395.             item = apply(generic, thing[:1] + (f,) + thing[1:])
  396.             record.append((thing[1], item))
  397.         
  398.         return record
  399.     
  400.     return 'BAD GENERIC ARGS: %r' % (what,)
  401.  
  402. getdata = [
  403.     (getostype, 'type'),
  404.     (getpstr, 'description'),
  405.     (getword, 'flags')]
  406. getargument = [
  407.     (getpstr, 'name'),
  408.     (getostype, 'keyword'),
  409.     (getdata, 'what')]
  410. getevent = [
  411.     (getpstr, 'name'),
  412.     (getpstr, 'description'),
  413.     (getostype, 'suite code'),
  414.     (getostype, 'event code'),
  415.     (getdata, 'returns'),
  416.     (getdata, 'accepts'),
  417.     (getlist, 'optional arguments', getargument)]
  418. getproperty = [
  419.     (getpstr, 'name'),
  420.     (getostype, 'code'),
  421.     (getdata, 'what')]
  422. getelement = [
  423.     (getostype, 'type'),
  424.     (getlist, 'keyform', getostype)]
  425. getclass = [
  426.     (getpstr, 'name'),
  427.     (getostype, 'class code'),
  428.     (getpstr, 'description'),
  429.     (getlist, 'properties', getproperty),
  430.     (getlist, 'elements', getelement)]
  431. getcomparison = [
  432.     (getpstr, 'operator name'),
  433.     (getostype, 'operator ID'),
  434.     (getpstr, 'operator comment')]
  435. getenumerator = [
  436.     (getpstr, 'enumerator name'),
  437.     (getostype, 'enumerator ID'),
  438.     (getpstr, 'enumerator comment')]
  439. getenumeration = [
  440.     (getostype, 'enumeration ID'),
  441.     (getlist, 'enumerator', getenumerator)]
  442. getsuite = [
  443.     (getpstr, 'suite name'),
  444.     (getpstr, 'suite description'),
  445.     (getostype, 'suite ID'),
  446.     (getword, 'suite level'),
  447.     (getword, 'suite version'),
  448.     (getlist, 'events', getevent),
  449.     (getlist, 'classes', getclass),
  450.     (getlist, 'comparisons', getcomparison),
  451.     (getlist, 'enumerations', getenumeration)]
  452. getaete = [
  453.     (getword, 'major/minor version in BCD'),
  454.     (getword, 'language code'),
  455.     (getword, 'script code'),
  456.     (getlist, 'suites', getsuite)]
  457.  
  458. def compileaete(aete, resinfo, fname, output = None, basepkgname = None, edit_modnames = None, creatorsignature = None, verbose = None):
  459.     '''Generate code for a full aete resource. fname passed for doc purposes'''
  460.     (version, language, script, suites) = aete
  461.     (major, minor) = divmod(version, 256)
  462.     if not creatorsignature:
  463.         (creatorsignature, dummy) = MacOS.GetCreatorAndType(fname)
  464.     
  465.     packagename = identify(os.path.splitext(os.path.basename(fname))[0])
  466.     if language:
  467.         packagename = packagename + '_lang%d' % language
  468.     
  469.     if script:
  470.         packagename = packagename + '_script%d' % script
  471.     
  472.     if len(packagename) > 27:
  473.         packagename = packagename[:27]
  474.     
  475.     if output:
  476.         if not os.path.exists(output):
  477.             os.mkdir(output)
  478.         
  479.         pathname = output
  480.     else:
  481.         pathname = EasyDialogs.AskFolder(message = 'Create and select package folder for %s' % packagename, defaultLocation = DEFAULT_USER_PACKAGEFOLDER)
  482.         output = pathname
  483.     if not pathname:
  484.         return None
  485.     
  486.     packagename = os.path.split(os.path.normpath(pathname))[1]
  487.     if not basepkgname:
  488.         basepkgname = EasyDialogs.AskFolder(message = 'Package folder for base suite (usually StdSuites)', defaultLocation = DEFAULT_STANDARD_PACKAGEFOLDER)
  489.     
  490.     if basepkgname:
  491.         (dirname, basepkgname) = os.path.split(os.path.normpath(basepkgname))
  492.         if dirname and dirname not in sys.path:
  493.             sys.path.insert(0, dirname)
  494.         
  495.         basepackage = __import__(basepkgname)
  496.     else:
  497.         basepackage = None
  498.     suitelist = []
  499.     allprecompinfo = []
  500.     allsuites = []
  501.     for suite in suites:
  502.         compiler = SuiteCompiler(suite, basepackage, output, edit_modnames, verbose)
  503.         (code, modname, precompinfo) = compiler.precompilesuite()
  504.         if not code:
  505.             continue
  506.         
  507.         allprecompinfo = allprecompinfo + precompinfo
  508.         suiteinfo = (suite, pathname, modname)
  509.         suitelist.append((code, modname))
  510.         allsuites.append(compiler)
  511.     
  512.     for compiler in allsuites:
  513.         compiler.compilesuite(major, minor, language, script, fname, allprecompinfo)
  514.     
  515.     initfilename = os.path.join(output, '__init__.py')
  516.     fp = open(initfilename, 'w')
  517.     MacOS.SetCreatorAndType(initfilename, 'Pyth', 'TEXT')
  518.     fp.write('"""\n')
  519.     fp.write('Package generated from %s\n' % ascii(fname))
  520.     if resinfo:
  521.         fp.write('Resource %s resid %d %s\n' % (ascii(resinfo[1]), resinfo[0], ascii(resinfo[2])))
  522.     
  523.     fp.write('"""\n')
  524.     fp.write('import aetools\n')
  525.     fp.write('Error = aetools.Error\n')
  526.     suitelist.sort()
  527.     for code, modname in suitelist:
  528.         fp.write('import %s\n' % modname)
  529.     
  530.     fp.write('\n\n_code_to_module = {\n')
  531.     for code, modname in suitelist:
  532.         fp.write("    '%s' : %s,\n" % (ascii(code), modname))
  533.     
  534.     fp.write('}\n\n')
  535.     fp.write('\n\n_code_to_fullname = {\n')
  536.     for code, modname in suitelist:
  537.         fp.write("    '%s' : ('%s.%s', '%s'),\n" % (ascii(code), packagename, modname, modname))
  538.     
  539.     fp.write('}\n\n')
  540.     for code, modname in suitelist:
  541.         fp.write('from %s import *\n' % modname)
  542.     
  543.     fp.write('\ndef getbaseclasses(v):\n')
  544.     fp.write("    if not getattr(v, '_propdict', None):\n")
  545.     fp.write('        v._propdict = {}\n')
  546.     fp.write('        v._elemdict = {}\n')
  547.     fp.write("        for superclassname in getattr(v, '_superclassnames', []):\n")
  548.     fp.write('            superclass = eval(superclassname)\n')
  549.     fp.write('            getbaseclasses(superclass)\n')
  550.     fp.write("            v._propdict.update(getattr(superclass, '_propdict', {}))\n")
  551.     fp.write("            v._elemdict.update(getattr(superclass, '_elemdict', {}))\n")
  552.     fp.write("        v._propdict.update(getattr(v, '_privpropdict', {}))\n")
  553.     fp.write("        v._elemdict.update(getattr(v, '_privelemdict', {}))\n")
  554.     fp.write('\n')
  555.     fp.write('import StdSuites\n')
  556.     allprecompinfo.sort()
  557.     if allprecompinfo:
  558.         fp.write('\n#\n# Set property and element dictionaries now that all classes have been defined\n#\n')
  559.         for codenamemapper in allprecompinfo:
  560.             for k, v in codenamemapper.getall('class'):
  561.                 fp.write('getbaseclasses(%s)\n' % v)
  562.             
  563.         
  564.     
  565.     application_class = None
  566.     if allprecompinfo:
  567.         fp.write('\n#\n# Indices of types declared in this module\n#\n')
  568.         fp.write('_classdeclarations = {\n')
  569.         for codenamemapper in allprecompinfo:
  570.             for k, v in codenamemapper.getall('class'):
  571.                 fp.write('    %r : %s,\n' % (k, v))
  572.                 if k == 'capp':
  573.                     application_class = v
  574.                     continue
  575.             
  576.         
  577.         fp.write('}\n')
  578.     
  579.     if suitelist:
  580.         fp.write('\n\nclass %s(%s_Events' % (packagename, suitelist[0][1]))
  581.         for code, modname in suitelist[1:]:
  582.             fp.write(',\n        %s_Events' % modname)
  583.         
  584.         fp.write(',\n        aetools.TalkTo):\n')
  585.         fp.write('    _signature = %r\n\n' % (creatorsignature,))
  586.         fp.write("    _moduleName = '%s'\n\n" % packagename)
  587.         if application_class:
  588.             fp.write('    _elemdict = %s._elemdict\n' % application_class)
  589.             fp.write('    _propdict = %s._propdict\n' % application_class)
  590.         
  591.     
  592.     fp.close()
  593.  
  594.  
  595. class SuiteCompiler:
  596.     
  597.     def __init__(self, suite, basepackage, output, edit_modnames, verbose):
  598.         self.suite = suite
  599.         self.basepackage = basepackage
  600.         self.edit_modnames = edit_modnames
  601.         self.output = output
  602.         self.verbose = verbose
  603.         self.pathname = None
  604.         self.modname = None
  605.         self.fp = None
  606.         self.basemodule = None
  607.         self.enumsneeded = { }
  608.  
  609.     
  610.     def precompilesuite(self):
  611.         '''Parse a single suite without generating the output. This step is needed
  612.         so we can resolve recursive references by suites to enums/comps/etc declared
  613.         in other suites'''
  614.         (name, desc, code, level, version, events, classes, comps, enums) = self.suite
  615.         modname = identify(name)
  616.         if len(modname) > 28:
  617.             modname = modname[:27]
  618.         
  619.         if self.edit_modnames is None:
  620.             self.pathname = EasyDialogs.AskFileForSave(message = 'Python output file', savedFileName = modname + '.py')
  621.         else:
  622.             for old, new in self.edit_modnames:
  623.                 if old == modname:
  624.                     modname = new
  625.                     continue
  626.             
  627.             if modname:
  628.                 self.pathname = os.path.join(self.output, modname + '.py')
  629.             else:
  630.                 self.pathname = None
  631.         if not self.pathname:
  632.             return (None, None, None)
  633.         
  634.         self.modname = os.path.splitext(os.path.split(self.pathname)[1])[0]
  635.         if self.basepackage and self.basepackage._code_to_module.has_key(code):
  636.             basemodule = self.basepackage._code_to_module[code]
  637.         else:
  638.             basemodule = None
  639.         self.enumsneeded = { }
  640.         for event in events:
  641.             self.findenumsinevent(event)
  642.         
  643.         objc = ObjectCompiler(None, self.modname, basemodule, interact = self.edit_modnames is None, verbose = self.verbose)
  644.         for cls in classes:
  645.             objc.compileclass(cls)
  646.         
  647.         for cls in classes:
  648.             objc.fillclasspropsandelems(cls)
  649.         
  650.         for comp in comps:
  651.             objc.compilecomparison(comp)
  652.         
  653.         for enum in enums:
  654.             objc.compileenumeration(enum)
  655.         
  656.         for enum in self.enumsneeded.keys():
  657.             objc.checkforenum(enum)
  658.         
  659.         objc.dumpindex()
  660.         precompinfo = objc.getprecompinfo(self.modname)
  661.         return (code, self.modname, precompinfo)
  662.  
  663.     
  664.     def compilesuite(self, major, minor, language, script, fname, precompinfo):
  665.         '''Generate code for a single suite'''
  666.         (name, desc, code, level, version, events, classes, comps, enums) = self.suite
  667.         
  668.         def class_sorter(k1, k2):
  669.             '''Sort classes by code, and make sure main class sorts before synonyms'''
  670.             if k1[1] < k2[1]:
  671.                 return -1
  672.             
  673.             if k1[1] > k2[1]:
  674.                 return 1
  675.             
  676.             if not k2[3] or k2[3][0][1] == 'c@#!':
  677.                 return -1
  678.             
  679.             if not k1[3] or k1[3][0][1] == 'c@#!':
  680.                 return 1
  681.             
  682.             return 0
  683.  
  684.         events.sort()
  685.         classes.sort(class_sorter)
  686.         comps.sort()
  687.         enums.sort()
  688.         self.fp = fp = open(self.pathname, 'w')
  689.         MacOS.SetCreatorAndType(self.pathname, 'Pyth', 'TEXT')
  690.         fp.write('"""Suite %s: %s\n' % (ascii(name), ascii(desc)))
  691.         fp.write('Level %d, version %d\n\n' % (level, version))
  692.         fp.write('Generated from %s\n' % ascii(fname))
  693.         fp.write('AETE/AEUT resource version %d/%d, language %d, script %d\n' % (major, minor, language, script))
  694.         fp.write('"""\n\n')
  695.         fp.write('import aetools\n')
  696.         fp.write('import MacOS\n\n')
  697.         fp.write('_code = %r\n\n' % (code,))
  698.         if self.basepackage and self.basepackage._code_to_module.has_key(code):
  699.             fp.write('from %s import *\n' % self.basepackage._code_to_fullname[code][0])
  700.             basemodule = self.basepackage._code_to_module[code]
  701.         elif self.basepackage and self.basepackage._code_to_module.has_key(code.lower()):
  702.             fp.write('from %s import *\n' % self.basepackage._code_to_fullname[code.lower()][0])
  703.             basemodule = self.basepackage._code_to_module[code.lower()]
  704.         else:
  705.             basemodule = None
  706.         self.basemodule = basemodule
  707.         self.compileclassheader()
  708.         self.enumsneeded = { }
  709.         if events:
  710.             for event in events:
  711.                 self.compileevent(event)
  712.             
  713.         else:
  714.             fp.write('    pass\n\n')
  715.         objc = ObjectCompiler(fp, self.modname, basemodule, precompinfo, interact = self.edit_modnames is None, verbose = self.verbose)
  716.         for cls in classes:
  717.             objc.compileclass(cls)
  718.         
  719.         for cls in classes:
  720.             objc.fillclasspropsandelems(cls)
  721.         
  722.         for comp in comps:
  723.             objc.compilecomparison(comp)
  724.         
  725.         for enum in enums:
  726.             objc.compileenumeration(enum)
  727.         
  728.         for enum in self.enumsneeded.keys():
  729.             objc.checkforenum(enum)
  730.         
  731.         objc.dumpindex()
  732.  
  733.     
  734.     def compileclassheader(self):
  735.         '''Generate class boilerplate'''
  736.         classname = '%s_Events' % self.modname
  737.         if self.basemodule:
  738.             modshortname = string.split(self.basemodule.__name__, '.')[-1]
  739.             baseclassname = '%s_Events' % modshortname
  740.             self.fp.write('class %s(%s):\n\n' % (classname, baseclassname))
  741.         else:
  742.             self.fp.write('class %s:\n\n' % classname)
  743.  
  744.     
  745.     def compileevent(self, event):
  746.         '''Generate code for a single event'''
  747.         (name, desc, code, subcode, returns, accepts, arguments) = event
  748.         fp = self.fp
  749.         funcname = identify(name)
  750.         if arguments:
  751.             fp.write('    _argmap_%s = {\n' % funcname)
  752.             for a in arguments:
  753.                 fp.write('        %r : %r,\n' % (identify(a[0]), a[1]))
  754.             
  755.             fp.write('    }\n\n')
  756.         
  757.         has_arg = not is_null(accepts)
  758.         if has_arg:
  759.             pass
  760.         opt_arg = is_optional(accepts)
  761.         fp.write('    def %s(self, ' % funcname)
  762.         if has_arg:
  763.             if not opt_arg:
  764.                 fp.write('_object, ')
  765.             else:
  766.                 fp.write('_object=None, ')
  767.         else:
  768.             fp.write('_no_object=None, ')
  769.         fp.write('_attributes={}, **_arguments):\n')
  770.         fp.write('        """%s: %s\n' % (ascii(name), ascii(desc)))
  771.         if has_arg:
  772.             fp.write('        Required argument: %s\n' % getdatadoc(accepts))
  773.         elif opt_arg:
  774.             fp.write('        Optional argument: %s\n' % getdatadoc(accepts))
  775.         
  776.         for arg in arguments:
  777.             fp.write('        Keyword argument %s: %s\n' % (identify(arg[0]), getdatadoc(arg[2])))
  778.         
  779.         fp.write('        Keyword argument _attributes: AppleEvent attribute dictionary\n')
  780.         if not is_null(returns):
  781.             fp.write('        Returns: %s\n' % getdatadoc(returns))
  782.         
  783.         fp.write('        """\n')
  784.         fp.write('        _code = %r\n' % (code,))
  785.         fp.write('        _subcode = %r\n\n' % (subcode,))
  786.         if arguments:
  787.             fp.write('        aetools.keysubst(_arguments, self._argmap_%s)\n' % funcname)
  788.         else:
  789.             fp.write("        if _arguments: raise TypeError, 'No optional args expected'\n")
  790.         if has_arg:
  791.             fp.write("        _arguments['----'] = _object\n")
  792.         elif opt_arg:
  793.             fp.write('        if _object:\n')
  794.             fp.write("            _arguments['----'] = _object\n")
  795.         else:
  796.             fp.write("        if _no_object != None: raise TypeError, 'No direct arg expected'\n")
  797.         fp.write('\n')
  798.         for a in arguments:
  799.             if is_enum(a[2]):
  800.                 kname = a[1]
  801.                 ename = a[2][0]
  802.                 if ename != '****':
  803.                     fp.write('        aetools.enumsubst(_arguments, %r, _Enum_%s)\n' % (kname, identify(ename)))
  804.                     self.enumsneeded[ename] = 1
  805.                 
  806.             ename != '****'
  807.         
  808.         fp.write('\n')
  809.         fp.write('        _reply, _arguments, _attributes = self.send(_code, _subcode,\n')
  810.         fp.write('                _arguments, _attributes)\n')
  811.         fp.write("        if _arguments.get('errn', 0):\n")
  812.         fp.write('            raise aetools.Error, aetools.decodeerror(_arguments)\n')
  813.         fp.write('        # XXXX Optionally decode result\n')
  814.         fp.write("        if _arguments.has_key('----'):\n")
  815.         if is_enum(returns):
  816.             fp.write('            # XXXX Should do enum remapping here...\n')
  817.         
  818.         fp.write("            return _arguments['----']\n")
  819.         fp.write('\n')
  820.  
  821.     
  822.     def findenumsinevent(self, event):
  823.         '''Find all enums for a single event'''
  824.         (name, desc, code, subcode, returns, accepts, arguments) = event
  825.         for a in arguments:
  826.             if is_enum(a[2]):
  827.                 ename = a[2][0]
  828.                 if ename != '****':
  829.                     self.enumsneeded[ename] = 1
  830.                 
  831.             ename != '****'
  832.         
  833.  
  834.  
  835.  
  836. class CodeNameMapper:
  837.     
  838.     def __init__(self, interact = 1, verbose = None):
  839.         self.code2name = {
  840.             'property': { },
  841.             'class': { },
  842.             'enum': { },
  843.             'comparison': { } }
  844.         self.name2code = {
  845.             'property': { },
  846.             'class': { },
  847.             'enum': { },
  848.             'comparison': { } }
  849.         self.modulename = None
  850.         self.star_imported = 0
  851.         self.can_interact = interact
  852.         self.verbose = verbose
  853.  
  854.     
  855.     def addnamecode(self, type, name, code):
  856.         self.name2code[type][name] = code
  857.         if not self.code2name[type].has_key(code):
  858.             self.code2name[type][code] = name
  859.         
  860.  
  861.     
  862.     def hasname(self, name):
  863.         for dict in self.name2code.values():
  864.             if dict.has_key(name):
  865.                 return True
  866.                 continue
  867.         
  868.         return False
  869.  
  870.     
  871.     def hascode(self, type, code):
  872.         return self.code2name[type].has_key(code)
  873.  
  874.     
  875.     def findcodename(self, type, code):
  876.         if not self.hascode(type, code):
  877.             return (None, None, None)
  878.         
  879.         name = self.code2name[type][code]
  880.         if self.modulename and not (self.star_imported):
  881.             qualname = '%s.%s' % (self.modulename, name)
  882.         else:
  883.             qualname = name
  884.         return (name, qualname, self.modulename)
  885.  
  886.     
  887.     def getall(self, type):
  888.         return self.code2name[type].items()
  889.  
  890.     
  891.     def addmodule(self, module, name, star_imported):
  892.         self.modulename = name
  893.         self.star_imported = star_imported
  894.         for code, name in module._propdeclarations.items():
  895.             self.addnamecode('property', name, code)
  896.         
  897.         for code, name in module._classdeclarations.items():
  898.             self.addnamecode('class', name, code)
  899.         
  900.         for code in module._enumdeclarations.keys():
  901.             self.addnamecode('enum', '_Enum_' + identify(code), code)
  902.         
  903.         for code, name in module._compdeclarations.items():
  904.             self.addnamecode('comparison', name, code)
  905.         
  906.  
  907.     
  908.     def prepareforexport(self, name = None):
  909.         if not self.modulename:
  910.             self.modulename = name
  911.         
  912.         return self
  913.  
  914.  
  915.  
  916. class ObjectCompiler:
  917.     
  918.     def __init__(self, fp, modname, basesuite, othernamemappers = None, interact = 1, verbose = None):
  919.         self.fp = fp
  920.         self.verbose = verbose
  921.         self.basesuite = basesuite
  922.         self.can_interact = interact
  923.         self.modulename = modname
  924.         self.namemappers = [
  925.             CodeNameMapper(self.can_interact, self.verbose)]
  926.         if othernamemappers:
  927.             self.othernamemappers = othernamemappers[:]
  928.         else:
  929.             self.othernamemappers = []
  930.         if basesuite:
  931.             basemapper = CodeNameMapper(self.can_interact, self.verbose)
  932.             basemapper.addmodule(basesuite, '', 1)
  933.             self.namemappers.append(basemapper)
  934.         
  935.  
  936.     
  937.     def getprecompinfo(self, modname):
  938.         list = []
  939.         for mapper in self.namemappers:
  940.             emapper = mapper.prepareforexport(modname)
  941.             if emapper:
  942.                 list.append(emapper)
  943.                 continue
  944.         
  945.         return list
  946.  
  947.     
  948.     def findcodename(self, type, code):
  949.         while None:
  950.             for mapper in self.namemappers:
  951.                 if mapper.hascode(type, code):
  952.                     return mapper.findcodename(type, code)
  953.                     continue
  954.             
  955.             for mapper in self.othernamemappers:
  956.                 if mapper.hascode(type, code):
  957.                     self.othernamemappers.remove(mapper)
  958.                     self.namemappers.append(mapper)
  959.                     if self.fp:
  960.                         self.fp.write('import %s\n' % mapper.modulename)
  961.                     
  962.                     break
  963.                     continue
  964.             elif self.fp:
  965.                 m = self.askdefinitionmodule(type, code)
  966.             else:
  967.                 m = None
  968.             if not m:
  969.                 return (None, None, None)
  970.             
  971.             mapper = CodeNameMapper(self.can_interact, self.verbose)
  972.             self.namemappers.append(mapper)
  973.  
  974.     
  975.     def hasname(self, name):
  976.         for mapper in self.othernamemappers:
  977.             if mapper.hasname(name) and mapper.modulename != self.modulename:
  978.                 if self.verbose:
  979.                     print >>self.verbose, 'Duplicate Python identifier:', name, self.modulename, mapper.modulename
  980.                 
  981.                 return True
  982.                 continue
  983.         
  984.         return False
  985.  
  986.     
  987.     def askdefinitionmodule(self, type, code):
  988.         if not self.can_interact:
  989.             if self.verbose:
  990.                 print >>self.verbose, "** No definition for %s '%s' found" % (type, code)
  991.             
  992.             return None
  993.         
  994.         path = EasyDialogs.AskFileForSave(message = 'Where is %s %s declared?' % (type, code))
  995.         if not path:
  996.             return None
  997.         
  998.         (path, file) = os.path.split(path)
  999.         modname = os.path.splitext(file)[0]
  1000.         if path not in sys.path:
  1001.             sys.path.insert(0, path)
  1002.         
  1003.         m = __import__(modname)
  1004.         self.fp.write('import %s\n' % modname)
  1005.         return m
  1006.  
  1007.     
  1008.     def compileclass(self, cls):
  1009.         (name, code, desc, properties, elements) = cls
  1010.         pname = identify(name)
  1011.         if self.namemappers[0].hascode('class', code):
  1012.             (othername, dummy, dummy) = self.namemappers[0].findcodename('class', code)
  1013.             if self.fp:
  1014.                 self.fp.write('\n%s = %s\n' % (pname, othername))
  1015.             
  1016.         elif self.fp:
  1017.             self.fp.write('\nclass %s(aetools.ComponentItem):\n' % pname)
  1018.             self.fp.write('    """%s - %s """\n' % (ascii(name), ascii(desc)))
  1019.             self.fp.write('    want = %r\n' % (code,))
  1020.         
  1021.         self.namemappers[0].addnamecode('class', pname, code)
  1022.         is_application_class = code == 'capp'
  1023.         properties.sort()
  1024.         for prop in properties:
  1025.             self.compileproperty(prop, is_application_class)
  1026.         
  1027.         elements.sort()
  1028.         for elem in elements:
  1029.             self.compileelement(elem)
  1030.         
  1031.  
  1032.     
  1033.     def compileproperty(self, prop, is_application_class = False):
  1034.         (name, code, what) = prop
  1035.         if code == 'c@#!':
  1036.             return None
  1037.         
  1038.         pname = identify(name)
  1039.         if self.namemappers[0].hascode('property', code):
  1040.             (othername, dummy, dummy) = self.namemappers[0].findcodename('property', code)
  1041.             if pname == othername:
  1042.                 return None
  1043.             
  1044.             if self.fp:
  1045.                 self.fp.write('\n_Prop_%s = _Prop_%s\n' % (pname, othername))
  1046.             
  1047.         elif self.fp:
  1048.             self.fp.write('class _Prop_%s(aetools.NProperty):\n' % pname)
  1049.             self.fp.write('    """%s - %s """\n' % (ascii(name), ascii(what[1])))
  1050.             self.fp.write('    which = %r\n' % (code,))
  1051.             self.fp.write('    want = %r\n' % (what[0],))
  1052.         
  1053.         self.namemappers[0].addnamecode('property', pname, code)
  1054.         if is_application_class and self.fp:
  1055.             self.fp.write('%s = _Prop_%s()\n' % (pname, pname))
  1056.         
  1057.  
  1058.     
  1059.     def compileelement(self, elem):
  1060.         (code, keyform) = elem
  1061.         if self.fp:
  1062.             self.fp.write('#        element %r as %s\n' % (code, keyform))
  1063.         
  1064.  
  1065.     
  1066.     def fillclasspropsandelems(self, cls):
  1067.         (name, code, desc, properties, elements) = cls
  1068.         cname = identify(name)
  1069.         if self.namemappers[0].hascode('class', code) and self.namemappers[0].findcodename('class', code)[0] != cname:
  1070.             if self.fp:
  1071.                 if (elements and len(properties) > 1 or len(properties) == 1) and properties[0][1] != 'c@#!':
  1072.                     if self.verbose:
  1073.                         print >>self.verbose, '** Skip multiple %s of %s (code %r)' % (cname, self.namemappers[0].findcodename('class', code)[0], code)
  1074.                     
  1075.                     raise RuntimeError, 'About to skip non-empty class'
  1076.                 
  1077.             return None
  1078.         
  1079.         plist = []
  1080.         elist = []
  1081.         superclasses = []
  1082.         for prop in properties:
  1083.             (pname, pcode, what) = prop
  1084.             if pcode == 'c@#^':
  1085.                 superclasses.append(what)
  1086.             
  1087.             if pcode == 'c@#!':
  1088.                 continue
  1089.             
  1090.             pname = identify(pname)
  1091.             plist.append(pname)
  1092.         
  1093.         superclassnames = []
  1094.         for superclass in superclasses:
  1095.             (superId, superDesc, dummy) = superclass
  1096.             (superclassname, fullyqualifiedname, module) = self.findcodename('class', superId)
  1097.             if superclassname == cname:
  1098.                 continue
  1099.             superclassnames.append(superclassname)
  1100.         
  1101.         if self.fp:
  1102.             self.fp.write('%s._superclassnames = %r\n' % (cname, superclassnames))
  1103.         
  1104.         for elem in elements:
  1105.             (ecode, keyform) = elem
  1106.             if ecode == 'c@#!':
  1107.                 continue
  1108.             
  1109.             (name, ename, module) = self.findcodename('class', ecode)
  1110.             if not name:
  1111.                 if self.fp:
  1112.                     self.fp.write('# XXXX %s element %r not found!!\n' % (cname, ecode))
  1113.                 
  1114.             self.fp
  1115.             elist.append((name, ename))
  1116.         
  1117.         plist.sort()
  1118.         elist.sort()
  1119.         if self.fp:
  1120.             self.fp.write('%s._privpropdict = {\n' % cname)
  1121.             for n in plist:
  1122.                 self.fp.write("    '%s' : _Prop_%s,\n" % (n, n))
  1123.             
  1124.             self.fp.write('}\n')
  1125.             self.fp.write('%s._privelemdict = {\n' % cname)
  1126.             for n, fulln in elist:
  1127.                 self.fp.write("    '%s' : %s,\n" % (n, fulln))
  1128.             
  1129.             self.fp.write('}\n')
  1130.         
  1131.  
  1132.     
  1133.     def compilecomparison(self, comp):
  1134.         (name, code, comment) = comp
  1135.         iname = identify(name)
  1136.         self.namemappers[0].addnamecode('comparison', iname, code)
  1137.         if self.fp:
  1138.             self.fp.write('class %s(aetools.NComparison):\n' % iname)
  1139.             self.fp.write('    """%s - %s """\n' % (ascii(name), ascii(comment)))
  1140.         
  1141.  
  1142.     
  1143.     def compileenumeration(self, enum):
  1144.         (code, items) = enum
  1145.         name = '_Enum_%s' % identify(code)
  1146.         if self.fp:
  1147.             self.fp.write('%s = {\n' % name)
  1148.             for item in items:
  1149.                 self.compileenumerator(item)
  1150.             
  1151.             self.fp.write('}\n\n')
  1152.         
  1153.         self.namemappers[0].addnamecode('enum', name, code)
  1154.         return code
  1155.  
  1156.     
  1157.     def compileenumerator(self, item):
  1158.         (name, code, desc) = item
  1159.         self.fp.write('    %r : %r,\t# %s\n' % (identify(name), code, ascii(desc)))
  1160.  
  1161.     
  1162.     def checkforenum(self, enum):
  1163.         """This enum code is used by an event. Make sure it's available"""
  1164.         (name, fullname, module) = self.findcodename('enum', enum)
  1165.         if not name:
  1166.             if self.fp:
  1167.                 self.fp.write('_Enum_%s = None # XXXX enum %s not found!!\n' % (identify(enum), ascii(enum)))
  1168.             
  1169.             return None
  1170.         
  1171.         if module:
  1172.             if self.fp:
  1173.                 self.fp.write('from %s import %s\n' % (module, name))
  1174.             
  1175.         
  1176.  
  1177.     
  1178.     def dumpindex(self):
  1179.         if not self.fp:
  1180.             return None
  1181.         
  1182.         self.fp.write('\n#\n# Indices of types declared in this module\n#\n')
  1183.         self.fp.write('_classdeclarations = {\n')
  1184.         classlist = self.namemappers[0].getall('class')
  1185.         classlist.sort()
  1186.         for k, v in classlist:
  1187.             self.fp.write('    %r : %s,\n' % (k, v))
  1188.         
  1189.         self.fp.write('}\n')
  1190.         self.fp.write('\n_propdeclarations = {\n')
  1191.         proplist = self.namemappers[0].getall('property')
  1192.         proplist.sort()
  1193.         for k, v in proplist:
  1194.             self.fp.write('    %r : _Prop_%s,\n' % (k, v))
  1195.         
  1196.         self.fp.write('}\n')
  1197.         self.fp.write('\n_compdeclarations = {\n')
  1198.         complist = self.namemappers[0].getall('comparison')
  1199.         complist.sort()
  1200.         for k, v in complist:
  1201.             self.fp.write('    %r : %s,\n' % (k, v))
  1202.         
  1203.         self.fp.write('}\n')
  1204.         self.fp.write('\n_enumdeclarations = {\n')
  1205.         enumlist = self.namemappers[0].getall('enum')
  1206.         enumlist.sort()
  1207.         for k, v in enumlist:
  1208.             self.fp.write('    %r : %s,\n' % (k, v))
  1209.         
  1210.         self.fp.write('}\n')
  1211.  
  1212.  
  1213.  
  1214. def compiledata(data):
  1215.     (type, description, flags) = data
  1216.     return '%r -- %r %s' % (type, description, compiledataflags(flags))
  1217.  
  1218.  
  1219. def is_null(data):
  1220.     return data[0] == 'null'
  1221.  
  1222.  
  1223. def is_optional(data):
  1224.     return data[2] & 32768
  1225.  
  1226.  
  1227. def is_enum(data):
  1228.     return data[2] & 8192
  1229.  
  1230.  
  1231. def getdatadoc(data):
  1232.     (type, descr, flags) = data
  1233.     if descr:
  1234.         return ascii(descr)
  1235.     
  1236.     if type == '****':
  1237.         return 'anything'
  1238.     
  1239.     if type == 'obj ':
  1240.         return 'an AE object reference'
  1241.     
  1242.     return 'undocumented, typecode %r' % (type,)
  1243.  
  1244. dataflagdict = {
  1245.     15: 'optional',
  1246.     14: 'list',
  1247.     13: 'enum',
  1248.     12: 'mutable' }
  1249.  
  1250. def compiledataflags(flags):
  1251.     bits = []
  1252.     for i in range(16):
  1253.         if flags & 1 << i:
  1254.             if i in dataflagdict.keys():
  1255.                 bits.append(dataflagdict[i])
  1256.             else:
  1257.                 bits.append(repr(i))
  1258.         i in dataflagdict.keys()
  1259.     
  1260.     return '[%s]' % string.join(bits)
  1261.  
  1262.  
  1263. def ascii(str):
  1264.     '''Return a string with all non-ascii characters hex-encoded'''
  1265.     if type(str) != type(''):
  1266.         return map(ascii, str)
  1267.     
  1268.     rv = ''
  1269.     for c in str:
  1270.         if not c in ('\t', '\n', '\r'):
  1271.             if c <= c:
  1272.                 pass
  1273.             elif c < chr(127):
  1274.                 rv = rv + c
  1275.                 continue
  1276.         rv = rv + '\\' + 'x%02.2x' % ord(c)
  1277.     
  1278.     return rv
  1279.  
  1280.  
  1281. def identify(str):
  1282.     '''Turn any string into an identifier:
  1283.     - replace space by _
  1284.     - replace other illegal chars by _xx_ (hex code)
  1285.     - append _ if the result is a python keyword
  1286.     '''
  1287.     if not str:
  1288.         return 'empty_ae_name_'
  1289.     
  1290.     rv = ''
  1291.     ok = string.ascii_letters + '_'
  1292.     ok2 = ok + string.digits
  1293.     for c in str:
  1294.         if c in ok:
  1295.             rv = rv + c
  1296.         elif c == ' ':
  1297.             rv = rv + '_'
  1298.         else:
  1299.             rv = rv + '_%02.2x_' % ord(c)
  1300.         ok = ok2
  1301.     
  1302.     if keyword.iskeyword(rv):
  1303.         rv = rv + '_'
  1304.     
  1305.     return rv
  1306.  
  1307. if __name__ == '__main__':
  1308.     main()
  1309.     sys.exit(1)
  1310.  
  1311.