AppleScript for Python Programmers (Comparison Chart)

I'm a Python programmer who switched to Mac OS X. Being nerd and needing to automate common tasks, the learning of the AppleScript language was unavoidable. To speed up the process I've took some notes, comparing the new commands to Python statements. The result is this document.

As the name says, it's intended for Python programmers. But if you're an applescripter interested in Python you may also learn a lot.

Python AppleScript
indexes start with 0 indexes start with 1
string comparison considers case string comparison ignores case
# comments -- comments
command # half-line comment command -- half-line comment
"""
    multiline comment block (sort of)
"""
(*
    multiline comment block
*)
a = 5 set a to 5
a = "foo" set a to "foo"
print "Hello World" display dialog "Hello World"
syslog.syslog(msg)
or
print >>sys.stderr, msg
log(msg)
print "\a" beep
say "Hello World"
Data types
type("foo").__name__ class of "foo"
None missing value
True, False true, false
2 2
"foo"
or
'foo'
"foo"
"""foo
bar"""
"foo
bar"
[ 1, 2, 3 ] { 1, 2, 3 }
( 1, 2, 3 )
{ "foo": "bar" } { foo: "bar" }
str(5) 5 as text
int("5") "5" as integer
float(5) 5 as real
float("5") "5" as real
list("foo") characters of "foo"
"".join([ "f","o","o" ]) { "f","o","o" } as text
"".join([str(x) for x in [ 1, 2, 3 ]]) { 1, 2, 3 } as text
String
S = "" set S to ""
S = "foo" set S to "foo"
len(S) length of S
or
count S
S[2] item 3 of S
S[len(S)/2] middle item of S
S[random.randint(0, len(S)-1)] some item of S
S[2:-2] items 3 thru -3 of S as text
S + "foo" S & "foo"
S.index("z")
or
S.find("z")
offset of "z" in S
S.startswith("z") S starts with "z"
S.endswith("z") S ends with "z"
S.count("z") User function countSubstring()
S.split() words in S
S.split()[2] word 2 of S
S.split(":") set AppleScript's text item delimiters to ":"
text items of S
set AppleScript's text item delimiters to ""
":".join(LIST) set AppleScript's text item delimiters to ":"
LIST as text
set AppleScript's text item delimiters to ""
S.lstrip() User function lstripString()
S.rstrip() User function rstripString()
S.strip() User function stripString()
S.lower() User function lowerString()
S.upper() User function upperString()
S.capitalize() User function capitalizeString()
S.replace() User function replaceString()
"z" in S "z" is in S
\\ \" \t \n \r \\ \" \t \r space tab return
S = "foo\nbar" set S to "foo" & return & "bar"
S = """foo "bar" baz""" set S to "foo \"bar\" baz"
List
L = [] set L to {}
L = [ 77, "foo", True ] set L to { 77, "foo", true }
L = [ 1, [ 2, [ 3 ]]] set L to { 1, { 2, { 3 }}}
len(L) length of L
or
count L
[x for x in L if isinstance(x, int)] integers in L
[x for x in L if isinstance(x, str)] strings in L
L[2] item 3 of L
L[2][2] item 3 of item 3 of L
L[len(L)/2] middle item of L
L[random.randint(0, len(L)-1)] some item of L
newlist = L[:] set newlist to every item of L
or
copy L to newlist
L[2:-2] items 3 thru -3 of L
L + [ 1, 2 ]
or
L.extend([ 1, 2 ])
L & { 1, 2 }
L.append("foo") set the end of L to "foo"
or
copy "foo" to the end of L
L[2] = "foo" set item 3 of L to "foo"
del L[2] set L to items 1 thru 2 of L & items 4 thru -1 of L
L.index("foo") User function getListItemIndex()
L.count("foo") User function countListItem()
L.pop(0) first item of L
set L to rest of L
L.pop(0) ; L[:] rest of L
L.reverse() reverse of L
L.sort()
"foo" in L "foo" is in L
L[0] == "foo" L starts with "foo"
L[-1] == "foo" L ends with "foo"
Dictionary / Record
D = {} set D to {}
D = { "foo":"bar", "spam":"eggs" } set D to { foo:"bar", spam:"eggs" }
len(D) length of D
or
count D
D["foo"] foo of D
D["foo"] = "bar" set foo of D to "bar"
D + { "foo":"bar" }
or
D.update({ "foo":"bar" })
D & { foo:"bar" }
newdic = D.copy() copy D to newdic
del D["foo"]
D.keys()
D.values()
D.has_key()
D["foo"] == "bar" foo of D is "bar"
D.get("foo") == "bar" { foo:"bar" } is in D
Expressions
1 + 1 1 + 1
1 - 1 1 - 1
1 * 1 1 * 1
1 / 1 1 div 1
1.0 / 1.0 1 / 1
or
1 ÷ 1
1 % 1 1 mod 1
1 ** 1 1 ^ 1
(2 + 4) * 2 (2 + 4) * 2
1 == 1 1 = 1
or
1 is equal 1
1 != 1 1 ≠ 1
or
1 is not equal 1
1 > 1 1 > 1
or
1 is greater than 1
1 < 1 1 < 1
or
1 is less than 1
1 >= 1 1 >= 1
or
1 ≥ 1
or
1 isn't less than 1
1 <= 1 1 <= 1
or
1 ≤ 1
or
1 isn't greater than 1
1 is 1 1 is 1
1 is not 1 1 is not 1
1 is 1 or 2 is 2 1 is 1 or 2 is 2
1 is 1 and 2 is 2 1 is 1 and 2 is 2
(1 is 1) and (2 is 2) (1 is 1) and (2 is 2)
Conditionals
if VAR == 1: print "OK" if VAR = 1 then display dialog "OK"
if VAR == 1:
    print "OK"
