Programmish
Python and Apple AddressBook

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'}
7 Responses to Python and Apple AddressBook
You can leave a response, or trackback from your own site.
  1. [...] 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 – [...]

  2. Randolph Fritz says:

    Thanks! This looks very useful!

  3. Joe says:

    Hi,

    i would like to reuse this for my Adressbook-export. Can you give this code a Opensource-licence? That would be great.
    Joe

  4. patrick says:

    Feel free to use, modify, or distribute this example, as for this specific posting the code is hereby released into the Public Domain.

  5. Joe says:

    :-) thx a lot

  6. [...] 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 [...]

  7. Prabhu says:

    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

Leave a Reply