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

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

#countcontent
1n/a"""Tools for use in AppleEvent clients and servers.
2n/a
3n/apack(x) converts a Python object to an AEDesc object
4n/aunpack(desc) does the reverse
5n/a
6n/apackevent(event, parameters, attributes) sets params and attrs in an AEAppleEvent record
7n/aunpackevent(event) returns the parameters and attributes from an AEAppleEvent record
8n/a
9n/aPlus... Lots of classes and routines that help representing AE objects,
10n/aranges, conditionals, logicals, etc., so you can write, e.g.:
11n/a
12n/a x = Character(1, Document("foobar"))
13n/a
14n/aand pack(x) will create an AE object reference equivalent to AppleScript's
15n/a
16n/a character 1 of document "foobar"
17n/a
18n/aSome of the stuff that appears to be exported from this module comes from other
19n/afiles: the pack stuff from aepack, the objects from aetypes.
20n/a
21n/a"""
22n/a
23n/a
24n/afrom warnings import warnpy3k
25n/awarnpy3k("In 3.x, the aetools module is removed.", stacklevel=2)
26n/a
27n/afrom types import *
28n/afrom Carbon import AE
29n/afrom Carbon import Evt
30n/afrom Carbon import AppleEvents
31n/aimport MacOS
32n/aimport sys
33n/aimport time
34n/a
35n/afrom aetypes import *
36n/afrom aepack import packkey, pack, unpack, coerce, AEDescType
37n/a
38n/aError = 'aetools.Error'
39n/a
40n/a# Amount of time to wait for program to be launched
41n/aLAUNCH_MAX_WAIT_TIME=10
42n/a
43n/a# Special code to unpack an AppleEvent (which is *not* a disguised record!)
44n/a# Note by Jack: No??!? If I read the docs correctly it *is*....
45n/a
46n/aaekeywords = [
47n/a 'tran',
48n/a 'rtid',
49n/a 'evcl',
50n/a 'evid',
51n/a 'addr',
52n/a 'optk',
53n/a 'timo',
54n/a 'inte', # this attribute is read only - will be set in AESend
55n/a 'esrc', # this attribute is read only
56n/a 'miss', # this attribute is read only
57n/a 'from' # new in 1.0.1
58n/a]
59n/a
60n/adef missed(ae):
61n/a try:
62n/a desc = ae.AEGetAttributeDesc('miss', 'keyw')
63n/a except AE.Error, msg:
64n/a return None
65n/a return desc.data
66n/a
67n/adef unpackevent(ae, formodulename=""):
68n/a parameters = {}
69n/a try:
70n/a dirobj = ae.AEGetParamDesc('----', '****')
71n/a except AE.Error:
72n/a pass
73n/a else:
74n/a parameters['----'] = unpack(dirobj, formodulename)
75n/a del dirobj
76n/a # Workaround for what I feel is a bug in OSX 10.2: 'errn' won't show up in missed...
77n/a try:
78n/a dirobj = ae.AEGetParamDesc('errn', '****')
79n/a except AE.Error:
80n/a pass
81n/a else:
82n/a parameters['errn'] = unpack(dirobj, formodulename)
83n/a del dirobj
84n/a while 1:
85n/a key = missed(ae)
86n/a if not key: break
87n/a parameters[key] = unpack(ae.AEGetParamDesc(key, '****'), formodulename)
88n/a attributes = {}
89n/a for key in aekeywords:
90n/a try:
91n/a desc = ae.AEGetAttributeDesc(key, '****')
92n/a except (AE.Error, MacOS.Error), msg:
93n/a if msg[0] != -1701 and msg[0] != -1704:
94n/a raise
95n/a continue
96n/a attributes[key] = unpack(desc, formodulename)
97n/a return parameters, attributes
98n/a
99n/adef packevent(ae, parameters = {}, attributes = {}):
100n/a for key, value in parameters.items():
101n/a packkey(ae, key, value)
102n/a for key, value in attributes.items():
103n/a ae.AEPutAttributeDesc(key, pack(value))
104n/a
105n/a#
106n/a# Support routine for automatically generated Suite interfaces
107n/a# These routines are also useable for the reverse function.
108n/a#
109n/adef keysubst(arguments, keydict):
110n/a """Replace long name keys by their 4-char counterparts, and check"""
111n/a ok = keydict.values()
112n/a for k in arguments.keys():
113n/a if k in keydict:
114n/a v = arguments[k]
115n/a del arguments[k]
116n/a arguments[keydict[k]] = v
117n/a elif k != '----' and k not in ok:
118n/a raise TypeError, 'Unknown keyword argument: %s'%k
119n/a
120n/adef enumsubst(arguments, key, edict):
121n/a """Substitute a single enum keyword argument, if it occurs"""
122n/a if key not in arguments or edict is None:
123n/a return
124n/a v = arguments[key]
125n/a ok = edict.values()
126n/a if v in edict:
127n/a arguments[key] = Enum(edict[v])
128n/a elif not v in ok:
129n/a raise TypeError, 'Unknown enumerator: %s'%v
130n/a
131n/adef decodeerror(arguments):
132n/a """Create the 'best' argument for a raise MacOS.Error"""
133n/a errn = arguments['errn']
134n/a err_a1 = errn
135n/a if 'errs' in arguments:
136n/a err_a2 = arguments['errs']
137n/a else:
138n/a err_a2 = MacOS.GetErrorString(errn)
139n/a if 'erob' in arguments:
140n/a err_a3 = arguments['erob']
141n/a else:
142n/a err_a3 = None
143n/a
144n/a return (err_a1, err_a2, err_a3)
145n/a
146n/aclass TalkTo:
147n/a """An AE connection to an application"""
148n/a _signature = None # Can be overridden by subclasses
149n/a _moduleName = None # Can be overridden by subclasses
150n/a _elemdict = {} # Can be overridden by subclasses
151n/a _propdict = {} # Can be overridden by subclasses
152n/a
153n/a __eventloop_initialized = 0
154n/a def __ensure_WMAvailable(klass):
155n/a if klass.__eventloop_initialized: return 1
156n/a if not MacOS.WMAvailable(): return 0
157n/a # Workaround for a but in MacOSX 10.2: we must have an event
158n/a # loop before we can call AESend.
159n/a Evt.WaitNextEvent(0,0)
160n/a return 1
161n/a __ensure_WMAvailable = classmethod(__ensure_WMAvailable)
162n/a
163n/a def __init__(self, signature=None, start=0, timeout=0):
164n/a """Create a communication channel with a particular application.
165n/a
166n/a Addressing the application is done by specifying either a
167n/a 4-byte signature, an AEDesc or an object that will __aepack__
168n/a to an AEDesc.
169n/a """
170n/a self.target_signature = None
171n/a if signature is None:
172n/a signature = self._signature
173n/a if type(signature) == AEDescType:
174n/a self.target = signature
175n/a elif type(signature) == InstanceType and hasattr(signature, '__aepack__'):
176n/a self.target = signature.__aepack__()
177n/a elif type(signature) == StringType and len(signature) == 4:
178n/a self.target = AE.AECreateDesc(AppleEvents.typeApplSignature, signature)
179n/a self.target_signature = signature
180n/a else:
181n/a raise TypeError, "signature should be 4-char string or AEDesc"
182n/a self.send_flags = AppleEvents.kAEWaitReply
183n/a self.send_priority = AppleEvents.kAENormalPriority
184n/a if timeout:
185n/a self.send_timeout = timeout
186n/a else:
187n/a self.send_timeout = AppleEvents.kAEDefaultTimeout
188n/a if start:
189n/a self._start()
190n/a
191n/a def _start(self):
192n/a """Start the application, if it is not running yet"""
193n/a try:
194n/a self.send('ascr', 'noop')
195n/a except AE.Error:
196n/a _launch(self.target_signature)
197n/a for i in range(LAUNCH_MAX_WAIT_TIME):
198n/a try:
199n/a self.send('ascr', 'noop')
200n/a except AE.Error:
201n/a pass
202n/a else:
203n/a break
204n/a time.sleep(1)
205n/a
206n/a def start(self):
207n/a """Deprecated, used _start()"""
208n/a self._start()
209n/a
210n/a def newevent(self, code, subcode, parameters = {}, attributes = {}):
211n/a """Create a complete structure for an apple event"""
212n/a
213n/a event = AE.AECreateAppleEvent(code, subcode, self.target,
214n/a AppleEvents.kAutoGenerateReturnID, AppleEvents.kAnyTransactionID)
215n/a packevent(event, parameters, attributes)
216n/a return event
217n/a
218n/a def sendevent(self, event):
219n/a """Send a pre-created appleevent, await the reply and unpack it"""
220n/a if not self.__ensure_WMAvailable():
221n/a raise RuntimeError, "No window manager access, cannot send AppleEvent"
222n/a reply = event.AESend(self.send_flags, self.send_priority,
223n/a self.send_timeout)
224n/a parameters, attributes = unpackevent(reply, self._moduleName)
225n/a return reply, parameters, attributes
226n/a
227n/a def send(self, code, subcode, parameters = {}, attributes = {}):
228n/a """Send an appleevent given code/subcode/pars/attrs and unpack the reply"""
229n/a return self.sendevent(self.newevent(code, subcode, parameters, attributes))
230n/a
231n/a #
232n/a # The following events are somehow "standard" and don't seem to appear in any
233n/a # suite...
234n/a #
235n/a def activate(self):
236n/a """Send 'activate' command"""
237n/a self.send('misc', 'actv')
238n/a
239n/a def _get(self, _object, asfile=None, _attributes={}):
240n/a """_get: get data from an object
241n/a Required argument: the object
242n/a Keyword argument _attributes: AppleEvent attribute dictionary
243n/a Returns: the data
244n/a """
245n/a _code = 'core'
246n/a _subcode = 'getd'
247n/a
248n/a _arguments = {'----':_object}
249n/a if asfile:
250n/a _arguments['rtyp'] = mktype(asfile)
251n/a
252n/a _reply, _arguments, _attributes = self.send(_code, _subcode,
253n/a _arguments, _attributes)
254n/a if 'errn' in _arguments:
255n/a raise Error, decodeerror(_arguments)
256n/a
257n/a if '----' in _arguments:
258n/a return _arguments['----']
259n/a if asfile:
260n/a item.__class__ = asfile
261n/a return item
262n/a
263n/a get = _get
264n/a
265n/a _argmap_set = {
266n/a 'to' : 'data',
267n/a }
268n/a
269n/a def _set(self, _object, _attributes={}, **_arguments):
270n/a """set: Set an object's data.
271n/a Required argument: the object for the command
272n/a Keyword argument to: The new value.
273n/a Keyword argument _attributes: AppleEvent attribute dictionary
274n/a """
275n/a _code = 'core'
276n/a _subcode = 'setd'
277n/a
278n/a keysubst(_arguments, self._argmap_set)
279n/a _arguments['----'] = _object
280n/a
281n/a
282n/a _reply, _arguments, _attributes = self.send(_code, _subcode,
283n/a _arguments, _attributes)
284n/a if _arguments.get('errn', 0):
285n/a raise Error, decodeerror(_arguments)
286n/a # XXXX Optionally decode result
287n/a if '----' in _arguments:
288n/a return _arguments['----']
289n/a
290n/a set = _set
291n/a
292n/a # Magic glue to allow suite-generated classes to function somewhat
293n/a # like the "application" class in OSA.
294n/a
295n/a def __getattr__(self, name):
296n/a if name in self._elemdict:
297n/a cls = self._elemdict[name]
298n/a return DelayedComponentItem(cls, None)
299n/a if name in self._propdict:
300n/a cls = self._propdict[name]
301n/a return cls()
302n/a raise AttributeError, name
303n/a
304n/a# Tiny Finder class, for local use only
305n/a
306n/aclass _miniFinder(TalkTo):
307n/a def open(self, _object, _attributes={}, **_arguments):
308n/a """open: Open the specified object(s)
309n/a Required argument: list of objects to open
310n/a Keyword argument _attributes: AppleEvent attribute dictionary
311n/a """
312n/a _code = 'aevt'
313n/a _subcode = 'odoc'
314n/a
315n/a if _arguments: raise TypeError, 'No optional args expected'
316n/a _arguments['----'] = _object
317n/a
318n/a
319n/a _reply, _arguments, _attributes = self.send(_code, _subcode,
320n/a _arguments, _attributes)
321n/a if 'errn' in _arguments:
322n/a raise Error, decodeerror(_arguments)
323n/a # XXXX Optionally decode result
324n/a if '----' in _arguments:
325n/a return _arguments['----']
326n/a#pass
327n/a
328n/a_finder = _miniFinder('MACS')
329n/a
330n/adef _launch(appfile):
331n/a """Open a file thru the finder. Specify file by name or fsspec"""
332n/a _finder.open(_application_file(('ID ', appfile)))
333n/a
334n/a
335n/aclass _application_file(ComponentItem):
336n/a """application file - An application's file on disk"""
337n/a want = 'appf'
338n/a
339n/a_application_file._propdict = {
340n/a}
341n/a_application_file._elemdict = {
342n/a}
343n/a
344n/a# Test program
345n/a# XXXX Should test more, really...
346n/a
347n/adef test():
348n/a target = AE.AECreateDesc('sign', 'quil')
349n/a ae = AE.AECreateAppleEvent('aevt', 'oapp', target, -1, 0)
350n/a print unpackevent(ae)
351n/a raw_input(":")
352n/a ae = AE.AECreateAppleEvent('core', 'getd', target, -1, 0)
353n/a obj = Character(2, Word(1, Document(1)))
354n/a print obj
355n/a print repr(obj)
356n/a packevent(ae, {'----': obj})
357n/a params, attrs = unpackevent(ae)
358n/a print params['----']
359n/a raw_input(":")
360n/a
361n/aif __name__ == '__main__':
362n/a test()
363n/a sys.exit(1)