~malept/ubuntu/lucid/python2.6/dev-dependency-fix

« back to all changes in this revision

Viewing changes to Mac/Demo/applescript.html

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2009-02-13 12:51:00 UTC
  • Revision ID: james.westby@ubuntu.com-20090213125100-uufgcb9yeqzujpqw
Tags: upstream-2.6.1
ImportĀ upstreamĀ versionĀ 2.6.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<!doctype HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
 
2
<html><head><title>Using the Open Scripting Architecture from Python</title></head>
 
3
<body>
 
4
<h1>Using the Open Scripting Architecture from Python</h1>
 
5
<hr>
 
6
 
 
7
<p><b>NOTE:</b> this document describes the OSA support that is shipped with
 
8
the core python distribution. Most users are better of with the more 
 
9
userfriendly <a href="http://freespace.virgin.net/hamish.sanderson/appscript.html">appscript library</a>.
 
10
 
 
11
<p>OSA support in Python is still not 100% complete, but
 
12
there is already enough in place to allow you to do some nifty things
 
13
with other programs from your python program. </p> 
 
14
 
 
15
 
 
16
<p>
 
17
In this example, we will look at a scriptable application, extract its
 
18
&#8220;AppleScript Dictionary,&#8221;  generate a Python interface package from
 
19
the dictionary, and use that package to control the application. 
 
20
The application we are going to script is Disk Copy, Apple's standard
 
21
utility for making copies of floppies, creating files that are mountable
 
22
as disk images, etc. 
 
23
Because we want
 
24
to concentrate on the OSA details, we won&#8217;t bother with a real
 
25
user-interface for our application. </p>
 
26
 
 
27
 
 
28
<p>
 
29
<em>When we say &#8220;AppleScript&#8221; in this document we actually mean
 
30
&#8220;the Open Scripting Architecture.&#8221; There is nothing
 
31
AppleScript-specific in the Python implementation. Most of this document 
 
32
focuses on the classic Mac OS; <a href="#osx">Mac OS X</a> users have some 
 
33
additional tools.</em>
 
34
</p>
 
35
 
 
36
<h2>Python OSA architecture</h2>
 
37
 
 
38
<p>Open Scripting suites and inheritance can be modelled rather nicely 
 
39
with Python packages, so we generate
 
40
a package for each application we want to script. Each suite defined in 
 
41
the application becomes a module in the
 
42
package, and the package main module imports everything from all the
 
43
submodules and glues together all the classes (in Python terminology&#8212; 
 
44
events in OSA terminology or verbs in AppleScript terminology). </p>
 
45
 
 
46
<p>
 
47
A suite in an OSA application can extend the functionality of a standard
 
48
suite. This is implemented in Python by importing everything from the
 
49
module that implements the standard suites and overriding anything that has
 
50
been extended. The standard suites live in the StdSuite package. </p>
 
51
 
 
52
<p>
 
53
This all sounds complicated, but the good news is that basic
 
54
scripting is actually pretty simple. You can do strange and wondrous things
 
55
with OSA scripting once you fully understand it. </p>
 
56
 
 
57
<h2>Creating the Python interface package</h2>
 
58
 
 
59
 
 
60
<p>There is a tool in the standard distribution that can automatically 
 
61
generate the interface packages.  This tool is called
 
62
<code>gensuitemodule.py</code>, and lives in <code>Mac:scripts</code>. 
 
63
It looks through a file
 
64
for an &#8216;AETE&#8217; or &#8216;AEUT&#8217; resource, 
 
65
the internal representation of the
 
66
AppleScript dictionary, and parses the resource to generate the suite 
 
67
modules.
 
68
When we start <code>gensuitemodule</code>, it asks us for an input file; 
 
69
for our example,
 
70
we point it to the Disk Copy executable. </p>
 
71
 
 
72
<p>
 
73
Next, <code>gensuitemodule</code> wants a folder where it will store the 
 
74
package it is going to generate.
 
75
Note that this is the package folder, not the parent folder, so we
 
76
navigate to <code>Python:Mac:Demo:applescript</code>, create a folder
 
77
<code>Disk_Copy</code>, and select that. </p>
 
78
 
 
79
<p>
 
80
We  next specify the folder from which <code>gensuitemodule</code>  
 
81
should import the standard suites. Here,
 
