Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c15ab03

Browse files
committed
Updated the applescript documentation for te new framework, and replaced the Eudora example with one that uses Disk Copy (which everyone running MacOS 8 or
higher should have).
1 parent e743c6e commit c15ab03

9 files changed

Lines changed: 1252 additions & 963 deletions

File tree

Mac/Demo/applescript.html

Lines changed: 87 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@
33
<H1>Using Open Scripting Extension from Python</H1>
44
<HR>
55

6-
OSA support in Python is still far from complete, and what
7-
support there is is likely to change in the forseeable future. Still,
6+
OSA support in Python is still not 100% complete, but
87
there is already enough in place to allow you to do some nifty things
98
to other programs from your python program. <P>
109

@@ -20,11 +19,27 @@ <H1>Using Open Scripting Extension from Python</H1>
2019
to concentrate on the OSA details we don't bother with a real
2120
user-interface for our application. <p>
2221

23-
The application we are going to script is Eudora Light, a free mail
24-
program from <A HREF="http://www.qualcomm.com">QualComm</A>. This is a
25-
very versatile mail-reader, and QualComm has an accompanying
26-
commercial version once your needs outgrow Eudora Light. Our program
27-
will tell Eudora to send queued mail, retrieve mail or quit. <p>
22+
The application we are going to script is Disk Copy, Apple's standard
23+
utility for making copies of floppies, creating files that are mountable
24+
as disk images, etc. <p>
25+
26+
<H2>Python OSA architecture</H2>
27+
28+
Open Scripting suites and inheritance can be modelled rather nicely with
29+
with Python packages, so for each application we want to script we generate
30+
a package. Each suite defined in the application becomes a module in the
31+
package, and the package main module imports everything from all the
32+
submodules and glues all the classes (Python terminology, OSA terminology is
33+
events, AppleScript terminology is verbs) together. <p>
34+
35+
A suite in an OSA application can extend the functionality of a standard
36+
suite, and this is implemented in Python by importing everything from the
37+
module that implements the standard suite and overriding anything that has
38+
been extended. The standard suites live in the StdSuite package. <p>
39+
40+
This all sounds complicated, and you can do strange and wondrous things
41+
with it once you fully understand it, but the good news is that simple
42+
scripting is actually pretty simple. <p>
2843

2944
<H2>Creating the Python interface module</H2>
3045

@@ -33,69 +48,76 @@ <H2>Creating the Python interface module</H2>
3348
AppleScript dictionary. This tool is called
3449
<CODE>gensuitemodule.py</CODE>, and lives in <CODE>Mac:scripts</CODE>.
3550
When we start it, it asks us for an input file and we point it to the
36-
Eudora Light executable. It starts parsing the AETE resource, and for
51+
Disk Copy executable. <p>
52+
53+
Next it wants a folder where it will store the package it is going to generate.
54+
Note that this is the package folder, not the parent folder, so we
55+
navigate to <code>Python:Mac:Demo:applescript</code>, create a folder
56+
<code>Disk_Copy</code> and select that. <p>
57+
58+
Next it wants the folder from which it should import the standard suites. Here
59+
you always select <code>Python:Mac:Lib:lib-scriptpackages</code>. (There is
60+
one exception to this rule: when you are generating <code>StdSuites</code> itself
61+
you select <code>cancel</code>, for obvious reasons). <p>
62+
63+
It starts parsing the AETE resource, and for
3764
each AppleEvent suite it finds it prompts us for the filename of the
3865
resulting python module. Remember to change folders for the first
3966
module, you don't want to clutter up the Eudora folder with your python
4067
interfaces. If you want to skip a suite you press cancel and the process
41-
continues with the next suite. In the case of Eudora, you do
42-
<EM>not</EM> want to generate the Required and Standard suites, because
43-
they are identical to the standard ones which are pregenerated (and
44-
empty in the eudora binary). AppleScript understands that an empty suite
45-
means "incorporate the whole standard suite by this name",
46-
gensuitemodule does not currently understand this. Creating the empty
47-
<CODE>Required_Suite.py</CODE> would hide the correct module of that
48-
name from our application. <p>
68+
continues with the next suite. <p>
4969

5070
Gensuitemodule may ask you questions like "Where is enum 'xyz ' declared?".
51-
For the first time, cancel out of this dialog after taking down the
52-
enum (or class or prop) name. After you've created all the suites look
53-
for these codes, in the suites generated here and in the standard suites.
54-
If you've found them all run gensuitemodule again and point it to the right
55-
file for each declaration. Gensuitemodule will generate the imports to make the
56-
reference work. <p>
71+
This is either due to a misunderstanding on my part or (rather too common)
72+
bugs in the AETE resources. Pressing <code>cancel</code> is usually the
73+
right option, it will cause the specific enum not to be treated as an enum
74+
but as a "normal" type. As things like fsspecs and TEXT strings clearly are
75+
not enumerators this is correct. If someone understands what is really going on
76+
here please let me know. <p>
5777

