Split aepack and aetypes off from aetools (it was getting too big)

Added support for all basic types mentioned in Apple Event Registry
Added support for automatically-generated suites.
This commit is contained in:
Jack Jansen 1995-07-17 11:42:23 +00:00
parent 5ae5fdf901
commit 40775bafab
3 changed files with 897 additions and 462 deletions

356
Mac/Lib/toolbox/aepack.py Normal file
View File

@ -0,0 +1,356 @@
"""Tools for use in AppleEvent clients and servers:
conversion between AE types and python types
pack(x) converts a Python object to an AEDesc object
unpack(desc) does the reverse
coerce(x, wanted_sample) coerces a python object to another python object
"""
#
# This code was originally written by Guido, and modified/extended by Jack
# to include the various types that were missing. The reference used is
# Apple Event Registry, chapter 9.
#
import struct
import string
import types
from string import strip
from types import *
import AE
from AppleEvents import *
from AERegistry import *
from AEObjects import *
import MacOS
import macfs
import StringIO
import aetypes
from aetypes import mkenum, mktype
# These ones seem to be missing from AppleEvents
# (they're in AERegistry.h)
#typeColorTable = 'clrt'
#typeDrawingArea = 'cdrw'
#typePixelMap = 'cpix'
#typePixelMapMinus = 'tpmm'
#typeRotation = 'trot'
#typeTextStyles = 'tsty'
#typeStyledText = 'STXT'
#typeAEText = 'tTXT'
#typeEnumeration = 'enum'
#
# Some AE types are immedeately coerced into something
# we like better (and which is equivalent)
#
unpacker_coercions = {
typeComp : typeExtended,
typeColorTable : typeAEList,
typeDrawingArea : typeAERecord,
typeFixed : typeExtended,
typeFloat : typeExtended,
typePixelMap : typeAERecord,
typeRotation : typeAERecord,
typeStyledText : typeAERecord,
typeTextStyles : typeAERecord,
};
#
# Some python types we need in the packer:
#
AEDescType = type(AE.AECreateDesc('TEXT', ''))
_sample_fss = macfs.FSSpec(':')
_sample_alias = _sample_fss.NewAliasMinimal()
FSSType = type(_sample_fss)
AliasType = type(_sample_alias)
def pack(x, forcetype = None):
"""Pack a python object into an AE descriptor"""
if forcetype:
if type(x) is StringType:
return AE.AECreateDesc(forcetype, x)
else:
return pack(x).AECoerceDesc(forcetype)
if x == None:
return AE.AECreateDesc('null', '')
t = type(x)
if t == AEDescType:
return x
if t == FSSType:
return AE.AECreateDesc('fss ', x.data)
if t == AliasType:
return AE.AECreateDesc('alis', x.data)
if t == IntType:
return AE.AECreateDesc('long', struct.pack('l', x))
if t == FloatType:
#
# XXXX (note by Guido) Weird thing -- Think C's "double" is 10 bytes, but
# struct.pack('d') return 12 bytes (and struct.unpack requires
# them, too). The first 2 bytes seem to be repeated...
# Probably an alignment problem
# XXXX (note by Jack) haven't checked this under MW
#
return AE.AECreateDesc('exte', struct.pack('d', x)[2:])
if t == StringType:
return AE.AECreateDesc('TEXT', x)
if t == ListType:
list = AE.AECreateList('', 0)
for item in x:
list.AEPutDesc(0, pack(item))
return list
if t == DictionaryType:
record = AE.AECreateList('', 1)
for key, value in x.items():
record.AEPutParamDesc(key, pack(value))
return record
if t == InstanceType and hasattr(x, '__aepack__'):
return x.__aepack__()
return AE.AECreateDesc('TEXT', repr(x)) # Copout
def unpack(desc):
"""Unpack an AE descriptor to a python object"""
t = desc.type
if unpacker_coercions.has_key(t):
desc = desc.AECoerceDesc(unpacker_coercions[t])
if t == typeAEList:
l = []
for i in range(desc.AECountItems()):
keyword, item = desc.AEGetNthDesc(i+1, '****')
l.append(unpack(item))
return l
if t == typeAERecord:
d = {}
for i in range(desc.AECountItems()):
keyword, item = desc.AEGetNthDesc(i+1, '****')
d[keyword] = unpack(item)
return d
if t == typeAEText:
record = desc.AECoerceDesc('reco')
return mkaetext(unpack(record))
if t == typeAlias:
return macfs.RawAlias(desc.data)
# typeAppleEvent returned as unknown
if t == typeBoolean:
return struct.unpack('b', desc.data)[0]
if t == typeChar:
return desc.data
# typeColorTable coerced to typeAEList
# typeComp coerced to extended
# typeData returned as unknown
# typeDrawingArea coerced to typeAERecord
if t == typeEnumeration:
return mkenum(desc.data)
# typeEPS returned as unknown
if t == typeExtended:
data = desc.data
# XXX See corresponding note for pack()
return struct.unpack('d', data[:2] + data)[0]
if t == typeFalse:
return 0
# typeFixed coerced to extended
# typeFloat coerced to extended
if t == typeFSS:
return macfs.RawFSSpec(desc.data)
if t == typeInsertionLoc:
record = desc.AECoerceDesc('reco')
return mkinsertionloc(unpack(record))
# typeInteger equal to typeLongInteger
if t == typeIntlText:
script, language = struct.unpack('hh', desc.data[:4])
return aetypes.IntlText(script, language, desc.data[4:])
if t == typeIntlWritingCode:
script, language = struct.unpack('hh', desc.data)
return aetypes.IntlWritingCode(script, language)
if t == typeKeyword:
return mkkeyword(desc.data)
# typeLongFloat is equal to typeFloat
if t == typeLongInteger:
return struct.unpack('l', desc.data)[0]
if t == typeNull:
return None
if t == typeMagnitude:
v = struct.unpack('l', desc.data)
if v < 0:
v = 0x100000000L + v
return v
if t == typeObjectSpecifier:
record = desc.AECoerceDesc('reco')
return mkobject(unpack(record))
# typePict returned as unknown
# typePixelMap coerced to typeAERecord
# typePixelMapMinus returned as unknown
# typeProcessSerialNumber returned as unknown
if t == typeQDPoint:
v, h = struct.unpack('hh', desc.data)
return aetypes.QDPoint(v, h)
if t == typeQDRectangle:
v0, h0, v1, h1 = struct.unpack('hhhh', desc.data)
return aetypes.QDRectangle(v0, h0, v1, h1)
if t == typeRGBColor:
r, g, b = struct.unpack('hhh', desc.data)
return aetypes.RGBColor(r, g, b)
# typeRotation coerced to typeAERecord
# typeScrapStyles returned as unknown
# typeSessionID returned as unknown
if t == typeShortFloat:
return struct.unpack('f', desc.data)[0]
if t == typeShortInteger:
return struct.unpack('h', desc.data)[0]
# typeSMFloat identical to typeShortFloat
# typeSMInt indetical to typeShortInt
# typeStyledText coerced to typeAERecord
if t == typeTargetID:
return mktargetid(desc.data)
# typeTextStyles coerced to typeAERecord
# typeTIFF returned as unknown
if t == typeTrue:
return 1
if t == typeType:
return mktype(desc.data)
#
# The following are special
#
if t == 'rang':
record = desc.AECoerceDesc('reco')
return mkrange(unpack(record))
if t == 'cmpd':
record = desc.AECoerceDesc('reco')
return mkcomparison(unpack(record))
if t == 'logi':
record = desc.AECoerceDesc('reco')
return mklogical(unpack(record))
return mkunknown(desc.type, desc.data)
def coerce(data, egdata):
"""Coerce a python object to another type using the AE coercers"""
pdata = pack(data)
pegdata = pack(egdata)
pdata = pdata.AECoerceDesc(pegdata.type)
return unpack(pdata)
#
# Helper routines for unpack
#
def mktargetid(data):
sessionID = getlong(data[:4])
name = mkppcportrec(data[4:4+72])
location = mklocationnamerec(data[76:76+36])
rcvrName = mkppcportrec(data[112:112+72])
return sessionID, name, location, rcvrName
def mkppcportrec(rec):
namescript = getword(rec[:2])
name = getpstr(rec[2:2+33])
portkind = getword(rec[36:38])
if portkind == 1:
ctor = rec[38:42]
type = rec[42:46]
identity = (ctor, type)
else:
identity = getpstr(rec[38:38+33])
return namescript, name, portkind, identity
def mklocationnamerec(rec):
kind = getword(rec[:2])
stuff = rec[2:]
if kind == 0: stuff = None
if kind == 2: stuff = getpstr(stuff)
return kind, stuff
def mkunknown(type, data):
return aetypes.Unknown(type, data)
def getpstr(s):
return s[1:1+ord(s[0])]
def getlong(s):
return (ord(s[0])<<24) | (ord(s[1])<<16) | (ord(s[2])<<8) | ord(s[3])
def getword(s):
return (ord(s[0])<<8) | (ord(s[1])<<0)
def mkkeyword(keyword):
return aetypes.Keyword(keyword)
def mkrange(dict):
return aetypes.Range(dict['star'], dict['stop'])
def mkcomparison(dict):
return aetypes.Comparison(dict['obj1'], dict['relo'].enum, dict['obj2'])
def mklogical(dict):
return aetypes.Logical(dict['logc'], dict['term'])
def mkstyledtext(dict):
return aetypes.StyledText(dict['ksty'], dict['ktxt'])
def mkaetext(dict):
return aetypes.AEText(dict[keyAEScriptTag], dict[keyAEStyles], dict[keyAEText])
def mkinsertionloc(dict):
return aetypes.InsertionLoc(dict[keyAEObject], dict[keyAEPosition])
def mkobject(dict):
want = dict['want'].type
form = dict['form'].enum
seld = dict['seld']
fr = dict['from']
if form in ('name', 'indx', 'rang', 'test'):
if want == 'text': return aetypes.Text(seld, fr)
if want == 'cha ': return aetypes.Character(seld, fr)
if want == 'cwor': return aetypes.Word(seld, fr)
if want == 'clin': return aetypes.Line(seld, fr)
if want == 'cpar': return aetypes.Paragraph(seld, fr)
if want == 'cwin': return aetypes.Window(seld, fr)
if want == 'docu': return aetypes.Document(seld, fr)
if want == 'file': return aetypes.File(seld, fr)
if want == 'cins': return aetypes.InsertionPoint(seld, fr)
if want == 'prop' and form == 'prop' and aetypes.IsType(seld):
return aetypes.Property(seld.type, fr)
return aetypes.ObjectSpecifier(want, form, seld, fr)
def _test():
"""Test program. Pack and unpack various things"""
objs = [
'a string',
12,
12.0,
None,
['a', 'list', 'of', 'strings'],
{'key1': 'value1', 'key2':'value2'},
macfs.FSSpec(':'),
macfs.FSSpec(':').NewAliasMinimal(),
aetypes.Enum('enum'),
aetypes.Type('type'),
aetypes.Keyword('kwrd'),
aetypes.Range(1, 10),
aetypes.Comparison(1, '< ', 10),
aetypes.Logical('not ', 1),
# Cannot do StyledText
# Cannot do AEText
aetypes.IntlText(0, 0, 'international text'),
aetypes.IntlWritingCode(0,0),
aetypes.QDPoint(50,100),
aetypes.QDRectangle(50,100,150,200),
aetypes.RGBColor(0x7000, 0x6000, 0x5000),
aetypes.Unknown('xxxx', 'unknown type data'),
aetypes.Character(1),
aetypes.Character(2, aetypes.Line(2)),
]
for o in objs:
print 'BEFORE', o, `o`
packed = pack(o)
unpacked = unpack(packed)
print 'AFTER ', unpacked, `unpacked`
import sys
sys.exit(1)
if __name__ == '__main__':
_test()

