1 """Tools for use in AppleEvent clients and servers.
3 pack(x) converts a Python object to an AEDesc object
4 unpack(desc) does the reverse
6 packevent(event, parameters, attributes) sets params and attrs in an AEAppleEvent record
7 unpackevent(event) returns the parameters and attributes from an AEAppleEvent record
9 Plus... Lots of classes and routines that help representing AE objects,
10 ranges, conditionals, logicals, etc., so you can write, e.g.:
12 x = Character(1, Document("foobar"))
14 and pack(x) will create an AE object reference equivalent to AppleScript's
16 character 1 of document "foobar"
18 Some of the stuff that appears to be exported from this module comes from other
19 files: the pack stuff from aepack, the objects from aetypes.
31 from aepack
import pack
, unpack
, coerce, AEDescType
33 Error
= 'aetools.Error'
35 # Special code to unpack an AppleEvent (which is *not* a disguised record!)
36 # Note by Jack: No??!? If I read the docs correctly it *is*....
46 'inte', # this attribute is read only - will be set in AESend
47 'esrc', # this attribute is read only
48 'miss', # this attribute is read only
54 desc
= ae
.AEGetAttributeDesc('miss', 'keyw')
64 parameters
[key
] = unpack(ae
.AEGetParamDesc(key
, '****'))
66 for key
in aekeywords
:
68 desc
= ae
.AEGetAttributeDesc(key
, '****')
69 except (AE
.Error
, MacOS
.Error
), msg
:
70 if msg
[0] != -1701 and msg
[0] != -1704:
71 raise sys
.exc_type
, sys
.exc_value
73 attributes
[key
] = unpack(desc
)
74 return parameters
, attributes
76 def packevent(ae
, parameters
= {}, attributes
= {}):
77 for key
, value
in parameters
.items():
78 ae
.AEPutParamDesc(key
, pack(value
))
79 for key
, value
in attributes
.items():
80 ae
.AEPutAttributeDesc(key
, pack(value
))
83 # Support routine for automatically generated Suite interfaces
84 # These routines are also useable for the reverse function.
86 def keysubst(arguments
, keydict
):
87 """Replace long name keys by their 4-char counterparts, and check"""
89 for k
in arguments
.keys():
90 if keydict
.has_key(k
):
93 arguments
[keydict
[k
]] = v
94 elif k
!= '----' and k
not in ok
:
95 raise TypeError, 'Unknown keyword argument: %s'%k
97 def enumsubst(arguments
, key
, edict
):
98 """Substitute a single enum keyword argument, if it occurs"""
99 if not arguments
.has_key(key
):
104 arguments
[key
] = edict
[v
]
106 raise TypeError, 'Unknown enumerator: %s'%v
108 def decodeerror(arguments
):
109 """Create the 'best' argument for a raise MacOS.Error"""
110 errn
= arguments
['errn']
112 if arguments
.has_key('errs'):
113 err_a2
= arguments
['errs']
115 err_a2
= MacOS
.GetErrorString(errn
)
116 if arguments
.has_key('erob'):
117 err_a3
= arguments
['erob']
121 return (err_a1
, err_a2
, err_a3
)
124 """An AE connection to an application"""
126 def __init__(self
, signature
, start
=0, timeout
=0):
127 """Create a communication channel with a particular application.
129 Addressing the application is done by specifying either a
130 4-byte signature, an AEDesc or an object that will __aepack__
133 self
.target_signature
= None
134 if type(signature
) == AEDescType
:
135 self
.target
= signature
136 elif type(signature
) == InstanceType
and hasattr(signature
, '__aepack__'):
137 self
.target
= signature
.__aepack
__()
138 elif type(signature
) == StringType
and len(signature
) == 4:
139 self
.target
= AE
.AECreateDesc(AppleEvents
.typeApplSignature
, signature
)
140 self
.target_signature
= signature
142 raise TypeError, "signature should be 4-char string or AEDesc"
143 self
.send_flags
= AppleEvents
.kAEWaitReply
144 self
.send_priority
= AppleEvents
.kAENormalPriority
146 self
.send_timeout
= timeout
148 self
.send_timeout
= AppleEvents
.kAEDefaultTimeout
153 """Start the application, if it is not running yet"""
154 _launch(self
.target_signature
)
156 def newevent(self
, code
, subcode
, parameters
= {}, attributes
= {}):
157 """Create a complete structure for an apple event"""
159 event
= AE
.AECreateAppleEvent(code
, subcode
, self
.target
,
160 AppleEvents
.kAutoGenerateReturnID
, AppleEvents
.kAnyTransactionID
)
161 packevent(event
, parameters
, attributes
)
164 def sendevent(self
, event
):
165 """Send a pre-created appleevent, await the reply and unpack it"""
167 reply
= event
.AESend(self
.send_flags
, self
.send_priority
,
169 parameters
, attributes
= unpackevent(reply
)
170 return reply
, parameters
, attributes
172 def send(self
, code
, subcode
, parameters
= {}, attributes
= {}):
173 """Send an appleevent given code/subcode/pars/attrs and unpack the reply"""
174 return self
.sendevent(self
.newevent(code
, subcode
, parameters
, attributes
))
177 # The following events are somehow "standard" and don't seem to appear in any
181 """Send 'activate' command"""
182 self
.send('misc', 'actv')
184 def _get(self
, _object
, as=None, _attributes
={}):
185 """_get: get data from an object
186 Required argument: the object
187 Keyword argument _attributes: AppleEvent attribute dictionary
193 _arguments
= {'----':_object
}
195 _arguments
['rtyp'] = mktype(as)
197 _reply
, _arguments
, _attributes
= self
.send(_code
, _subcode
,
198 _arguments
, _attributes
)
199 if _arguments
.has_key('errn'):
200 raise Error
, decodeerror(_arguments
)
202 if _arguments
.has_key('----'):
203 return _arguments
['----']
205 # Tiny Finder class, for local use only
207 class _miniFinder(TalkTo
):
208 def open(self
, _object
, _attributes
={}, **_arguments
):
209 """open: Open the specified object(s)
210 Required argument: list of objects to open
211 Keyword argument _attributes: AppleEvent attribute dictionary
216 if _arguments
: raise TypeError, 'No optional args expected'
217 _arguments
['----'] = _object
220 _reply
, _arguments
, _attributes
= self
.send(_code
, _subcode
,
221 _arguments
, _attributes
)
222 if _arguments
.has_key('errn'):
223 raise aetools
.Error
, aetools
.decodeerror(_arguments
)
224 # XXXX Optionally decode result
225 if _arguments
.has_key('----'):
226 return _arguments
['----']
229 _finder
= _miniFinder('MACS')
231 def _launch(appfile
):
232 """Open a file thru the finder. Specify file by name or fsspec"""
233 _finder
.open(_application_file(('ID ', appfile
)))
236 class _application_file(ComponentItem
):
237 """application file - An application's file on disk"""
240 _application_file
._propdict
= {
242 _application_file
._elemdict
= {
246 # XXXX Should test more, really...
249 target
= AE
.AECreateDesc('sign', 'quil')
250 ae
= AE
.AECreateAppleEvent('aevt', 'oapp', target
, -1, 0)
251 print unpackevent(ae
)
253 ae
= AE
.AECreateAppleEvent('core', 'getd', target
, -1, 0)
254 obj
= Character(2, Word(1, Document(1)))
257 packevent(ae
, {'----': obj
})
258 params
, attrs
= unpackevent(ae
)
262 if __name__
== '__main__':