Actually, when we say "AppleScript" in this document we actually mean
"the Open Scripting Architecture", there is nothing
AppleScript-specific in the Python implementation.
The application we are going to script is Eudora Light, a free mail program from QualComm. This is a very versatile mail-reader, and QualComm has an accompanying commercial version once your needs outgrow Eudora Light. Our program will tell Eudora to send queued mail, retrieve mail or quit.
gensuitemodule.py
, and lives in
Tools:bgen:ae
. When we start it, it asks us for an input
file and we point it to the Eudora Light executable. It starts parsing
the AETE resource, and for each AppleEvent suite it finds it prompts
us for the filename of the resulting python module. Remember to change
folders for the first module, you don't want to clutter up the Eudora
folder with your python interfaces. If you want to skip a suite you
press cancel and the process continues with the next suite. In the
case of Eudora, you do not want to generate the Required
suite, because it will be empty. AppleScript understands that an empty
suite means "incorporate the whole standard suite by this name",
gensuitemodule does not currently understand this. Creating the empty
Required_Suite.py
would hide the correct module of that
name from our application.
Time for a sidebar. If you want to re-create
Required_Suite.py
or one of the other standard modules
you should look in System Folder:Extensions:Scripting
Additions:Dialects:English Dialect
, that is where the core
AppleEvent dictionaries live. Also, if you are looking for the
Finder_Suite
interface: don't look in the finder (it has
an old System 7.0 scripting suite), look at the extension Finder
Scripting Extension
.
instead of the rather more cryptic
eudora.notice(occurrence="mail_arrives")
The
eudora.notice(occurrence="wArv")
Eudora_Suite
class is the bulk of the code
generated. For each verb it contains a method. Each method knows what
arguments the verb expects, and it makes handy use of the keyword
argument scheme introduced in Python 1.3 to present a palatable
interface to the python programmer. You will see that each method
calls some routines from aetools
, an auxiliary module
living in Tools:bgen:ae
which contains some other nifty
AppleEvent tools as well. Have a look at it sometime, there is (of
course) no documentation yet.
The other thing you notice is that each method calls
self.send
, but no such method is defined. You will have
to provide it by subclassing or multiple inheritance, as we shall see
later.
The module ends with some comments. Sadly, gensuitemodule is not yet
able to turn the Object Specifiers into reasonable Python code. For
now, if you need object specifiers, you will have to use the routines
defined in aetools.py
(and aetypes.py
, which
it incorporates). You use these in the form aetools.Word(10,
aetools.Document(1))
where the corresponding AppleScript
terminology would be word 10 of the first
document
. Examine the two modules mentioned above along with
the comments at the end of your suite module if you need to create
more than the standard object specifiers.
Eudora_Suite
and the TalkTo
class from
aetools
. The TalkTo
class is basically a
container for the send
method used by the methods from
the suite classes.
Actually, our class will also inherit Required_Suite
,
because we also need functionality from that suite: the quit
command. Gensuitemodule could have created this completely derived
class for us, since it has access to all information needed to build
the class but unfortunately it does not do so at the moment. All in
all, the heart of our program looks like this:
Yes, our class body is
import Eudora_Suite, Required_Suite, aetools
class Eudora(aetools.TalkTo, Required_Suite.Required_Suite, \
Eudora_Suite.Eudora_Suite):
pass
pass
, all functionality is already
provided by the base classes, the only thing we have to do is glue it
together in the right way.
Looking at the sourcefile testeudora.py we see that it starts
with some imports (and some addpack
calls to extend
sys.path
to include Tools:bgen:ae
, use of
ni
should be preferred over addpack
but I
have not managed to master it yet). Then we get the class definition
for our main object and a constant giving the signature of Eudora.
This, again, needs a little explanation. There are various ways to
describe to AppleScript which program we want to talk to, but the
easiest one to use (from Python, at least) is creator
signature. Application name would be much nicer, but Python currently
does not have a module that interfaces to the Finder database (which
would allow us to map names to signatures). The other alternative,
ChooseApplication
from the program-to-program toolbox, is
also not available from Python at the moment.
The main program itself is a wonder of simplicity. We create the object that talks to Eudora (passing the signature as argument), ask the user what she wants and call the appropriate method of the talker object. The use of keyword arguments with the same names as used by AppleScript make passing the parameters a breeze.
The exception handling does need a few comments, though. Since
AppleScript is basically a connectionless RPC protocol nothing happens
when we create to talker object. Hence, if the destination application
is not running we will not notice until we send our first
command. There is another thing to note about errors returned by
AppleScript calls: even though MacOS.Error
is raised not
all of the errors are actually OSErr
-type errors, some
are error codes returned by the server application. In that case, the
error message will be incorrect.
That concludes our simple example. Again, let me emphasize that scripting support in Python is not very complete at the moment, and the details of how to use AppleEvents will definitely change in the near future. This will not only fix all the ideosyncracies noted in this document but also break existing programs, since the current suite organization will have to change to fix some of the problems. Still, if you want to experiment with AppleEvents right now: go ahead!