Among various other tasks for a project this week I’ve been writing some Python classes to query Apple’s AddressBook database. OS X 10.5 ships with PyObjC, a Python to Objective-C bridge, preinstalled, which makes this kind of task fairly straight forward. Or, at least, it should. A few minutes of digging discovered that what few examples of working with Python and AddressBook were easy to find were incomplete, broken, or counter to the task I was trying to accomplish. Add to that a lack of any good documentation on the PyObjC methods, and it fell to experimenting and digging through Objective-C documentation.
What follows is a method for retrieving a list of People from the local AddressBook as a list of Python Dictionaries.
from AddressBook import *
import pprint
def addressBookToList():
"""
Read the current user's AddressBook database, converting each person
in the address book into a Dictionary of values. Some values (addresses,
phone numbers, email, etc) can have multiple values, in which case a
list of all of those values is stored. The result of this method is
a List of Dictionaries, with each person represented by a single record
in the list.
"""
# get the shared addressbook and the list of
# people from the book.
ab = ABAddressBook.sharedAddressBook()
people = ab.people()
peopleList = []
# convert the ABPerson to a hash
for person in people:
thisPerson = {}
props = person.allProperties()
for prop in props:
# skip some properties
if prop == "com.apple.ABPersonMeProperty":
continue
elif prop == "com.apple.ABImageData":
continue
# How we convert the value depends on the ObjC
# class used to represent it
val = person.valueForProperty_(prop)
if type(val) == objc.pyobjc_unicode:
# Unicode String
thisPerson[prop.lower()] = val
elif issubclass(val.__class__, NSDate):
# NSDate
thisPerson[prop.lower()] = val.description()
elif type(val) == ABMultiValueCoreDataWrapper:
# List -- convert each item in the list
# into the proper format
thisPerson[prop.lower()] = []
for valIndex in range(0, val.count()):
indexedValue = val.valueAtIndex_(valIndex)
if type(indexedValue) == objc.pyobjc_unicode:
# Unicode string
thisPerson[prop.lower()].append(indexedValue)
elif issubclass(indexedValue.__class__, NSDate):
# Date
thisPerson[prop.lower()].append(indexedValue.description())
elif type(indexedValue) == NSCFDictionary:
# NSDictionary -- convert to a Python Dictionary
propDict = {}
for propKey in indexedValue.keys():
propValue = indexedValue[propKey]
propDict[propKey.lower()] = propValue
thisPerson[prop.lower()].append(propDict)
peopleList.append(thisPerson)
return peopleList
So, given an entry in the AddressBook that looked like:

This method will have the following Dictionary in the list of returned People:
{ u'address': [ { u'city': u'Anytown',
u'country': u'USA',
u'countrycode': u'us',
u'state': u'NY',
u'street': u'123 Fake Street',
u'zip': u'10111'}],
u'aiminstant': [u'john_doe_aim'],
u'creation': u'2008-04-09 13:33:17 -0500',
u'email': [u'john@doe.com'],
u'first': u'John',
u'last': u'Doe',
u'modification': u'2008-04-09 13:33:17 -0500',
u'phone': [u'555-555-1212'],
u'uid': u'BBFAB17F-591A-4D3C-BE75-4FE5B25B984D:ABPerson'}
[...] Using pythons datetime classes it is pretty simple to accomplish almost anything concerning dates. This blog-entry was a great help and gave me the idea to use PyObjC – [...]
Thanks! This looks very useful!
Hi,
i would like to reuse this for my Adressbook-export. Can you give this code a Opensource-licence? That would be great.
Joe
Feel free to use, modify, or distribute this example, as for this specific posting the code is hereby released into the Public Domain.
[...] hier das Coding / Thx a lot to programmish ); for releasing his snippet under public domain. from AddressBook import * import re from xml.dom.minidom import [...]
Nice post! I took this as base and have added couple of more extra api. Cleaned up certain copy-paste stuff. You can get the source code here – http://github.com/prabhu/macutils