82
we always select <code>Python:Mac:Lib:lib-scriptpackages:StdSuites</code>. (There is
 
83
one exception to this rule: when you are generating <code>StdSuites</code> itself
 
84
you select <code>_builtinSuites</code>.)
 
85
</p>
 
86
 
 
87
<p>
 
88
It starts parsing the AETE resource, and for
 
89
each AppleEvent suite it finds, <code>gensuitemodule.py</code>
 
90
prompts us for the filename of the
 
91
resulting python module. Remember to change folders for the first
 
92
module&#8212;you don't want to clutter up, say, the 
 
93
Disk Copy folder
 
94
with your python
 
95
interfaces. If you want to skip a suite, press <code>cancel</code> and the process
 
96
continues with the next suite. </p>
 
97
 
 
98
<h3>Summary</h3>
 
99
 
 
100
<ol>
 
101
        
 
102
        <li>Run <code>gensuitemodule</code>.</li>
 
103
        
 
104
        <li>Select the application (or OSAX) for which you would like a Python interface.</li>
 
105
        
 
106
        <li>Select the package folder where the interface modules should be 
 
107
        stored.</li>
 
108
        
 
109
        <li>Specify the folder <code>Python:Mac:Lib:lib-scriptpackages:StdSuites</code>
 
110
        to import the standard suites (or <code>_builtinSuites</code> if you are 
 
111
        generating <code>StdSuites</code> itself). </li>
 
112
        
 
113
        <li>Save the generated suites (use <code>cancel</code> to skip a suite).</li>
 
114
        
 
115
        
 
116
</ol>
 
117
 
 
118
 
 
119
<h3>Notes</h3>
 
120
 
 
121
 
 
122
<ul>
 
123
        
 
124
        <li>The interface package may occasionally need some editing by hand.  For example, 
 
125
        <code>gensuitemodule</code> does not handle all Python reserved words, so
 
126
        if
 
127
         one of the AppleScript verbs is a Python reserved word, a <code>SyntaxError</code> 
 
128
         may be raised when the package is imported.  
 
129
        Simply rename the class into something acceptable, if this happens;
 
130
        take a look at how the
 
131
        <code>print</code> verb is handled (automatically by <code>gensuitemodule</code>) 
 
132
        in the standard suites. But: f you need to edit your package this should be considered a
 
133
        bug in gensuitemodule, so please report it so it can be fixed in future releases.
 
134
        </li>
 
135
        
 
136
        
 
137
        <li>If you want to re-create the StdSuite modules,
 
138
you should look in one of two places. With versions of AppleScript older than 1.4.0 
 
139
(which first shipped with OS 9.0),  you will find the
 
140
AEUT resources in <code>System Folder:Extensions:Scripting
 
141
Additions:Dialects:English Dialect</code>. For newer versions, you will
 
142
find them in <code>System Folder:Extensions:Applescript</code>.
 
143
</li>
 
144
 
 
145
        <li>Since MacPython 2.0, this new structure, with packages
 
146
per application and submodules per suite, is used. Older MacPythons had a
 
147
single level of modules, with uncertain semantics. With the new structure,
 
148
it is possible for programs to override standard suites, as programs often do.
 
149
 
 
150
</li>
 
151
 
 
152
<li><code>Gensuitemodule.py</code> may ask you questions 
 
153
like &#8220;Where is enum 'xyz ' declared?&#8221;.
 
154
This is either due to a misunderstanding on my part or (rather too commonly)
 
155
bugs in the AETE resources. Pressing <code>cancel</code> is usually the
 
156
right choice: it will cause the specific enum not to be treated as an enum
 
157
but as a &#8220;normal&#8221; type. As things like fsspecs and TEXT strings clearly are
 
158
not enumerators, this is correct. If someone understands what is really going on
 
159
here, please let me know.</li>
 
160
 
 
161
</ul>
 
162
 
 
163
 
 
164
 
 
165
<h2>The Python interface package contents</h2>
 
166
 
 
167
<p>
 
168
Let&#8217;s glance at the 
 
169
<a href="applescript/Disk_Copy">Disk_Copy</a> package just created. You
 
170
may want to open Script Editor alongside to see how it
 
171
interprets the dictionary. 
 
172
</p>
 
173
 
 
174
 
 
175
<p>
 
176
The main package module is in <code>__init__.py</code>.
 