View File

@ -15,477 +15,22 @@ and pack(x) will create an AE object reference equivalent to AppleScript's
character 1 of document "foobar"
Some of the stuff that appears to be exported from this module comes from other
files: the pack stuff from aepack, the objects from aetypes.
"""
import struct
import string
from string import strip
from types import *
import AE
import AppleEvents
import MacOS
import macfs
import StringIO
AEDescType = type(AE.AECreateDesc('TEXT', ''))
FSSType = type(macfs.FSSpec(':'))
def pack(x, forcetype = None):
if forcetype:
if type(x) is StringType:
return AE.AECreateDesc(forcetype, x)
else:
return pack(x).AECoerceDesc(forcetype)
if x == None:
return AE.AECreateDesc('null', '')
t = type(x)
if t == AEDescType:
return x
if t == FSSType:
vol, dir, filename = x.as_tuple()
fnlen = len(filename)
header = struct.pack('hlb', vol, dir, fnlen)
padding = '\0'*(63-fnlen)
return AE.AECreateDesc('fss ', header + filename + padding)
if t == IntType:
return AE.AECreateDesc('long', struct.pack('l', x))
if t == FloatType:
# XXX Weird thing -- Think C's "double" is 10 bytes, but
# struct.pack('d') return 12 bytes (and struct.unpack requires
# them, too). The first 2 bytes seem to be repeated...
# Probably an alignment problem
return AE.AECreateDesc('exte', struct.pack('d', x)[2:])
if t == StringType:
return AE.AECreateDesc('TEXT', x)
if t == ListType:
list = AE.AECreateList('', 0)
for item in x:
list.AEPutDesc(0, pack(item))
return list
if t == DictionaryType:
record = AE.AECreateList('', 1)
for key, value in x.items():
record.AEPutParamDesc(key, pack(value))
return record
if t == InstanceType and hasattr(x, '__aepack__'):
return x.__aepack__()
return AE.AECreateDesc('TEXT', repr(x)) # Copout
def unpack(desc):
t = desc.type
if t == 'TEXT':
return desc.data
if t == 'fals':
return 0
if t == 'true':
return 1
if t == 'enum':
return mkenum(desc.data)
if t == 'type':
return mktype(desc.data)
if t == 'long':
return struct.unpack('l', desc.data)[0]
if t == 'shor':
return struct.unpack('h', desc.data)[0]
if t == 'sing':
return struct.unpack('f', desc.data)[0]
if t == 'exte':
data = desc.data
# XXX See corresponding note for pack()
return struct.unpack('d', data[:2] + data)[0]
if t in ('doub', 'comp', 'magn'):
return unpack(desc.AECoerceDesc('exte'))
if t == 'null':
return None
if t == 'list':
l = []
for i in range(desc.AECountItems()):
keyword, item = desc.AEGetNthDesc(i+1, '****')
l.append(unpack(item))
return l
if t == 'reco':
d = {}
for i in range(desc.AECountItems()):
keyword, item = desc.AEGetNthDesc(i+1, '****')
d[keyword] = unpack(item)
return d
if t == 'obj ':
record = desc.AECoerceDesc('reco')
return mkobject(unpack(record))
if t == 'rang':
record = desc.AECoerceDesc('reco')
return mkrange(unpack(record))
if t == 'cmpd':
record = desc.AECoerceDesc('reco')
return mkcomparison(unpack(record))
if t == 'logi':
record = desc.AECoerceDesc('reco')
return mklogical(unpack(record))
if t == 'targ':
return mktargetid(desc.data)
if t == 'alis':
# XXX Can't handle alias records yet, so coerce to FS spec...
return unpack(desc.AECoerceDesc('fss '))
if t == 'fss ':
return mkfss(desc.data)
return mkunknown(desc.type, desc.data)
def mkfss(data):
print "mkfss data =", `data`
vol, dir, fnlen = struct.unpack('hlb', data[:7])
filename = data[7:7+fnlen]
print (vol, dir, fnlen, filename)
return macfs.FSSpec((vol, dir, filename))
def mktargetid(data):
sessionID = getlong(data[:4])
name = mkppcportrec(data[4:4+72])
print len(name), `name`
location = mklocationnamerec(data[76:76+36])
rcvrName = mkppcportrec(data[112:112+72])
return sessionID, name, location, rcvrName
def mkppcportrec(rec):
namescript = getword(rec[:2])
name = getpstr(rec[2:2+33])
portkind = getword(rec[36:38])
if portkind == 1:
ctor = rec[38:42]
type = rec[42:46]
identity = (ctor, type)
else:
identity = getpstr(rec[38:38+33])
return namescript, name, portkind, identity
def mklocationnamerec(rec):
kind = getword(rec[:2])
stuff = rec[2:]
if kind == 0: stuff = None
if kind == 2: stuff = getpstr(stuff)
return kind, stuff
def getpstr(s):
return s[1:1+ord(s[0])]
def getlong(s):
return (ord(s[0])<<24) | (ord(s[1])<<16) | (ord(s[2])<<8) | ord(s[3])
def getword(s):
return (ord(s[0])<<8) | (ord(s[1])<<0)
def mkunknown(type, data):
return Unknown(type, data)
class Unknown:
def __init__(self, type, data):
self.type = type
self.data = data
def __repr__(self):
return "Unknown(%s, %s)" % (`self.type`, `self.data`)
def __aepack__(self):
return pack(self.data, self.type)
def IsSubclass(cls, base):
"""Test whether CLASS1 is the same as or a subclass of CLASS2"""
# Loop to optimize for single inheritance
while 1:
if cls is base: return 1
if len(cls.__bases__) <> 1: break
cls = cls.__bases__[0]
# Recurse to cope with multiple inheritance
for c in cls.__bases__:
if IsSubclass(c, base): return 1
return 0
def IsInstance(x, cls):
"""Test whether OBJECT is an instance of (a subclass of) CLASS"""
return type(x) is InstanceType and IsSubclass(x.__class__, cls)
def nice(s):
if type(s) is StringType: return repr(s)
else: return str(s)
def mkenum(enum):
if IsEnum(enum): return enum
return Enum(enum)
class Enum:
def __init__(self, enum):
self.enum = "%-4.4s" % str(enum)
def __repr__(self):
return "Enum(%s)" % `self.enum`
def __str__(self):
return strip(self.enum)
def __aepack__(self):
return pack(self.enum, 'enum')
def IsEnum(x):
return IsInstance(x, Enum)
def mktype(type):
if IsType(type): return type
return Type(type)
class Type:
def __init__(self, type):
self.type = "%-4.4s" % str(type)
def __repr__(self):
return "Type(%s)" % `self.type`
def __str__(self):
return strip(self.type)
def __aepack__(self):
return pack(self.type, 'type')
def IsType(x):
return IsInstance(x, Type)
def mkrange(dict):
return Range(dict['star'], dict['stop'])
class Range:
def __init__(self, start, stop):
self.start = start
self.stop = stop
def __repr__(self):
return "Range(%s, %s)" % (`self.start`, `self.stop`)
def __str__(self):
return "%s thru %s" % (nice(self.start), nice(self.stop))
def __aepack__(self):
return pack({'star': self.start, 'stop': self.stop}, 'rang')
def IsRange(x):
return IsInstance(x, Range)
def mkcomparison(dict):
return Comparison(dict['obj1'], dict['relo'].enum, dict['obj2'])
class Comparison:
def __init__(self, obj1, relo, obj2):
self.obj1 = obj1
self.relo = "%-4.4s" % str(relo)
self.obj2 = obj2
def __repr__(self):
return "Comparison(%s, %s, %s)" % (`self.obj1`, `self.relo`, `self.obj2`)
def __str__(self):
return "%s %s %s" % (nice(self.obj1), strip(self.relo), nice(self.obj2))
def __aepack__(self):
return pack({'obj1': self.obj1,
'relo': mkenum(self.relo),
'obj2': self.obj2},
'cmpd')
def IsComparison(x):
return IsInstance(x, Comparison)
def mklogical(dict):
return Logical(dict['logc'], dict['term'])
class Logical:
def __init__(self, logc, term):
self.logc = "%-4.4s" % str(logc)
self.term = term
def __repr__(self):
return "Logical(%s, %s)" % (`self.logc`, `self.term`)
def __str__(self):
if type(self.term) == ListType and len(self.term) == 2:
return "%s %s %s" % (nice(self.term[0]),
strip(self.logc),
nice(self.term[1]))
else:
return "%s(%s)" % (strip(self.logc), nice(self.term))
def __aepack__(self):
return pack({'logc': mkenum(self.logc), 'term': self.term}, 'logi')
def IsLogical(x):
return IsInstance(x, Logical)
class ObjectSpecifier:
"""A class for constructing and manipulation AE object specifiers in python.
An object specifier is actually a record with four fields:
key type description
--- ---- -----------
'want' type what kind of thing we want,
e.g. word, paragraph or property
'form' enum how we specify the thing(s) we want,
e.g. by index, by range, by name, or by property specifier
'seld' any which thing(s) we want,
e.g. its index, its name, or its property specifier
'from' object the object in which it is contained,
or null, meaning look for it in the application
Note that we don't call this class plain "Object", since that name
is likely to be used by the application.
"""
def __init__(self, want, form, seld, fr = None):
self.want = want
self.form = form
self.seld = seld
self.fr = fr
def __repr__(self):
s = "ObjectSpecifier(%s, %s, %s" % (`self.want`, `self.form`, `self.seld`)
if self.fr:
s = s + ", %s)" % `self.fr`
else:
s = s + ")"
return s
def __aepack__(self):
return pack({'want': mktype(self.want),
'form': mkenum(self.form),
'seld': self.seld,
'from': self.fr},
'obj ')
def IsObjectSpecifier(x):
return IsInstance(x, ObjectSpecifier)
class Property(ObjectSpecifier):
def __init__(self, which, fr = None):
ObjectSpecifier.__init__(self, 'prop', 'prop', mkenum(which), fr)
def __repr__(self):
if self.fr:
return "Property(%s, %s)" % (`self.seld.enum`, `self.fr`)
else:
return "Property(%s)" % `self.seld.enum`
def __str__(self):
if self.fr:
return "Property %s of %s" % (str(self.seld), str(self.fr))
else:
return "Property %s" % str(self.seld)
class SelectableItem(ObjectSpecifier):
def __init__(self, want, seld, fr = None):
t = type(seld)
if t == StringType:
form = 'name'
elif IsRange(seld):
form = 'rang'
elif IsComparison(seld) or IsLogical(seld):
form = 'test'
else:
form = 'indx'
ObjectSpecifier.__init__(self, want, form, seld, fr)
class ComponentItem(SelectableItem):
# Derived classes *must* set the *class attribute* 'want' to some constant
def __init__(self, which, fr = None):
SelectableItem.__init__(self, self.want, which, fr)
def __repr__(self):
if not self.fr:
return "%s(%s)" % (self.__class__.__name__, `self.seld`)
return "%s(%s, %s)" % (self.__class__.__name__, `self.seld`, `self.fr`)
def __str__(self):
seld = self.seld
if type(seld) == StringType:
ss = repr(seld)
elif IsRange(seld):
start, stop = seld.start, seld.stop
if type(start) == InstanceType == type(stop) and \
start.__class__ == self.__class__ == stop.__class__:
ss = str(start.seld) + " thru " + str(stop.seld)
else:
ss = str(seld)
else:
ss = str(seld)
s = "%s %s" % (self.__class__.__name__, ss)
if self.fr: s = s + " of %s" % str(self.fr)
return s
template = """
class %s(ComponentItem): want = '%s'
"""
exec template % ("Text", 'text')
exec template % ("Character", 'cha ')
exec template % ("Word", 'cwor')
exec template % ("Line", 'clin')
exec template % ("Paragraph", 'cpar')
exec template % ("Window", 'cwin')
exec template % ("Document", 'docu')
exec template % ("File", 'file')
exec template % ("InsertionPoint", 'cins')
def mkobject(dict):
want = dict['want'].type
form = dict['form'].enum
seld = dict['seld']
fr = dict['from']
if form in ('name', 'indx', 'rang', 'test'):
if want == 'text': return Text(seld, fr)
if want == 'cha ': return Character(seld, fr)
if want == 'cwor': return Word(seld, fr)
if want == 'clin': return Line(seld, fr)
if want == 'cpar': return Paragraph(seld, fr)
if want == 'cwin': return Window(seld, fr)
if want == 'docu': return Document(seld, fr)
if want == 'file': return File(seld, fr)
if want == 'cins': return InsertionPoint(seld, fr)
if want == 'prop' and form == 'prop' and IsType(seld):
return Property(seld.type, fr)
return ObjectSpecifier(want, form, seld, fr)
from aetypes import *
from aepack import pack, unpack, coerce, AEDescType
# Special code to unpack an AppleEvent (which is *not* a disguised record!)
# Note by Jack: No??!? If I read the docs correctly it *is*....
aekeywords = [
'tran',
@ -531,8 +76,90 @@ def packevent(ae, parameters = {}, attributes = {}):
for key, value in attributes.items():
ae.AEPutAttributeDesc(key, pack(value))
#
# Support routine for automatically generated Suite interfaces
#
def keysubst(arguments, keydict):
"""Replace long name keys by their 4-char counterparts, and check"""
ok = keydict.values()
for k in arguments.keys():
if keydict.has_key(k):
v = arguments[k]
del arguments[k]
arguments[keydict[k]] = v
elif k != '----' and k not in ok:
raise TypeError, 'Unknown keyword argument: %s'%k
def enumsubst(arguments, key, edict):
"""Substitute a single enum keyword argument, if it occurs"""
if not arguments.has_key(key):
return
v = arguments[key]
ok = edict.values()
if edict.has_key(v):
arguments[key] = edict[v]
elif not v in ok:
raise TypeError, 'Unknown enumerator: %s'%v
def decodeerror(arguments):
"""Create the 'best' argument for a raise MacOS.Error"""
errn = arguments['errn']
errarg = (errn, MacOS.GetErrorString(errn))
if arguments.has_key('errs'):
errarg = errarg + (arguments['errs'],)
if arguments.has_key('erob'):
errarg = errarg + (arguments['erob'],)
return errarg
class TalkTo:
"""An AE connection to an application"""
def __init__(self, signature):
"""Create a communication channel with a particular application.
Addressing the application is done by specifying either a
4-byte signature, an AEDesc or an object that will __aepack__
to an AEDesc.
"""
if type(signature) == AEDescType:
self.target = signature
elif type(signature) == InstanceType and hasattr(signature, '__aepack__'):
self.target = signature.__aepack__()
elif type(signature) == StringType and len(signature) != 4:
self.target = AE.AECreateDesc(AppleEvents.typeApplSignature, signature)
else:
raise TypeError, "signature should be 4-char string or AEDesc"
self.send_flags = AppleEvents.kAEWaitReply
self.send_priority = AppleEvents.kAENormalPriority
self.send_timeout = AppleEvents.kAEDefaultTimeout
def newevent(self, code, subcode, parameters = {}, attributes = {}):
"""Create a complete structure for an apple event"""
event = AE.AECreateAppleEvent(code, subcode, self.target,
AppleEvents.kAutoGenerateReturnID, AppleEvents.kAnyTransactionID)
packevent(event, parameters, attributes)
return event
def sendevent(self, event):
"""Send a pre-created appleevent, await the reply and unpack it"""
reply = event.AESend(self.send_flags, self.send_priority,
self.send_timeout)
parameters, attributes = unpackevent(reply)
return reply, parameters, attributes
def send(self, code, subcode, parameters = {}, attributes = {}):
"""Send an appleevent given code/subcode/pars/attrs and unpack the reply"""
return self.sendevent(self.newevent(code, subcode, parameters, attributes))
def activate(self):
"""Send 'activate' command"""
self.send('misc', 'actv')
# Test program
# XXXX Should test more, really...
def test():
target = AE.AECreateDesc('sign', 'KAHL')

452
Mac/Lib/toolbox/aetypes.py Normal file
View File

@ -0,0 +1,452 @@
"""aetypes - Python objects representing various AE types."""
from AppleEvents import *
from AERegistry import *
from AEObjects import *
import struct
from types import *
import string
#
# convoluted, since there are cyclic dependencies between this file and
# aetools_convert.
#
def pack(*args):
from aepack import pack
return apply(pack, args)
def IsSubclass(cls, base):
"""Test whether CLASS1 is the same as or a subclass of CLASS2"""
# Loop to optimize for single inheritance
while 1:
if cls is base: return 1
if len(cls.__bases__) <> 1: break
cls = cls.__bases__[0]
# Recurse to cope with multiple inheritance
for c in cls.__bases__:
if IsSubclass(c, base): return 1
return 0
def IsInstance(x, cls):
"""Test whether OBJECT is an instance of (a subclass of) CLASS"""
return type(x) is InstanceType and IsSubclass(x.__class__, cls)
def nice(s):
"""'nice' representation of an object"""
if type(s) is StringType: return repr(s)
else: return str(s)
class Unknown:
"""An uninterpreted AE object"""
def __init__(self, type, data):
self.type = type
self.data = data
def __repr__(self):
return "Unknown(%s, %s)" % (`self.type`, `self.data`)
def __aepack__(self):
return pack(self.data, self.type)
class Enum:
"""An AE enumeration value"""
def __init__(self, enum):
self.enum = "%-4.4s" % str(enum)
def __repr__(self):
return "Enum(%s)" % `self.enum`
def __str__(self):
return string.strip(self.enum)
def __aepack__(self):
return pack(self.enum, typeEnumeration)
def IsEnum(x):
return IsInstance(x, Enum)
def mkenum(enum):
if IsEnum(enum): return enum
return Enum(enum)
class Type:
"""An AE 4-char typename object"""
def __init__(self, type):
self.type = "%-4.4s" % str(type)
def __repr__(self):
return "Type(%s)" % `self.type`
def __str__(self):
return string.strip(self.type)
def __aepack__(self):
return pack(self.type, typeType)
def IsType(x):
return IsInstance(x, Type)
def mktype(type):
if IsType(type): return type
return Type(type)
class Keyword:
"""An AE 4-char keyword object"""
def __init__(self, keyword):
self.keyword = "%-4.4s" % str(keyword)
def __repr__(self):
return "Keyword(%s)" % `self.keyword`
def __str__(self):
return string.strip(self.keyword)
def __aepack__(self):
return pack(self.keyword, typeKeyword)
def IsKeyword(x):
return IsInstance(x, Keyword)
class Range:
"""An AE range object"""
def __init__(self, start, stop):
self.start = start
self.stop = stop
def __repr__(self):
return "Range(%s, %s)" % (`self.start`, `self.stop`)
def __str__(self):
return "%s thru %s" % (nice(self.start), nice(self.stop))
def __aepack__(self):
return pack({'star': self.start, 'stop': self.stop}, 'rang')
def IsRange(x):
return IsInstance(x, Range)
class Comparison:
"""An AE Comparison"""
def __init__(self, obj1, relo, obj2):
self.obj1 = obj1
self.relo = "%-4.4s" % str(relo)
self.obj2 = obj2
def __repr__(self):
return "Comparison(%s, %s, %s)" % (`self.obj1`, `self.relo`, `self.obj2`)
def __str__(self):
return "%s %s %s" % (nice(self.obj1), string.strip(self.relo), nice(self.obj2))
def __aepack__(self):
return pack({'obj1': self.obj1,
'relo': mkenum(self.relo),
'obj2': self.obj2},
'cmpd')
def IsComparison(x):
return IsInstance(x, Comparison)
class Logical:
"""An AE logical expression object"""
def __init__(self, logc, term):
self.logc = "%-4.4s" % str(logc)
self.term = term
def __repr__(self):
return "Logical(%s, %s)" % (`self.logc`, `self.term`)
def __str__(self):
if type(self.term) == ListType and len(self.term) == 2:
return "%s %s %s" % (nice(self.term[0]),
string.strip(self.logc),
nice(self.term[1]))
else:
return "%s(%s)" % (string.strip(self.logc), nice(self.term))
def __aepack__(self):
return pack({'logc': mkenum(self.logc), 'term': self.term}, 'logi')
def IsLogical(x):
return IsInstance(x, Logical)
class StyledText:
"""An AE object respresenting text in a certain style"""
def __init__(self, style, text):
self.style = style
self.text = text
def __repr__(self):
return "StyledText(%s, %s)" % (`self.style`, `self.text`)
def __str__(self):
return self.text
def __aepack__(self):
return pack({'ksty': self.style, 'ktxt': self.text}, 'STXT')
def IsStyledText(x):
return IsInstance(x, StyledText)
class AEText:
"""An AE text object with style, script and language specified"""
def __init__(self, script, style, text):
self.script = script
self.style = style
self.text = text
def __repr__(self):
return "AEText(%s, %s, %s)" % (`self.script`, `self.style`, `self.text`)
def __str__(self):
return self.text
def __aepack__(self):
return pack({keyAEScriptTag: self.script, keyAEStyles: self.style,
keyAEText: self.text}, typeAEText)
def IsAEText(x):
return IsInstance(x, AEText)
class IntlText:
"""A text object with script and language specified"""
def __init__(self, script, language, text):
self.script = script
self.language = language
self.text = text
def __repr__(self):
return "IntlText(%s, %s, %s)" % (`self.script`, `self.language`, `self.text`)
def __str__(self):
return self.text
def __aepack__(self):
return pack(struct.pack('hh', self.script, self.language)+self.text,
typeIntlText)
def IsIntlText(x):
return IsInstance(x, IntlText)
class IntlWritingCode:
"""An object representing script and language"""
def __init__(self, script, language):
self.script = script
self.language = language
def __repr__(self):
return "IntlWritingCode(%s, %s)" % (`self.script`, `self.language`)
def __str__(self):
return "script system %d, language %d"%(self.script, self.language)
def __aepack__(self):
return pack(struct.pack('hh', self.script, self.language),
typeIntlWritingCode)
def IsIntlWritingCode(x):
return IsInstance(x, IntlWritingCode)
class QDPoint:
"""A point"""
def __init__(self, v, h):
self.v = v
self.h = h
def __repr__(self):
return "QDPoint(%s, %s)" % (`self.v`, `self.h`)
def __str__(self):
return "(%d, %d)"%(self.v, self.h)
def __aepack__(self):
return pack(struct.pack('hh', self.v, self.h),
typeQDPoint)
def IsQDPoint(x):
return IsInstance(x, QDPoint)
class QDRectangle:
"""A rectangle"""
def __init__(self, v0, h0, v1, h1):
self.v0 = v0
self.h0 = h0
self.v1 = v1
self.h1 = h1
def __repr__(self):
return "QDRectangle(%s, %s, %s, %s)" % (`self.v0`, `self.h0`,
`self.v1`, `self.h1`)
def __str__(self):
return "(%d, %d)-(%d, %d)"%(self.v0, self.h0, self.v1, self.h1)
def __aepack__(self):
return pack(struct.pack('hhhh', self.v0, self.h0, self.v1, self.h1),
typeQDRectangle)
def IsQDRectangle(x):
return IsInstance(x, QDRectangle)
class RGBColor:
"""An RGB color"""
def __init__(self, r, g, b):
self.r = r
self.g = g
self.b = b
def __repr__(self):
return "RGBColor(%s, %s, %s)" % (`self.r`, `self.g`, `self.b`)
def __str__(self):
return "0x%x red, 0x%x green, 0x%x blue"% (self.r, self.g, self.b)
def __aepack__(self):
return pack(struct.pack('hhh', self.r, self.g, self.b),
typeRGBColor)
def IsRGBColor(x):
return IsInstance(x, RGBColor)
class ObjectSpecifier:
"""A class for constructing and manipulation AE object specifiers in python.
An object specifier is actually a record with four fields:
key type description
--- ---- -----------
'want' type what kind of thing we want,
e.g. word, paragraph or property
'form' enum how we specify the thing(s) we want,
e.g. by index, by range, by name, or by property specifier
'seld' any which thing(s) we want,
e.g. its index, its name, or its property specifier
'from' object the object in which it is contained,
or null, meaning look for it in the application
Note that we don't call this class plain "Object", since that name
is likely to be used by the application.
"""
def __init__(self, want, form, seld, fr = None):
self.want = want
self.form = form
self.seld = seld
self.fr = fr
def __repr__(self):
s = "ObjectSpecifier(%s, %s, %s" % (`self.want`, `self.form`, `self.seld`)
if self.fr:
s = s + ", %s)" % `self.fr`
else:
s = s + ")"
return s
def __aepack__(self):
return pack({'want': mktype(self.want),
'form': mkenum(self.form),
'seld': self.seld,
'from': self.fr},
'obj ')
def IsObjectSpecifier(x):
return IsInstance(x, ObjectSpecifier)
class Property(ObjectSpecifier):
def __init__(self, which, fr = None):
ObjectSpecifier.__init__(self, 'prop', 'prop', mkenum(which), fr)
def __repr__(self):
if self.fr:
return "Property(%s, %s)" % (`self.seld.enum`, `self.fr`)
else:
return "Property(%s)" % `self.seld.enum`
def __str__(self):
if self.fr:
return "Property %s of %s" % (str(self.seld), str(self.fr))
else:
return "Property %s" % str(self.seld)
class SelectableItem(ObjectSpecifier):
def __init__(self, want, seld, fr = None):
t = type(seld)
if t == StringType:
form = 'name'
elif IsRange(seld):
form = 'rang'
elif IsComparison(seld) or IsLogical(seld):
form = 'test'
else:
form = 'indx'
ObjectSpecifier.__init__(self, want, form, seld, fr)
class ComponentItem(SelectableItem):
# Derived classes *must* set the *class attribute* 'want' to some constant
def __init__(self, which, fr = None):
SelectableItem.__init__(self, self.want, which, fr)
def __repr__(self):
if not self.fr:
return "%s(%s)" % (self.__class__.__name__, `self.seld`)
return "%s(%s, %s)" % (self.__class__.__name__, `self.seld`, `self.fr`)
def __str__(self):
seld = self.seld
if type(seld) == StringType:
ss = repr(seld)
elif IsRange(seld):
start, stop = seld.start, seld.stop
if type(start) == InstanceType == type(stop) and \
start.__class__ == self.__class__ == stop.__class__:
ss = str(start.seld) + " thru " + str(stop.seld)
else:
ss = str(seld)
else:
ss = str(seld)
s = "%s %s" % (self.__class__.__name__, ss)
if self.fr: s = s + " of %s" % str(self.fr)
return s
template = """
class %s(ComponentItem): want = '%s'
"""
exec template % ("Text", 'text')
exec template % ("Character", 'cha ')
exec template % ("Word", 'cwor')
exec template % ("Line", 'clin')
exec template % ("Paragraph", 'cpar')
exec template % ("Window", 'cwin')
exec template % ("Document", 'docu')
exec template % ("File", 'file')
exec template % ("InsertionPoint", 'cins')