if VAR = 1 then
    display dialog "OK"
end if
if VAR == 1:
    print "OK"
else:
    print "Error"
if VAR = 1 then
    display dialog "OK"
else
    display dialog "Error"
end if
if VAR < 10:
    print "Need more!"
elif VAR > 20:
    print "Too much!"
else:
    print "It's OK"
if VAR < 10 then
    display dialog "Need more!"
else if VAR > 20 then
    display dialog "Too much!"
else
    display dialog "It's OK"
end if
Loops
for i in LIST:
    print i
repeat with i in LIST
    display dialog i
end repeat
while 1:
    break
repeat
    exit repeat
end repeat
while 1:
    continue
while VAR is False:
    # do something
repeat while VAR is false
    -- do something
end repeat
while VAR is not False:
    # do something
repeat until VAR is false
    -- do something
end repeat
for i in range(10):
    # do something
repeat 10 times
    -- do something
end repeat
for i in range(1, 10, 2):
    # do something
repeat with i from 1 to 10 by 2
    -- do something
end repeat
Functions
def add_numbers(a, b):
    return a + b
on add_numbers(a, b)
    return a + b
end add_numbers
five = add_numbers(2, 3) set five to add_numbers(2, 3)
def optional(a=0, b=""):
Class / Script
class FooBar(Father):
    VAR = 0
    def setValue(self, val):
        self.VAR = val
script FooBar
    property parent : Father
    property VAR : 0
    on setValue(val)
        set my VAR to val
    end setValue
end script
myFoo = FooBar()
myFoo.setValue(5)
myData = myFoo.VAR
copy FooBar to myFoo
tell myFoo to setValue(5)
set myData to VAR of myFoo
File Read/Write
F = open("/tmp/foo")
TXT = F.read()
F.close()
set F to "/tmp/foo" as POSIX file
set TXT to read F
F = open("/tmp/foo")
LINES = F.readlines()
F.close()
set F to "/tmp/foo" as POSIX file
set LINES to read F using delimiter (ASCII character 10)
F = open("/tmp/foo", "w")
F.write("Hello!\n")
F.close()
set F to "/tmp/foo" as POSIX file
set F to open for access F with write permission
write "Hello!" & return to F
close access F
Path
(requires tell app "Finder")
os.path.isfile(F) file F exists
os.path.isdir(F) folder F exists
os.path.abspath(F) file F as text
os.path.dirname(F) folder of file F as text
os.path.basename(F) name of file F
F.split(os.path.extsep)[-1] name extension of file F
os.stat(F)[6] size of file F
pwd.getpwuid(os.stat(F)[4])[0] owner of file F
grp.getgrgid(os.stat(F)[5])[0] group of file F
open(newfile, "w").write(open(F).read()) duplicate file F to file newfile
os.rename(F, newfile) set name of file F to newfile
os.unlink(F) delete file F
Date & Time
time.asctime() current date as string
T = time.localtime() set T to current date
T = time.strptime(
        "Jan 31, 2005 17:59",
        "%b %d, %Y %H:%M" )
set T to date "Jan 31, 2005 17:59"
orig = time.mktime(time.strptime(
        "Jan 31, 2005 17:59",
        "%b %d, %Y %H:%M" ))
plus = time.mktime(time.strptime(
        "4 3 2 1970",
        "%d %H %M %Y" ))
T = time.localtime(orig+plus)
set orig to date "Jan 31, 2005 17:59"
set plus to 4 * days + 3 * hours + 2 * minutes
set T to orig + plus
time.strftime("%A", T) weekday of T
time.strftime("%d", T) day of T
time.strftime("%B", T) month of T
time.strftime("%m", T) month of T as integer
time.strftime("%Y", T) year of T
time.strftime("%X", T) time string of T
time.strftime("%x", T) date string of T
fmt = "%H*3600 + %M*60 + %S"
eval(time.strftime(fmt, T))
time of T -- Seconds since midnight
Other
try:
    # do something
except:
    # do something
try
    -- do something
on error
    -- do something
end try
try:
    # do something
except error, errmsg:
    # do something
