ยปCore Development>Code coverage>Lib/plat-mac/gensuitemodule.py

Python code coverage for Lib/plat-mac/gensuitemodule.py

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