Scripting the Mac with Python

What is AppleScript?

You don't have to use AppleScript to use AppleScript!

Sending AppleEvents from Python

Emails from Address Book


from appscript import *

ab = app('Address Book.app')
people = ab.people.filter(its.emails != [])
for person in people.get():
    emails = ', '.join(person.emails.value.get())
    print "%s: %s" % (person.name.get(), emails)

Running appscripts

$ python print-ab-emails.py

Traceback (most recent call last):
  [...]
RuntimeError: Can't send Apple events: 
              no access to Window Manager.

$ pythonw print-ab-emails.py

Jacob Kaplan-Moss: jacob@lawrence.com
David Ryan: dryan@ljworld.com, dryan@mac.com
Adrian Holovaty: aholovaty@ljworld.com
[...]

Getting help

help() example

...

Translating AppleScript to appscript

tell application "Finder"
    get free space of startup disk
end tell
app('Finder.app').startup_disk.free_space.get()

Translating AppleScript to appscript

tell application "Address Book"
    get name of every person whose ¬
        last name starts with "H" or ¬
        first name ends with "b"
end tell
ab = app('Address Book.app')
people = ab.people.filter(
            con.OR(
                its.first_name.startswith('H'), 
                its.last_name.endswith('b')
            )
         )
print [person.name for people in people.get()]

Now for something difficult

Building a OmniGraffle site map


def build_site_map(uri):
    og = appscript.app('OmniGraffle.app')
    og.make(new=appscript.k.document)
    doc = og.windows.first.get()
    elems = {}
    for (src, dest) in get_link_map(uri):
        if not elems.has_key(src):
            elems[src] = create_node(doc, src)
        if not elems.has_key(dest):
            elems[dest] = create_node(doc, dest)
            
        connect_nodes(og, elems[src], elems[dest])
        
    og.layout(doc.document.pages.first)
    

Building a OmniGraffle site map


def create_node(document, link):
    k = appscript.k
    properties = {
        k.url: link,
        k.text: urlparse.urlsplit(link)[2],
        k.autosizing: k.full,
        k.draws_shadow: False,
    }
    return document.make(new=appscript.k.shape, 
                         at=document.graphics.start, 
                         with_properties=properties)                                    

Building a OmniGraffle site map


def connect_nodes(app, n1, n2):
    k = appscript.k
    properties = {
        k.line_type : k.curved,
    }
    app.connect(n1, to=n2, 
                with_properties=properties)

Abracadabra!

(see full script)

Unscriptable Apps

Unscriptable Apps


from appscript import *

sys_prefs = app('System Preferences.app')
sys_prefs.activate()
sys_prefs.current_pane.set(sys_prefs.panes['com.apple.preferences.users'])

ui = app('System Events.app')
process = ui.processes['System Preferences']
tabs = windows['Accounts'].tab_groups[1]
tabs.radio_buttons[1].click()

print tabs.text_fields[1].value.get()

Appscript Tips

Questions?