try
    -- do something
on error errMsg number errNum
    -- do something
end try
os.system("ls /etc/ | head -n 1") do shell script "ls /etc/ | head -n 1"
global VAR global VAR
eval("4 + 4") run script "4 + 4"
chr(64) ASCII character 64
ord("@") ASCII number "@"
time.sleep(10) delay 10
random.randint(5, 10) random number from 5 to 11
foo, bar = 1, 2 set {foo, bar} to {1, 2}
D = {"foo":1, "bar":2 }
var1, var2 = D["foo"], D["bar"]
set {var1, var2} to {foo, bar} of {foo:1, bar:2}
[ 0, 1, { "foo":"bar" }][2]["foo"][0] character 1 of foo of item 3 of {0, 1, {foo:"bar"}}
import foo
foo.do_something()
set foo to load script "foo.scpt"
tell foo to do_something()
"a" == "A" # returns False "a" = "A" -- returns true
considering case
    "a" = "A" -- returns false
end considering
"1 2 3 4" == "1234" # returns False "1 2 3 4" = "1234" -- returns false
ignoring white space
    "1 2 3 4" = "1234" -- returns true
end ignoring
sys.exit() tell me to quit

Handy functions

The AppleScript language is very limited on data handling. The programmer must build his own tools (functions) to have Python-like functionality to manage strings and lists.

countSubstring()

-- Counts how many times a string appears in a text
-- Note: Its splits the text by the substring and count the items
--
on countSubstring(theText, theSubstring)
   set AppleScript's text item delimiters to theSubstring
   set counter to (count of every text item of theText) - 1
   set AppleScript's text item delimiters to ""
   return counter
end countSubstring

lstripString()

-- Trims the provided string from the text's beginning
--
on lstripString(theText, trimString)
   set x to count trimString
   try
      repeat while theText begins with the trimString
         set theText to characters (x + 1) thru -1 of theText as text
      end repeat
   on error
      return ""
   end try
   return theText
end lstripString

rstripString()

-- Trims the provided string from the text's ending
--
on rstripString(theText, trimString)
   set x to count trimString
   try
      repeat while theText ends with the trimString
         set theText to characters 1 thru -(x + 1) of theText as text
      end repeat
   on error
      return ""
   end try
   return theText
end rstripString

stripString()

-- Trims the provided string from the text's boundaries
-- Note: Requires the lstripString and rstripString functions
--
on stripString(theText, trimString)
   set theText to lstripString(theText, trimString)
   set theText to rstripString(theText, trimString)
   return theText
end stripString

lowerString() / upperString() / capitalizeString()

-- Translate characters of a text
-- Note: Pass the From and To tables as strings (same lenght!)
--
on translateChars(theText, fromChars, toChars)
   set the newText to ""
   if (count fromChars) is not equal to (count toChars) then
      error "translateChars: From/To strings have different lenght"
   end if
   repeat with char in theText
      set newChar to char
      set x to offset of char in the fromChars
      if x is not 0 then set newChar to character x of the toChars
      set newText to newText & newChar
   end repeat
   return the newText
end translateChars


-- Convert a text case to lower characters
-- Note: Requires the translateChars function
--
on lowerString(theText)
   set upper to "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
   set lower to "abcdefghijklmnopqrstuvwxyz"
   return translateChars(theText, upper, lower)
end lowerString


-- Convert a text case to upper characters
-- Note: Requires the translateChars function
--
on upperString(theText)
   set lower to "abcdefghijklmnopqrstuvwxyz"
   set upper to "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
   return translateChars(theText, lower, upper)
end upperString


-- Capitalize a text, returning only the first letter uppercased
-- Note: Requires translateChars, lowerString and upperString
--
on capitalizeString(theText)
   set firstChar to upperString(first character of theText)
   set otherChars to lowerString(characters 2 thru -1 of theText)
   return firstChar & otherChars
end capitalizeString

replaceString()

-- Replace all occurences of one string for another in a text
-- The trick here is to change the internal delimiter,
-- spliting and joining the text
--
on replaceString(theText, oldString, newString)
   set AppleScript's text item delimiters to oldString
   set tempList to every text item of theText
   set AppleScript's text item delimiters to newString
   set theText to the tempList as string
   set AppleScript's text item delimiters to ""
   return theText
end replaceString

getListItemIndex()

-- Returns the integer index of a list item (zero if not found)
--
on getListItemIndex(theList, theItem)
   repeat with i from 1 to count of theList
      if item i of theList is theItem then return i
   end repeat
   return 0
end getListItemIndex

countListItem()

-- Returns the total count of a specific item in a list
--
on countListItem(theList, theItem)
   set counter to 0
   repeat with i from 1 to count of theList
      if item i of theList is equal to theItem then
         set counter to counter + 1
      end if
   end repeat
   return counter
end countListItem

Thank You Very Much!

This document was reviewed and got valuable contributions from:

— EOF —
GitHub