pseudofish

powered by text files

python

Part 2 - Using Address Book and making an app

Having successfully created a simple Cocoa application using Python in Part 1, the next step is to integrate data from Apple’s Address Book (AB).

The PyObjC example of Address Book usage is a good place to start, and the Apple documentation includes any other information needed. I started with the example, played around a bit and then read the documentation mainly for the constants to get the fields I wanted.

The first step is to create a separate file to include the Address Book interaction. I put this into DateList.py. For a simple start, I’ve made the interaction a function that returns the data to the Delegate class. This is called dateFields(), and it creates a connection to the Address Book and loads the fields for it.

import AddressBook

def dateFields():
  book = AddressBook.ABAddressBook.sharedAddressBook()
  return bookFields(book)

bookFields generates the actual list using a list comprehension. validPerson filters the list to only include records which have the birthday field set.

def validPerson(person):
  return person.valueForProperty_(\
    AddressBook.kABBirthdayProperty) is not None

def bookFields(book):
  return [ personToFields(p) \
    for p in book.people() if validPerson(p) ]

I’m still in awe over how nicely the PyObjC does the translation behind the scenes. The native python list constructs loop effortlessly across the Objective C objects.

The next part in the story is to actually create the tuple with the person’s name and birthday. If you recall, this should look something like:

{'date': 1977-08-04 12:00:00 GMT, 'name': u'Geoff Wilson'}

I’ve hidden this away in the personToFields function, with two functions to get some details, as follows:

def personToFields(person):
  return {
    'date': getBirthday(person),
    'name': getPersonName(person)
    }

def getPersonName(person):
  return person.valueForProperty_(\
    AddressBook.kABFirstNameProperty\
      ) + ' ' \
        + person.valueForProperty_(\
          AddressBook.kABLastNameProperty)

def getBirthday(person):
  return person.valueForProperty_(\
    AddressBook.kABBirthdayProperty)

At this stage you should have enough code to be able to query your Address Book. Python allows you to add the equivalent of a main function to a source file. Similar to the Java usage, I’ve used this to write quick test code to my module. Better would be to write unit test cases, but this isn’t an example of TDD.

Add the following to your code:

if __name__ == '__main__':
  print dateFields()

And then run the result:

$ python DateList.py
[{'date': 2004-04-04 12:00:00 Australia/Melbourne, 'name': u'Test User'}]
$

Note: if you don’t have any records in Address Book, you won’t see any results.

The change to integrate this into the user interface is to update the delegate to request the data from the dateFields() function. You also need to add the appropriate import call:

from PyObjCTools import NibClassBuilder
from DateList import dateFields

NibClassBuilder.extractClasses('MainMenu')

class DateListDelegate(NibClassBuilder.AutoBaseClass):
  def items(self):
    return dateFields()

The magical bit is that there is no need to re-compile and no need to change the user interface. You should now see something like:

Birthday list

The source code for the sample application from this tutorial is available here.