home *** CD-ROM | disk | FTP | other *** search
Wrap
# Source Generated with Decompyle++ # File: in.pyo (Python 2.4) ''' gensuitemodule - Generate an AE suite module from an aete/aeut resource Based on aete.py. Reading and understanding this code is left as an exercise to the reader. ''' import MacOS import EasyDialogs import os import string import sys import types import StringIO import keyword import macresource import aetools import distutils.sysconfig as distutils import OSATerminology from Carbon.Res import * import Carbon.Folder as Carbon import MacOS import getopt import plistlib _MAC_LIB_FOLDER = os.path.dirname(aetools.__file__) DEFAULT_STANDARD_PACKAGEFOLDER = os.path.join(_MAC_LIB_FOLDER, 'lib-scriptpackages') DEFAULT_USER_PACKAGEFOLDER = distutils.sysconfig.get_python_lib() def usage(): sys.stderr.write('Usage: %s [opts] application-or-resource-file\n' % sys.argv[0]) 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') sys.exit(1) def main(): if len(sys.argv) > 1: SHORTOPTS = 'rb:o:e:c:dv' LONGOPTS = ('resource', 'base=', 'output=', 'edit=', 'creator=', 'dump', 'verbose') try: (opts, args) = getopt.getopt(sys.argv[1:], SHORTOPTS, LONGOPTS) except getopt.GetoptError: usage() process_func = processfile basepkgname = 'StdSuites' output = None edit_modnames = [] creatorsignature = None dump = None verbose = None for o, a in opts: if o in ('-r', '--resource'): process_func = processfile_fromresource if o in ('-b', '--base'): basepkgname = a if o in ('-o', '--output'): output = a if o in ('-e', '--edit'): split = a.split('=') if len(split) != 2: usage() edit_modnames.append(split) if o in ('-c', '--creator'): if len(a) != 4: sys.stderr.write('creator must be 4-char string\n') sys.exit(1) creatorsignature = a if o in ('-d', '--dump'): dump = sys.stdout if o in ('-v', '--verbose'): verbose = sys.stderr continue if output and len(args) > 1: sys.stderr.write('%s: cannot specify --output with multiple inputs\n' % sys.argv[0]) sys.exit(1) for filename in args: process_func(filename, output = output, basepkgname = basepkgname, edit_modnames = edit_modnames, creatorsignature = creatorsignature, dump = dump, verbose = verbose) else: main_interactive() def main_interactive(interact = 0, basepkgname = 'StdSuites'): if interact: edit_modnames = None else: edit_modnames = [] appsfolder = Carbon.Folder.FSFindFolder(-32765, 'apps', 0) filename = EasyDialogs.AskFileForOpen(message = 'Select scriptable application', dialogOptionFlags = 4182, defaultLocation = appsfolder) if not filename: return None if not is_scriptable(filename): if EasyDialogs.AskYesNoCancel('Warning: application does not seem scriptable', yes = 'Continue', default = 2, no = '') <= 0: return None try: processfile(filename, edit_modnames = edit_modnames, basepkgname = basepkgname, verbose = sys.stderr) except MacOS.Error: arg = None print 'Error getting terminology:', arg print 'Retry, manually parsing resources' processfile_fromresource(filename, edit_modnames = edit_modnames, basepkgname = basepkgname, verbose = sys.stderr) def is_scriptable(application): '''Return true if the application is scriptable''' if os.path.isdir(application): plistfile = os.path.join(application, 'Contents', 'Info.plist') if not os.path.exists(plistfile): return False plist = plistlib.Plist.fromFile(plistfile) return plist.get('NSAppleScriptEnabled', False) currf = CurResFile() try: refno = macresource.open_pathname(application) except MacOS.Error: return False UseResFile(refno) n_terminology = Count1Resources('aete') + Count1Resources('aeut') + Count1Resources('scsz') + Count1Resources('osiz') CloseResFile(refno) UseResFile(currf) return n_terminology > 0 def processfile_fromresource(fullname, output = None, basepkgname = None, edit_modnames = None, creatorsignature = None, dump = None, verbose = None): '''Process all resources in a single file''' if not is_scriptable(fullname) and verbose: print >>verbose, 'Warning: app does not seem scriptable: %s' % fullname cur = CurResFile() if verbose: print >>verbose, 'Processing', fullname rf = macresource.open_pathname(fullname) try: UseResFile(rf) resources = [] for i in range(Count1Resources('aete')): res = Get1IndResource('aete', 1 + i) resources.append(res) for i in range(Count1Resources('aeut')): res = Get1IndResource('aeut', 1 + i) resources.append(res) if verbose: print >>verbose, '\nLISTING aete+aeut RESOURCES IN', repr(fullname) aetelist = [] for res in resources: if verbose: print >>verbose, 'decoding', res.GetResInfo(), '...' data = res.data aete = decode(data, verbose) aetelist.append((aete, res.GetResInfo())) finally: if rf != cur: CloseResFile(rf) UseResFile(cur) UseResFile(cur) if dump: dumpaetelist(aetelist, dump) compileaetelist(aetelist, fullname, output = output, basepkgname = basepkgname, edit_modnames = edit_modnames, creatorsignature = creatorsignature, verbose = verbose) def processfile(fullname, output = None, basepkgname = None, edit_modnames = None, creatorsignature = None, dump = None, verbose = None): '''Ask an application for its terminology and process that''' if not is_scriptable(fullname) and verbose: print >>verbose, 'Warning: app does not seem scriptable: %s' % fullname if verbose: print >>verbose, '\nASKING FOR aete DICTIONARY IN', repr(fullname) try: (aedescobj, launched) = OSATerminology.GetAppTerminology(fullname) except MacOS.Error: arg = None if arg[0] in (-1701, -192): if verbose: print >>verbose, 'GetAppTerminology failed with errAEDescNotFound/resNotFound, trying manually' (aedata, sig) = getappterminology(fullname, verbose = verbose) if not creatorsignature: creatorsignature = sig else: raise except: arg[0] in (-1701, -192) if launched: if verbose: print >>verbose, 'Launched', fullname raw = aetools.unpack(aedescobj) if not raw: if verbose: print >>verbose, 'Unpack returned empty value:', raw return None if not raw[0].data: if verbose: print >>verbose, 'Unpack returned value without data:', raw return None aedata = raw[0] aete = decode(aedata.data, verbose) if dump: dumpaetelist([ aete], dump) return None compileaete(aete, None, fullname, output = output, basepkgname = basepkgname, creatorsignature = creatorsignature, edit_modnames = edit_modnames, verbose = verbose) def getappterminology(fullname, verbose = None): '''Get application terminology by sending an AppleEvent''' if not MacOS.WMAvailable(): raise RuntimeError, 'Cannot send AppleEvents, no access to window manager' import Carbon.Evt as Carbon Carbon.Evt.WaitNextEvent(0, 0) if os.path.isdir(fullname): pkginfo = os.path.join(fullname, 'Contents', 'PkgInfo') if not os.path.exists(pkginfo): raise RuntimeError, 'No PkgInfo file found' tp_cr = open(pkginfo, 'rb').read() cr = tp_cr[4:8] else: (cr, tp) = MacOS.GetCreatorAndType(fullname) talker = aetools.TalkTo(cr) try: talker._start() except (MacOS.Error, aetools.Error): arg = None if verbose: print >>verbose, 'Warning: start() failed, continuing anyway:', arg except: verbose reply = talker.send('ascr', 'gdte') return (reply[1]['----'], cr) def compileaetelist(aetelist, fullname, output = None, basepkgname = None, edit_modnames = None, creatorsignature = None, verbose = None): for aete, resinfo in aetelist: compileaete(aete, resinfo, fullname, output = output, basepkgname = basepkgname, edit_modnames = edit_modnames, creatorsignature = creatorsignature, verbose = verbose) def dumpaetelist(aetelist, output): import pprint pprint.pprint(aetelist, output) def decode(data, verbose = None): '''Decode a resource into a python data structure''' f = StringIO.StringIO(data) aete = generic(getaete, f) aete = simplify(aete) processed = f.tell() unprocessed = len(f.read()) total = f.tell() if unprocessed and verbose: verbose.write('%d processed + %d unprocessed = %d total\n' % (processed, unprocessed, total)) return aete def simplify(item): '''Recursively replace singleton tuples by their constituent item''' if type(item) is types.ListType: return map(simplify, item) elif type(item) == types.TupleType and len(item) == 2: return simplify(item[1]) else: return item def getbyte(f, *args): c = f.read(1) if not c: raise EOFError, 'in getbyte' + str(args) return ord(c) def getword(f, *args): getalign(f) s = f.read(2) if len(s) < 2: raise EOFError, 'in getword' + str(args) return ord(s[0]) << 8 | ord(s[1]) def getlong(f, *args): getalign(f) s = f.read(4) if len(s) < 4: raise EOFError, 'in getlong' + str(args) return ord(s[0]) << 24 | ord(s[1]) << 16 | ord(s[2]) << 8 | ord(s[3]) def getostype(f, *args): getalign(f) s = f.read(4) if len(s) < 4: raise EOFError, 'in getostype' + str(args) return s def getpstr(f, *args): c = f.read(1) if len(c) < 1: raise EOFError, 'in getpstr[1]' + str(args) nbytes = ord(c) if nbytes == 0: return '' s = f.read(nbytes) if len(s) < nbytes: raise EOFError, 'in getpstr[2]' + str(args) return s def getalign(f): if f.tell() & 1: c = f.read(1) def getlist(f, description, getitem): count = getword(f) list = [] for i in range(count): list.append(generic(getitem, f)) getalign(f) return list def alt_generic(what, f, *args): print 'generic', repr(what), args res = vageneric(what, f, args) print '->', repr(res) return res def generic(what, f, *args): if type(what) == types.FunctionType: return apply(what, (f,) + args) if type(what) == types.ListType: record = [] for thing in what: item = apply(generic, thing[:1] + (f,) + thing[1:]) record.append((thing[1], item)) return record return 'BAD GENERIC ARGS: %r' % (what,) getdata = [ (getostype, 'type'), (getpstr, 'description'), (getword, 'flags')] getargument = [ (getpstr, 'name'), (getostype, 'keyword'), (getdata, 'what')] getevent = [ (getpstr, 'name'), (getpstr, 'description'), (getostype, 'suite code'), (getostype, 'event code'), (getdata, 'returns'), (getdata, 'accepts'), (getlist, 'optional arguments', getargument)] getproperty = [ (getpstr, 'name'), (getostype, 'code'), (getdata, 'what')] getelement = [ (getostype, 'type'), (getlist, 'keyform', getostype)] getclass = [ (getpstr, 'name'), (getostype, 'class code'), (getpstr, 'description'), (getlist, 'properties', getproperty), (getlist, 'elements', getelement)] getcomparison = [ (getpstr, 'operator name'), (getostype, 'operator ID'), (getpstr, 'operator comment')] getenumerator = [ (getpstr, 'enumerator name'), (getostype, 'enumerator ID'), (getpstr, 'enumerator comment')] getenumeration = [ (getostype, 'enumeration ID'), (getlist, 'enumerator', getenumerator)] getsuite = [ (getpstr, 'suite name'), (getpstr, 'suite description'), (getostype, 'suite ID'), (getword, 'suite level'), (getword, 'suite version'), (getlist, 'events', getevent), (getlist, 'classes', getclass), (getlist, 'comparisons', getcomparison), (getlist, 'enumerations', getenumeration)] getaete = [ (getword, 'major/minor version in BCD'), (getword, 'language code'), (getword, 'script code'), (getlist, 'suites', getsuite)] def compileaete(aete, resinfo, fname, output = None, basepkgname = None, edit_modnames = None, creatorsignature = None, verbose = None): '''Generate code for a full aete resource. fname passed for doc purposes''' (version, language, script, suites) = aete (major, minor) = divmod(version, 256) if not creatorsignature: (creatorsignature, dummy) = MacOS.GetCreatorAndType(fname) packagename = identify(os.path.splitext(os.path.basename(fname))[0]) if language: packagename = packagename + '_lang%d' % language if script: packagename = packagename + '_script%d' % script if len(packagename) > 27: packagename = packagename[:27] if output: if not os.path.exists(output): os.mkdir(output) pathname = output else: pathname = EasyDialogs.AskFolder(message = 'Create and select package folder for %s' % packagename, defaultLocation = DEFAULT_USER_PACKAGEFOLDER) output = pathname if not pathname: return None packagename = os.path.split(os.path.normpath(pathname))[1] if not basepkgname: basepkgname = EasyDialogs.AskFolder(message = 'Package folder for base suite (usually StdSuites)', defaultLocation = DEFAULT_STANDARD_PACKAGEFOLDER) if basepkgname: (dirname, basepkgname) = os.path.split(os.path.normpath(basepkgname)) if dirname and dirname not in sys.path: sys.path.insert(0, dirname) basepackage = __import__(basepkgname) else: basepackage = None suitelist = [] allprecompinfo = [] allsuites = [] for suite in suites: compiler = SuiteCompiler(suite, basepackage, output, edit_modnames, verbose) (code, modname, precompinfo) = compiler.precompilesuite() if not code: continue allprecompinfo = allprecompinfo + precompinfo suiteinfo = (suite, pathname, modname) suitelist.append((code, modname)) allsuites.append(compiler) for compiler in allsuites: compiler.compilesuite(major, minor, language, script, fname, allprecompinfo) initfilename = os.path.join(output, '__init__.py') fp = open(initfilename, 'w') MacOS.SetCreatorAndType(initfilename, 'Pyth', 'TEXT') fp.write('"""\n') fp.write('Package generated from %s\n' % ascii(fname)) if resinfo: fp.write('Resource %s resid %d %s\n' % (ascii(resinfo[1]), resinfo[0], ascii(resinfo[2]))) fp.write('"""\n') fp.write('import aetools\n') fp.write('Error = aetools.Error\n') suitelist.sort() for code, modname in suitelist: fp.write('import %s\n' % modname) fp.write('\n\n_code_to_module = {\n') for code, modname in suitelist: fp.write(" '%s' : %s,\n" % (ascii(code), modname)) fp.write('}\n\n') fp.write('\n\n_code_to_fullname = {\n') for code, modname in suitelist: fp.write(" '%s' : ('%s.%s', '%s'),\n" % (ascii(code), packagename, modname, modname)) fp.write('}\n\n') for code, modname in suitelist: fp.write('from %s import *\n' % modname) fp.write('\ndef getbaseclasses(v):\n') fp.write(" if not getattr(v, '_propdict', None):\n") fp.write(' v._propdict = {}\n') fp.write(' v._elemdict = {}\n') fp.write(" for superclassname in getattr(v, '_superclassnames', []):\n") fp.write(' superclass = eval(superclassname)\n') fp.write(' getbaseclasses(superclass)\n') fp.write(" v._propdict.update(getattr(superclass, '_propdict', {}))\n") fp.write(" v._elemdict.update(getattr(superclass, '_elemdict', {}))\n") fp.write(" v._propdict.update(getattr(v, '_privpropdict', {}))\n") fp.write(" v._elemdict.update(getattr(v, '_privelemdict', {}))\n") fp.write('\n') fp.write('import StdSuites\n') allprecompinfo.sort() if allprecompinfo: fp.write('\n#\n# Set property and element dictionaries now that all classes have been defined\n#\n') for codenamemapper in allprecompinfo: for k, v in codenamemapper.getall('class'): fp.write('getbaseclasses(%s)\n' % v) application_class = None if allprecompinfo: fp.write('\n#\n# Indices of types declared in this module\n#\n') fp.write('_classdeclarations = {\n') for codenamemapper in allprecompinfo: for k, v in codenamemapper.getall('class'): fp.write(' %r : %s,\n' % (k, v)) if k == 'capp': application_class = v continue fp.write('}\n') if suitelist: fp.write('\n\nclass %s(%s_Events' % (packagename, suitelist[0][1])) for code, modname in suitelist[1:]: fp.write(',\n %s_Events' % modname) fp.write(',\n aetools.TalkTo):\n') fp.write(' _signature = %r\n\n' % (creatorsignature,)) fp.write(" _moduleName = '%s'\n\n" % packagename) if application_class: fp.write(' _elemdict = %s._elemdict\n' % application_class) fp.write(' _propdict = %s._propdict\n' % application_class) fp.close() class SuiteCompiler: def __init__(self, suite, basepackage, output, edit_modnames, verbose): self.suite = suite self.basepackage = basepackage self.edit_modnames = edit_modnames self.output = output self.verbose = verbose self.pathname = None self.modname = None self.fp = None self.basemodule = None self.enumsneeded = { } def precompilesuite(self): '''Parse a single suite without generating the output. This step is needed so we can resolve recursive references by suites to enums/comps/etc declared in other suites''' (name, desc, code, level, version, events, classes, comps, enums) = self.suite modname = identify(name) if len(modname) > 28: modname = modname[:27] if self.edit_modnames is None: self.pathname = EasyDialogs.AskFileForSave(message = 'Python output file', savedFileName = modname + '.py') else: for old, new in self.edit_modnames: if old == modname: modname = new continue if modname: self.pathname = os.path.join(self.output, modname + '.py') else: self.pathname = None if not self.pathname: return (None, None, None) self.modname = os.path.splitext(os.path.split(self.pathname)[1])[0] if self.basepackage and self.basepackage._code_to_module.has_key(code): basemodule = self.basepackage._code_to_module[code] else: basemodule = None self.enumsneeded = { } for event in events: self.findenumsinevent(event) objc = ObjectCompiler(None, self.modname, basemodule, interact = self.edit_modnames is None, verbose = self.verbose) for cls in classes: objc.compileclass(cls) for cls in classes: objc.fillclasspropsandelems(cls) for comp in comps: objc.compilecomparison(comp) for enum in enums: objc.compileenumeration(enum) for enum in self.enumsneeded.keys(): objc.checkforenum(enum) objc.dumpindex() precompinfo = objc.getprecompinfo(self.modname) return (code, self.modname, precompinfo) def compilesuite(self, major, minor, language, script, fname, precompinfo): '''Generate code for a single suite''' (name, desc, code, level, version, events, classes, comps, enums) = self.suite def class_sorter(k1, k2): '''Sort classes by code, and make sure main class sorts before synonyms''' if k1[1] < k2[1]: return -1 if k1[1] > k2[1]: return 1 if not k2[3] or k2[3][0][1] == 'c@#!': return -1 if not k1[3] or k1[3][0][1] == 'c@#!': return 1 return 0 events.sort() classes.sort(class_sorter) comps.sort() enums.sort() self.fp = fp = open(self.pathname, 'w') MacOS.SetCreatorAndType(self.pathname, 'Pyth', 'TEXT') fp.write('"""Suite %s: %s\n' % (ascii(name), ascii(desc))) fp.write('Level %d, version %d\n\n' % (level, version)) fp.write('Generated from %s\n' % ascii(fname)) fp.write('AETE/AEUT resource version %d/%d, language %d, script %d\n' % (major, minor, language, script)) fp.write('"""\n\n') fp.write('import aetools\n') fp.write('import MacOS\n\n') fp.write('_code = %r\n\n' % (code,)) if self.basepackage and self.basepackage._code_to_module.has_key(code): fp.write('from %s import *\n' % self.basepackage._code_to_fullname[code][0]) basemodule = self.basepackage._code_to_module[code] elif self.basepackage and self.basepackage._code_to_module.has_key(code.lower()): fp.write('from %s import *\n' % self.basepackage._code_to_fullname[code.lower()][0]) basemodule = self.basepackage._code_to_module[code.lower()] else: basemodule = None self.basemodule = basemodule self.compileclassheader() self.enumsneeded = { } if events: for event in events: self.compileevent(event) else: fp.write(' pass\n\n') objc = ObjectCompiler(fp, self.modname, basemodule, precompinfo, interact = self.edit_modnames is None, verbose = self.verbose) for cls in classes: objc.compileclass(cls) for cls in classes: objc.fillclasspropsandelems(cls) for comp in comps: objc.compilecomparison(comp) for enum in enums: objc.compileenumeration(enum) for enum in self.enumsneeded.keys(): objc.checkforenum(enum) objc.dumpindex() def compileclassheader(self): '''Generate class boilerplate''' classname = '%s_Events' % self.modname if self.basemodule: modshortname = string.split(self.basemodule.__name__, '.')[-1] baseclassname = '%s_Events' % modshortname self.fp.write('class %s(%s):\n\n' % (classname, baseclassname)) else: self.fp.write('class %s:\n\n' % classname) def compileevent(self, event): '''Generate code for a single event''' (name, desc, code, subcode, returns, accepts, arguments) = event fp = self.fp funcname = identify(name) if arguments: fp.write(' _argmap_%s = {\n' % funcname) for a in arguments: fp.write(' %r : %r,\n' % (identify(a[0]), a[1])) fp.write(' }\n\n') has_arg = not is_null(accepts) if has_arg: pass opt_arg = is_optional(accepts) fp.write(' def %s(self, ' % funcname) if has_arg: if not opt_arg: fp.write('_object, ') else: fp.write('_object=None, ') else: fp.write('_no_object=None, ') fp.write('_attributes={}, **_arguments):\n') fp.write(' """%s: %s\n' % (ascii(name), ascii(desc))) if has_arg: fp.write(' Required argument: %s\n' % getdatadoc(accepts)) elif opt_arg: fp.write(' Optional argument: %s\n' % getdatadoc(accepts)) for arg in arguments: fp.write(' Keyword argument %s: %s\n' % (identify(arg[0]), getdatadoc(arg[2]))) fp.write(' Keyword argument _attributes: AppleEvent attribute dictionary\n') if not is_null(returns): fp.write(' Returns: %s\n' % getdatadoc(returns)) fp.write(' """\n') fp.write(' _code = %r\n' % (code,)) fp.write(' _subcode = %r\n\n' % (subcode,)) if arguments: fp.write(' aetools.keysubst(_arguments, self._argmap_%s)\n' % funcname) else: fp.write(" if _arguments: raise TypeError, 'No optional args expected'\n") if has_arg: fp.write(" _arguments['----'] = _object\n") elif opt_arg: fp.write(' if _object:\n') fp.write(" _arguments['----'] = _object\n") else: fp.write(" if _no_object != None: raise TypeError, 'No direct arg expected'\n") fp.write('\n') for a in arguments: if is_enum(a[2]): kname = a[1] ename = a[2][0] if ename != '****': fp.write(' aetools.enumsubst(_arguments, %r, _Enum_%s)\n' % (kname, identify(ename))) self.enumsneeded[ename] = 1 ename != '****' fp.write('\n') fp.write(' _reply, _arguments, _attributes = self.send(_code, _subcode,\n') fp.write(' _arguments, _attributes)\n') fp.write(" if _arguments.get('errn', 0):\n") fp.write(' raise aetools.Error, aetools.decodeerror(_arguments)\n') fp.write(' # XXXX Optionally decode result\n') fp.write(" if _arguments.has_key('----'):\n") if is_enum(returns): fp.write(' # XXXX Should do enum remapping here...\n') fp.write(" return _arguments['----']\n") fp.write('\n') def findenumsinevent(self, event): '''Find all enums for a single event''' (name, desc, code, subcode, returns, accepts, arguments) = event for a in arguments: if is_enum(a[2]): ename = a[2][0] if ename != '****': self.enumsneeded[ename] = 1 ename != '****' class CodeNameMapper: def __init__(self, interact = 1, verbose = None): self.code2name = { 'property': { }, 'class': { }, 'enum': { }, 'comparison': { } } self.name2code = { 'property': { }, 'class': { }, 'enum': { }, 'comparison': { } } self.modulename = None self.star_imported = 0 self.can_interact = interact self.verbose = verbose def addnamecode(self, type, name, code): self.name2code[type][name] = code if not self.code2name[type].has_key(code): self.code2name[type][code] = name def hasname(self, name): for dict in self.name2code.values(): if dict.has_key(name): return True continue return False def hascode(self, type, code): return self.code2name[type].has_key(code) def findcodename(self, type, code): if not self.hascode(type, code): return (None, None, None) name = self.code2name[type][code] if self.modulename and not (self.star_imported): qualname = '%s.%s' % (self.modulename, name) else: qualname = name return (name, qualname, self.modulename) def getall(self, type): return self.code2name[type].items() def addmodule(self, module, name, star_imported): self.modulename = name self.star_imported = star_imported for code, name in module._propdeclarations.items(): self.addnamecode('property', name, code) for code, name in module._classdeclarations.items(): self.addnamecode('class', name, code) for code in module._enumdeclarations.keys(): self.addnamecode('enum', '_Enum_' + identify(code), code) for code, name in module._compdeclarations.items(): self.addnamecode('comparison', name, code) def prepareforexport(self, name = None): if not self.modulename: self.modulename = name return self class ObjectCompiler: def __init__(self, fp, modname, basesuite, othernamemappers = None, interact = 1, verbose = None): self.fp = fp self.verbose = verbose self.basesuite = basesuite self.can_interact = interact self.modulename = modname self.namemappers = [ CodeNameMapper(self.can_interact, self.verbose)] if othernamemappers: self.othernamemappers = othernamemappers[:] else: self.othernamemappers = [] if basesuite: basemapper = CodeNameMapper(self.can_interact, self.verbose) basemapper.addmodule(basesuite, '', 1) self.namemappers.append(basemapper) def getprecompinfo(self, modname): list = [] for mapper in self.namemappers: emapper = mapper.prepareforexport(modname) if emapper: list.append(emapper) continue return list def findcodename(self, type, code): while None: for mapper in self.namemappers: if mapper.hascode(type, code): return mapper.findcodename(type, code) continue for mapper in self.othernamemappers: if mapper.hascode(type, code): self.othernamemappers.remove(mapper) self.namemappers.append(mapper) if self.fp: self.fp.write('import %s\n' % mapper.modulename) break continue elif self.fp: m = self.askdefinitionmodule(type, code) else: m = None if not m: return (None, None, None) mapper = CodeNameMapper(self.can_interact, self.verbose) self.namemappers.append(mapper) def hasname(self, name): for mapper in self.othernamemappers: if mapper.hasname(name) and mapper.modulename != self.modulename: if self.verbose: print >>self.verbose, 'Duplicate Python identifier:', name, self.modulename, mapper.modulename return True continue return False def askdefinitionmodule(self, type, code): if not self.can_interact: if self.verbose: print >>self.verbose, "** No definition for %s '%s' found" % (type, code) return None path = EasyDialogs.AskFileForSave(message = 'Where is %s %s declared?' % (type, code)) if not path: return None (path, file) = os.path.split(path) modname = os.path.splitext(file)[0] if path not in sys.path: sys.path.insert(0, path) m = __import__(modname) self.fp.write('import %s\n' % modname) return m def compileclass(self, cls): (name, code, desc, properties, elements) = cls pname = identify(name) if self.namemappers[0].hascode('class', code): (othername, dummy, dummy) = self.namemappers[0].findcodename('class', code) if self.fp: self.fp.write('\n%s = %s\n' % (pname, othername)) elif self.fp: self.fp.write('\nclass %s(aetools.ComponentItem):\n' % pname) self.fp.write(' """%s - %s """\n' % (ascii(name), ascii(desc))) self.fp.write(' want = %r\n' % (code,)) self.namemappers[0].addnamecode('class', pname, code) is_application_class = code == 'capp' properties.sort() for prop in properties: self.compileproperty(prop, is_application_class) elements.sort() for elem in elements: self.compileelement(elem) def compileproperty(self, prop, is_application_class = False): (name, code, what) = prop if code == 'c@#!': return None pname = identify(name) if self.namemappers[0].hascode('property', code): (othername, dummy, dummy) = self.namemappers[0].findcodename('property', code) if pname == othername: return None if self.fp: self.fp.write('\n_Prop_%s = _Prop_%s\n' % (pname, othername)) elif self.fp: self.fp.write('class _Prop_%s(aetools.NProperty):\n' % pname) self.fp.write(' """%s - %s """\n' % (ascii(name), ascii(what[1]))) self.fp.write(' which = %r\n' % (code,)) self.fp.write(' want = %r\n' % (what[0],)) self.namemappers[0].addnamecode('property', pname, code) if is_application_class and self.fp: self.fp.write('%s = _Prop_%s()\n' % (pname, pname)) def compileelement(self, elem): (code, keyform) = elem if self.fp: self.fp.write('# element %r as %s\n' % (code, keyform)) def fillclasspropsandelems(self, cls): (name, code, desc, properties, elements) = cls cname = identify(name) if self.namemappers[0].hascode('class', code) and self.namemappers[0].findcodename('class', code)[0] != cname: if self.fp: if (elements and len(properties) > 1 or len(properties) == 1) and properties[0][1] != 'c@#!': if self.verbose: print >>self.verbose, '** Skip multiple %s of %s (code %r)' % (cname, self.namemappers[0].findcodename('class', code)[0], code) raise RuntimeError, 'About to skip non-empty class' return None plist = [] elist = [] superclasses = [] for prop in properties: (pname, pcode, what) = prop if pcode == 'c@#^': superclasses.append(what) if pcode == 'c@#!': continue pname = identify(pname) plist.append(pname) superclassnames = [] for superclass in superclasses: (superId, superDesc, dummy) = superclass (superclassname, fullyqualifiedname, module) = self.findcodename('class', superId) if superclassname == cname: continue superclassnames.append(superclassname) if self.fp: self.fp.write('%s._superclassnames = %r\n' % (cname, superclassnames)) for elem in elements: (ecode, keyform) = elem if ecode == 'c@#!': continue (name, ename, module) = self.findcodename('class', ecode) if not name: if self.fp: self.fp.write('# XXXX %s element %r not found!!\n' % (cname, ecode)) self.fp elist.append((name, ename)) plist.sort() elist.sort() if self.fp: self.fp.write('%s._privpropdict = {\n' % cname) for n in plist: self.fp.write(" '%s' : _Prop_%s,\n" % (n, n)) self.fp.write('}\n') self.fp.write('%s._privelemdict = {\n' % cname) for n, fulln in elist: self.fp.write(" '%s' : %s,\n" % (n, fulln)) self.fp.write('}\n') def compilecomparison(self, comp): (name, code, comment) = comp iname = identify(name) self.namemappers[0].addnamecode('comparison', iname, code) if self.fp: self.fp.write('class %s(aetools.NComparison):\n' % iname) self.fp.write(' """%s - %s """\n' % (ascii(name), ascii(comment))) def compileenumeration(self, enum): (code, items) = enum name = '_Enum_%s' % identify(code) if self.fp: self.fp.write('%s = {\n' % name) for item in items: self.compileenumerator(item) self.fp.write('}\n\n') self.namemappers[0].addnamecode('enum', name, code) return code def compileenumerator(self, item): (name, code, desc) = item self.fp.write(' %r : %r,\t# %s\n' % (identify(name), code, ascii(desc))) def checkforenum(self, enum): """This enum code is used by an event. Make sure it's available""" (name, fullname, module) = self.findcodename('enum', enum) if not name: if self.fp: self.fp.write('_Enum_%s = None # XXXX enum %s not found!!\n' % (identify(enum), ascii(enum))) return None if module: if self.fp: self.fp.write('from %s import %s\n' % (module, name)) def dumpindex(self): if not self.fp: return None self.fp.write('\n#\n# Indices of types declared in this module\n#\n') self.fp.write('_classdeclarations = {\n') classlist = self.namemappers[0].getall('class') classlist.sort() for k, v in classlist: self.fp.write(' %r : %s,\n' % (k, v)) self.fp.write('}\n') self.fp.write('\n_propdeclarations = {\n') proplist = self.namemappers[0].getall('property') proplist.sort() for k, v in proplist: self.fp.write(' %r : _Prop_%s,\n' % (k, v)) self.fp.write('}\n') self.fp.write('\n_compdeclarations = {\n') complist = self.namemappers[0].getall('comparison') complist.sort() for k, v in complist: self.fp.write(' %r : %s,\n' % (k, v)) self.fp.write('}\n') self.fp.write('\n_enumdeclarations = {\n') enumlist = self.namemappers[0].getall('enum') enumlist.sort() for k, v in enumlist: self.fp.write(' %r : %s,\n' % (k, v)) self.fp.write('}\n') def compiledata(data): (type, description, flags) = data return '%r -- %r %s' % (type, description, compiledataflags(flags)) def is_null(data): return data[0] == 'null' def is_optional(data): return data[2] & 32768 def is_enum(data): return data[2] & 8192 def getdatadoc(data): (type, descr, flags) = data if descr: return ascii(descr) if type == '****': return 'anything' if type == 'obj ': return 'an AE object reference' return 'undocumented, typecode %r' % (type,) dataflagdict = { 15: 'optional', 14: 'list', 13: 'enum', 12: 'mutable' } def compiledataflags(flags): bits = [] for i in range(16): if flags & 1 << i: if i in dataflagdict.keys(): bits.append(dataflagdict[i]) else: bits.append(repr(i)) i in dataflagdict.keys() return '[%s]' % string.join(bits) def ascii(str): '''Return a string with all non-ascii characters hex-encoded''' if type(str) != type(''): return map(ascii, str) rv = '' for c in str: if not c in ('\t', '\n', '\r'): if c <= c: pass elif c < chr(127): rv = rv + c continue rv = rv + '\\' + 'x%02.2x' % ord(c) return rv def identify(str): '''Turn any string into an identifier: - replace space by _ - replace other illegal chars by _xx_ (hex code) - append _ if the result is a python keyword ''' if not str: return 'empty_ae_name_' rv = '' ok = string.ascii_letters + '_' ok2 = ok + string.digits for c in str: if c in ok: rv = rv + c elif c == ' ': rv = rv + '_' else: rv = rv + '_%02.2x_' % ord(c) ok = ok2 if keyword.iskeyword(rv): rv = rv + '_' return rv if __name__ == '__main__': main() sys.exit(1)