5878
<BLOCKQUOTE>
59-
Time for a sidebar. If you want to re-create
60-
<CODE>Required_Suite.py</CODE> or one of the other standard modules
61-
you should look in <CODE>System Folder:Extensions:Scripting
62-
Additions:Dialects:English Dialect</CODE>, that is where the core
63-
AppleEvent dictionaries live. Also, if you are looking for the
64-
<CODE>Finder_Suite</CODE> interface: don't look in the finder (it has
65-
an old System 7.0 scripting suite), look at the extension <CODE>Finder
66-
Scripting Extension</CODE>. <p>
79+
Time for a sidebar. If you want to re-create the StdSuite modules
80+
you should look in one of two places. On older systems you will find the
81+
AEUT resources in <CODE>System Folder:Extensions:Scripting
82+
Additions:Dialects:English Dialect</CODE>. On newer systems you will
83+
find them in <code>System Folder:Extensions:Applescript</code>. <p>
6784
</BLOCKQUOTE>
6885

6986
Let's glance at the <A
70-
HREF="scripting/Eudora_Suite.py">Eudora_Suite.py</A> just created. You
87+
HREF="applescript/Disk_Copy">Disk_Copy</A> package just created. You
7188
may want to open Script Editor alongside, and have a look at how it
72-
interprets the dictionary. EudoraSuite.py starts with some
73-
boilerplate, then a big class definition with methods for each
74-
AppleScript Verb, then some small class definitions and then some dictionary
75-
initializations. <p>
76-
77-
The <CODE>Eudora_Suite</CODE> class is the bulk of the code
89+
interprets the dictionary. The main package module is in <code>__init__.py</code>
90+
and the only interesting bit is the <code>Disk_Copy</code> class, which
91+
includes the event handling classes from the individual suites. It also
92+
inherits <code>aetools.TalkTo</code>, which is a base class that handles all
93+
details on how to start the program and talk to it, and a class variable
94+
<code>_signature</code> which is the default application this class will talk
95+
to (you can override this in various when you instantiate your class, see
96+
<code>aetools.py</code> for details).
97+
<p>
98+
99+
The <a href="applescript/Disk_Copy/Special_Events.py">Special_Events</a>
100+
module is a nice example of a suite module.
101+
The <CODE>Special_Events_Events</CODE> class is the bulk of the code
78102
generated. For each verb it contains a method. Each method knows what
79-
arguments the verb expects, and it makes handy use of the keyword
80-
argument scheme introduced in Python 1.3 to present a palatable
103+
arguments the verb expects, and it makes handy use of keyword
104+
arguments to present a palatable
81105
interface to the python programmer. You will see that each method
82106
calls some routines from <CODE>aetools</CODE>, an auxiliary module
83107
living in <CODE>Lib:toolbox</CODE> which contains some other nifty
84108
AppleEvent tools as well. Have a look at it sometime, there is (of
85109
course) no documentation yet. <p>
86110

87111
The other thing you notice is that each method calls
88-
<CODE>self.send</CODE>, but no such method is defined. You will have
89-
to provide it by subclassing or multiple inheritance, as we shall see
90-
later. <p>
112+
<CODE>self.send</CODE>, this comes from the <code>aetools.TalkTo</code> baseclass. <p>
91113

92114
After the big class we get a number of little class declarations. These
93115
declarations are for the (appleevent) classes and properties in the suite.
94116
They allow you to create object IDs, which can then be passed to the verbs.
95117
For instance, to get the name of the sender of the first message in mailbox
96118
inbox you would use <code>mailbox("inbox").message(1).sender</code>. It is
97119
also possible to specify this as <code>sender(message(1, mailbox("inbox")))</code>,
98-
which is sometimes needed because these classes don't inherit correctly
120+
which is sometimes needed because these classes don't always inherit correctly
99121
from baseclasses, so you may have to use a class or property from another suite. <p>
100122

101123
<blockquote>
@@ -112,66 +134,37 @@ <H2>Creating the Python interface module</H2>
112134
english names as arguments to verbs, so you don't have to bother with the 4-letter
113135
type code. So, you can say
114136
<CODE><PRE>
115-
eudora.notice(occurrence="mail_arrives")
137+
diskcopy.create(..., filesystem="Mac OS Standard")
116138
</PRE></CODE>
117-
instead of the rather more cryptic
139+
as it is called in Script Editor, in stead of the cryptic lowlevel
118140
<CODE><PRE>
119-
eudora.notice(occurrence="wArv")
141+
diskcopy.create(..., filesystem="Fhfs")
120142
</PRE></CODE><p>
121143

122144
Finally, we get the "table of contents" of the module, listing all classes and such
123145
by code, which is used by gensuitemodule. <p>
124146