177
The only interesting bit is the <code>Disk_Copy</code> class, which
 
178
includes the event handling classes from the individual suites. It also
 
179
inherits <code>aetools.TalkTo</code>, which is a base class that handles all
 
180
details on how to start the program and talk to it, and a class variable
 
181
<code>_signature</code> which is the default application this class will talk
 
182
to (you can override this in various ways when you instantiate your class, see
 
183
<code>aetools.py</code> for details).
 
184
</p>
 
185
 
 
186
<p>
 
187
The <a href="applescript/Disk_Copy/Special_Events.py">Special_Events</a>
 
188
module is a nice example of a suite module.
 
189
The <code>Special_Events_Events</code> class is the bulk of the code
 
190
generated. For each verb, it contains a method. Each method knows what
 
191
arguments the verb expects, and it makes  use of keyword
 
192
arguments to present a palatable
 
193
interface to the python programmer. 
 
194
 
 
195
Notice that each method
 
196
calls some routines from <code>aetools</code>, an auxiliary module
 
197
living in <code>Mac:Lib</code>.
 
198
The other thing to notice is that each method calls
 
199
<code>self.send</code>.  This comes from the <code>aetools.TalkTo</code> 
 
200
baseclass. </p>
 
201
 
 
202
 
 
203
<p>
 
204
After the big class, there are a number of little class declarations. These
 
205
declarations are for the (AppleEvent) classes and properties in the suite.
 
206
They allow you to create object IDs, which can then be passed to the verbs.
 
207
For instance,
 
208
when scripting the popular email program Eudora,
 
209
you would use <code>mailbox("inbox").message(1).sender</code>
 
210
to get the name of the sender of the first message in mailbox
 
211
inbox. It is
 
212
also possible to specify this as <code>sender(message(1, mailbox("inbox")))</code>,
 
213
which is sometimes needed because these classes don&#8217;t always inherit correctly
 
214
from baseclasses, so you may have to use a class or property from another 
 
215
suite. </p>
 
216
 
 
217
<p>
 
218
Next we get the enumeration dictionaries, which allow you to pass
 
219
english names as arguments to verbs, so you don't have to bother with the 4-letter
 
220
type code. So, you can say
 
221
<code>
 
222
        diskcopy.create(..., filesystem="Mac OS Standard")
 
223
</code>
 
224
as it is called in Script Editor, instead of the cryptic lowlevel
 
225
<code>
 
226
        diskcopy.create(..., filesystem="Fhfs")
 
227
</code></p>
 
228
 
 
229
<p>
 
230
Finally, we get the &#8220;table of contents&#8221; of the module, listing all 
 
231
classes and such
 
232
by code, which is used by <code>gensuitemodule</code> itself: if you use this
 
233
suite as a base package in a later run this is how it knows what is defined in this
 
234
suite, and what the Python names are.
 
235
</p>
 
236
 
 
237
<h3>Notes</h3>
 
238
 
 
239
<ul>
 
240
        
 
241
        <li>The <code>aetools</code> module contains some other nifty
 
242
AppleEvent tools as well. Have a look at it sometime, there is (of
 
243
course) no documentation yet. 
 
244
</li>
 
245
        
 
246
        <li>There are also some older object specifiers for standard objects in aetools.
 
247
You use these in the form <code>aetools.Word(10,
 
248
aetools.Document(1))</code>, where the corresponding AppleScript
 
249
terminology would be <code>word 10 of the first
 
250
document</code>. Examine 
 
251
<code>aetools</code> and <code>aetools.TalkTo</code>
 
252
along with
 
253
the comments at the end of your suite module if you need to create
 
254
more than the standard object specifiers.
 
255
</li>
 
256
        
 
257
</ul>
 
258
 
 
259
 
 
260
 
 
261
 
 
262
<h2>Using a Python suite module</h2>
 
263
 
 
264
<p>
 
265
Now that we have created the suite module, we can use it in a Python script.
 
266
In older MacPython distributions this used to be a rather
 
267
complicated affair, but with the package scheme and with the application signature
 
268
known by the package it is very simple: you import the package and instantiate
 
269
the class, e.g. 
 
270
<code>
 
271
        talker = Disk_Copy.Disk_Copy(start=1)
 
272
</code>
 
273
You will usually specify the <code>start=1</code>: it will run the application if it is
 
274
not already running. 
 
