Applescript and Python are quite different, but can be used together to make very efficient tools without compromising the modularity of Python. This is a quick introduction to the major concepts with some real examples. I will also briefly cover using bash aliases with your code to make it even more effective.
Before we can even start I need to introduce you to being lazy with bash aliases and osascript, via the Script Editor application. The Script Editor is an IDE for AppleScript that works pretty well. But first, be lazy! Alias Script Editor to your .profile or .bashrc., here is an example of mine:
alias ose='open /Applications/AppleScript/Script\ Editor.app/'
(Note to add this to your .profile using vim:
Now from the command line, in a new shell type in: (Command + N for you keyboard shortcut guys like me)
Pretty cool right? Next, let's get even lazier. Let's write an embedded AppleScript to close Script Editor from bash and put it in your bash profile.
First, export two variables in
export OSA='osascript -e ' export SE='"Script Editor"'
Next, alias a close command:
alias cse='$OSA "tell app $SE to quit"'
Try it out, open a new shell and open the Script Editor again:
Now be lazy and close that shell from the terminal:
Pretty nifty; but you might be wondering, "isn't this about Python and AppleScript?" We're getting there. Let's use these shortcuts to actually write a simple AppleScript with embedded Python.
Here is our first example of calling Python from AppleScript:
Example 1: Call Python Command from AppleScript
do shell script "python -c 'print \"Hello World\"'"
(Note: \ is used for double quote escape)
Click run and you will see the expected ouput at the bottom of the window. Not a very exciting example, I hate hello world, but tradition, tradition...
It does bring up one of the limitations of this method. Python was not designed to be run from the command line like Perl. The only way to "trick" Python into executing big, complicated one liners is to import a module that will execute code upon import.
This is generally a bad idea, but I can show you one fun example:
Example 2: Using Python import Command from AppleScript
do shell script "python -c 'import this'"
(This is the famous "Zen of Python" by Tim Peters. I will supress the output for the sake of the article, but you will see the "Zen of Python")
So remember, this is one option to execute complex commands via the command line with Python, but it's generally a bad idea as there are better ways to use Python to solve your problems.
You might be thinking that if you can all Python from AppleScript, you can probably call AppleScript from Python. You would be correct in thinking this is possible.
First make a sandbox if you don't have one:
mkdir ~/sandbox cd ~/sandbox
Example 3: Call AppleScript from Python with osascript
(You can cut and paste this into your favorite text editor. I like GVim quite a bit.)
#!/usr/bin/env python #sleepy-mac.py #makes my mac very sleepy import os cmd = """osascript -e 'tell app "Finder" to sleep'""" def stupidtrick(): os.system(cmd) stupidtrick()
Now let's make it executable:
chmod +x ~/sandbox/sleepy-mac.py
And we can call this from the command line:
This should have just put your Mac to sleep. Pretty cool, and it can actually be very useful. Let's alias this to your bash profile so whenever you feel like telling your Mac to sleep, you just type in a command. In
Now, whenever you feel the urge to put your Mac to sleep you can just type in sleepymac from the command line.
Here is another way to call AppleScript within Python code.
Example 4: Call AppleScript from Python with HEREDOC
import os #An example of the HEREDOC method cmd = """osascript<<END tell application "iTunes" play playlist "Party Shuffle" end tell END""" def play_iTunes(): os.system(cmd) play_iTunes()
Notice that with osascript you can triple quote osascript and embed a huge complicated AppleScript. This can be a pretty effective way to use AppleScript in Python as you could even throw several osascripts into a list or dictionary and call them throughout a Python script.
Let's make this example a little more cool though. What if you just bought an expensive, fully loaded, MacBook Pro, you have no more money in the bank, and your alarm clock breaks. Well, you can write a script for your daily alarm clock. Here's how:
Step 1: Open up Automater and select "Run Shell Script"
Step 2: Select the Python shell.
Step 3: Paste in code from example 4.
Figure 1: Running a shell script in Automator
Step 4: Press Run and test it out.
Step 5: Save it as an application called automater-itunes-pmix inside of your home directory sandbox.
That's all it takes to create a full application using Automator. Now let's be smart and think of how to we can reuse this application again for more than just an alarm clock. If you are thinking, "Let's make an alias to this in .profile," you're right!
I created another section just for automator applications:
### Automator-commands alias pmix='open ~/sandbox/itunes-itunes-pmix.app/'
Figure 2: bash Profile
Now if you type this in a new shell (remember every change to .profile requires a new shell to see the change):
pmix alias pmix='open ~/sandbox/itunes-itunes-pmix.app/'
your Mac will automatically launch iTunes and play a party mix. Now we're talking...that is sweet!
Step 6: Open up System Preferences-Energy Saver, and select the Schedule button. You will see a startup or wake at dialog. Select the time you want to wake up.
In order for your machine to act as an alarm clock you must do two other things.
Step 7: Turn on Autologin for you account. Go to System Preferences>Accounts>your username>login options.
Figure 3: Automatic Login Enabled
Step 8: Create a login item for your profile.
Figure 4: Login for Alarm Clock
Step 9: Test it! Shut down your computer and turn the power back on. You should have a party mix automatically play.
Step 10:; Test it again! Change the wake up/power on clock time to a few minutes in the future and turn your computer off.
Once that works, you should pat yourself on the back. You just built your own customized alarm clock and command party mix tool in one shot!
Another intersting way to interact with Python is to pass a variable from Python into AppleScript:
Type in a shell (remember you created the bash alias, if you're following along from home):
Example 5: Pass a Python value to an AppleScript variable
This one line Python script will find your hostname and pass it to AppleScript, which will then create a pop-up dialog box with your hostname. Paste inside of the Script Editor and run:
set hostname to (do shell script "python -c 'from socket import gethostname; print gethostname()'") display dialog "Your hostname is: " & hostname
Note: I borrowed this one liner from the python wiki.
So we have some fun, useable techniques, but I think in some cases there is a better way. It is time to introduce appscript.
Appscript is a Python bridge to AppleScript. It translates the functionality of AppleScript into the Python language. Basically, it makes AppleScript Pythonic, by allowing it to execute as Python code and eliminating much of the verbosity of the language. Appscript, in turn, allows you interact with a higher level API to the Apple User Interface that would be possible from the python standard library. Finally, appscript is a viable alternative to AppleScript.
You can download appscript from http://appscript.sourceforge.net/
To use appscript you need to download appscript, HTMLDictionary, and ASTranslate. Appscript is the actual bridge from Python to AppleScript. HTMLDictionary formats AppleScript dictionaries to appscript documentation for that object which is quite handy for reference! ASTranslate will try to translate AppleScript code into an appscript version. The good news is that is mostly works.
Below is an example of an appscript I wrote:
Example 6: Fully scripting a third-arty application with appscript
#!/usr/bin/env pythonw #Automates Diskwarrior Application through appscript from appscript import * import time #A function to fully automate Diskwarrior Application def diskwarrior(): t0 = time.time() #Tells Diskwarrior to start with a timeout of 3600 sec. app(u'/Applications/DiskWarrior.app').activate(timeout=3600) #Tells diskwarrior to rebuild disk. app(u'/Applications/DiskWarrior.app').disk['main'].rebuild(replacing=k.yes_, timeout=3600) #Tells Diskwarrior to quit app(u'/Applications/DiskWarrior.app').quit(timeout=3600) print "It took this many seconds to run Diskwarrior on your hard drive: \n" print time.time()-t0 diskwarrior()
Example 7: AppleScript code comparison of DiskWarrior script
with timeout of 3600 seconds tell application "DiskWarrior" activate rebuild disk "main" replacing yes end tell tell application "DiskWarrior" quit end tell end timeout
If you don't have IPython installed then you should do so now. You can download the source from http://ipython.scipy.org/moin/Download. Or you can do like I do and use easy_install, download the easy_install script from http://peak.telecommunity.com/DevCenter/EasyInstall
Then just type:
And from a shell type:
Now you are in IPython. At the IPython prompt, enter:
from appscript import *
Now you are ready to experiment with appscript using IPython. Let's start a slideshow:
We just launched a slideshow with one line of code. Touch a key on keyboard to come back to IPython.
That was fun. Now let's quit iPhoto. I am bored of seeing my vacation pics for the 1,200th time.
Poof! iPhoto is gone. Hmmm...what else can we play with? I always wonder what day of the week I was born on. I bet iCal can show me:
import datetime app(u'/Applications/iCal.app').view_calendar(at=datetime.datetime(1975, 5, 21, 0, 0))
So I was born on a Wednesday in 1975.
AppleScript can be clumsy and I think appscript is a little better, but the best approach to solve problems may be to combine appscript or AppleScript within your Python scripts. Please watch out for AppleScript event timeouts, as they can kill a script you thought would work.
In addition, since you need to deal with AppleScript inside of Python, special thought needs to go into how you write programs, as they won't behave as you would expect regular Python code to behave, due to the nature of Apple events.
We made some fun toys using AppleScript, appscript, and Python. We now have a way to open and close applications from the shell by typing in a three character alias. We created a sneaky, sleepymac command-line tool. And we made a full-fledged alarm clock application using several of the techniques we learned. Finally, we got into IPython and appscript to really mix it up.
Python is very powerful and robust, so only use appscript or AppleScript when you have to. When you write AppleScript code, think of how to make it generic enough that you can reuse it and call if from a bash alias.
IPython is really fun to play with and very powerful. IPython and appscript are a good combination. I hope this article has given you some good ideas. Now go automate things!
Here is your final exam. Download PagePacker and use appscript to automate the printing of several .png files onto one page. I will post one example of how to do so later on my blog.
Noah Gift is the co-author of Python For Unix and Linux by O'Reilly. He is an author, speaker, consultant, and community leader, writing for publications such as IBM Developerworks, Red Hat Magazine, O'Reilly, and MacTech, and Manning.
Return to MacDevCenter.com.
Copyright © 2009 O'Reilly Media, Inc.