125147
<H2>Using a Python suite module</H2>
126148

127-
Now that we have created the suite module we can use it in an
128-
application. We do this by creating a class that inherits
129-
<CODE>Eudora_Suite</CODE> and the <CODE>TalkTo</CODE> class from
130-
<CODE>aetools</CODE>. The <CODE>TalkTo</CODE> class is basically a
131-
container for the <CODE>send</CODE> method used by the methods from
132-
the suite classes. <p>
133-
134-
Actually, our class will also inherit <CODE>Required_Suite</CODE>,
135-
because we also need functionality from that suite: the quit
136-
command. Gensuitemodule could have created this completely derived
137-
class for us, since it has access to all information needed to build
138-
the class but unfortunately it does not do so at the moment. All in
139-
all, the heart of our program looks like this:
149+
Now that we have created the suite module we can use it in a Python script.
150+
151+
In older MacPython distributions this used to be a rather
152+
complicated affair, but with the package scheme and with the application signature
153+
known by the package it is very simple: you import the package and instantiate
154+
the class, as
140155
<CODE><PRE>
141-
import Eudora_Suite, Required_Suite, aetools
142-
143-
class Eudora(Eudora_Suite.Eudora_Suite, Required_Suite.Required_Suite, \
144-
aetools.TalkTo):
145-
pass
156+
talker = Disk_Copy.Disk_Copy(start=1)
146157
</PRE></CODE>
147-
148-
Yes, our class body is <CODE>pass</CODE>, all functionality is already
149-
provided by the base classes, the only thing we have to do is glue it
150-
together in the right way. <p>
158+
You will usually specify the start=1: it will run the application if it is
159+
not already running. You may want to omit it if you want to talk to the application
160+
only if it is already running, or if the application is something like the Finder. <p>
151161

152162
Looking at the sourcefile <A
153-
HREF="scripting/testeudora.py">testeudora.py</A> we see that it starts
154-
with some imports. Then we get the class definition
155-
for our main object and a constant giving the signature of Eudora. <p>
156-
157-
This, again, needs a little explanation. There are various ways to
158-
describe to AppleScript which program we want to talk to, but the
159-
easiest one to use (from Python, at least) is creator
160-
signature. Application name would be much nicer, but Python currently
161-
does not have a module that interfaces to the Finder database (which
162-
would allow us to map names to signatures). The other alternative,
163-
<CODE>ChooseApplication</CODE> from the program-to-program toolbox, is
164-
also not available from Python at the moment. <p>
165-
166-
If you specify the application by creator you can specify an optional
167-
<CODE>start</CODE> parameter, which will cause the application to be
168-
started if it is not running. <P>
163+
HREF="applescript/makedisk.py">makedisk.py</A> we see that it starts
164+
with some imports.
169165

170166
The main program itself is a wonder of simplicity. We create the
171-
object that talks to Eudora (passing the signature as argument), ask
172-
the user what she wants and call the appropriate method of the talker
173-
object. The use of keyword arguments with the same names as used by
174-
AppleScript make passing the parameters a breeze. <p>
167+
object that talks to Disk Copy, creates a disk and mounts it. <p>
175168

176169
The exception handling does need a few comments, though. Since
177170
AppleScript is basically a connectionless RPC protocol nothing happens
@@ -188,8 +181,7 @@ <H2>Scripting Additions</H2>
188181
everyday speech) from a Python program you can use the same method
189182
as for applications, i.e. run <CODE>gensuitemodule</CODE> on the
190183
OSAX (commonly found in <CODE>System Folder:Extensions:Scripting Additions</CODE>
191-
or something similar), define a class which inherits the generated
192-
class and <CODE>aetools.TalkTo</CODE> and instantiate it. The application
184+
or something similar). There is one minor gotcha: the application
193185
signature to use is <CODE>'MACS'</CODE>. <P>
194186

195187
There are two minor points to watch out for when using gensuitemodule
@@ -199,11 +191,8 @@ <H2>Scripting Additions</H2>
199191
(some of the non-english dialects cause gensuitemodule to generate incorrect
200192
Python code). <P>
201193

202-
That concludes our simple example. Again, let me emphasize that
203-
scripting support in Python is not very complete at the moment, and
204-
the details of how to use AppleEvents will definitely change in the
205-
near future. This will not only fix all the ideosyncracies noted in
206-
this document but also break existing programs, since the current
207-
suite organization will have to change to fix some of the problems.
208-
Still, if you want to experiment with AppleEvents right now: go ahead!
209-
<p>
194+
<H2>Further Reading</H2>
195+
196+
If you want to look at more involved examples of applescripting look at the standard
197+
modules <code>findertools</code> and <code>nsremote</code>, or (possibly better, as it
198+
is more involved) <code>fullbuild</code> from the Mac:scripts folder.

0 commit comments

Comments
 (0)