275
You may want to omit it if you want to talk to the application
 
276
only if it is already running, or if the application is something like the Finder. 
 
277
Another way to ensure that  the application is running is to call <code>talker._start()</code>.
 
278
</p>
 
279
 
 
280
<p>
 
281
Looking at the sourcefile <a
 
282
href="applescript/makedisk.py">makedisk.py</a>, we see that it starts
 
283
with some imports.  Naturally, one of these is the Python interface to Disk 
 
284
Copy.</p>
 
285
 
 
286
<p>
 
287
The main program itself is a wonder of simplicity: we create the
 
288
object (<code>talker</code>) that talks to Disk Copy, 
 
289
create a disk, and mount it. The bulk of 
 
290
the work is done by <code>talker</code> and the Python interface package we 
 
291
just created.</p>
 
292
 
 
293
<p>
 
294
The exception handling does warrant a few comments, though. Since
 
295
AppleScript is basically a connectionless RPC protocol,
 
296
nothing happens
 
297
when we create the <code>talker</code> object. Hence, if the destination application
 
298
is not running, we will not notice until we send our first
 
299
command (avoid this as described above). There is another thing to note about errors returned by
 
300
AppleScript calls: <code>MacOS.Error</code> is raised for
 
301
all of the errors that are known to be <code>OSErr</code>-type errors, 
 
302
while
 
303
server generated errors raise <code>aetools.Error</code>. </p>
 
304
 
 
305
<h2>Scripting Additions</h2>
 
306
 
 
307
<p>
 
308
If you want to use any of the scripting additions (or OSAXen, in
 
309
everyday speech) from a Python program, you can use the same method
 
310
as for applications, i.e. run <code>gensuitemodule</code> on the
 
311
OSAX (commonly found in <code>System Folder:Scripting Additions</code>
 
312
or something similar). There is one minor gotcha: the application
 
313
signature to use is <code>MACS</code>. You will need to edit the main class
 
314
in the <code>__init__.py</code> file of the created package and change the value 
 
315
of <code>_signature</code> to <code>MACS</code>, or use a subclass to the
 
316
same effect.
 
317
</p>
 
318
 
 
319
<p>
 
320
There are two minor points to watch out for when using <code>gensuitemodule</code>
 
321
on OSAXen: they appear all to define the class <code>System_Object_Suite</code>,
 
322
and a lot of them have the command set in multiple dialects. You have to
 
323
watch out for name conflicts and make sure you select a reasonable dialect
 
324
(some of the non-English dialects cause <code>gensuitemodule</code> to generate incorrect
 
325
Python code). </p>
 
326
 
 
327
Despite these difficulties, OSAXen offer a lot of possibilities.  Take a 
 
328
look at some of the OSAXen in the Scripting Additions folder, or 
 
329
<A HREF="http://www.osaxen.com/index.php">download</A> some from the net.
 
330
 
 
331
<h2>Further Reading</h2>
 
332
 
 
333
<p>
 
334
If you want to look at more involved examples of applescripting, look at the standard
 
335
modules <code>findertools</code> and <code>nsremote</code>, or (possibly better, as it
 
336
is more involved) <code>fullbuild</code> from the <code>Mac:scripts</code> folder.
 
337
</p>
 
338
 
 
339
<h2><a name="alternatives">Alternatives</a></h2>
 
340
 
 
341
<h3><a name="osx">Mac OS X</a></h3>
 
342
 
 
343
<p>
 
344
Under Mac OS X, the above still works, but with some new difficulties.
 
345
The application package structure can hide the &#8216;AETE&#8217; or
 
346
&#8216;AEUT&#8217; resource from <code>gensuitemodule</code>, so that,
 
347
for example, it cannot generate an OSA interface to iTunes. Script
 
348
Editor gets at the dictionary of such programs using a &#8216;Get
 
349
AETE&#8217; AppleEvent, if someone wants to donate code to use the same
 
350
method for gensuitemodule: by all means!
 
351
</p>
 
352
 
 
353
<p>
 
354
One alternative is available through the Unix command line version of python. 
 
355
Apple has provided the <code>osacompile</code> and <code>osascript</code> tools, 
 
356
which can be used to compile and execute scripts written in OSA languages. See the 
 
357
man pages for more details.
 
358
</p>
 
359
 
 
360
 
 
361
</body>
 
362
</html>