TweetFollow Us on Twitter

Mac in the Shell: Accessing AddressBook with PyObjC

Volume Number: 25
Issue Number: 08
Column Tag: Mac in the Shell

Mac in the Shell: Accessing AddressBook with PyObjC

Using a specific Cocoa API from Python

by Edward Marczak

Introduction

Last month, we covered some basic text parsing using Python. I personally love the topic, as it's really applicable across a wide range of problems. But it was also fairly generic: that code will run on any platform with Python installed. Better yet: we can combine the text processing of standard Python with the OS X-specific PyObj-C libraries that let us tie into Cocoa APIs. This month, we'll look at AddressBook.

Accessing Address Book

First thing to remember: PyObj-C support is only built-in to OS 10.5 and above and with Python v2.5 and greater. If you're on a 10.4 system, this will not work out of the box. You'll need to get pyobjc support installed for 10.4 for yourself (further information and instructions can be found at http://pyobjc.sourceforge.net/downloads.html). This works just fine under 10.5 and, ummmmm... a certain future operating system.

The AddressBook framework in OS X is well documented by Apple. The developer site has plenty of information. A good starting point can be found at http://developer.apple.com/documentation/userexperience/Conceptual/AddressBook/AddressBook.html. All of the code presented in this article was written based on this documentation.

The code we'll look at this month is a small snippet of code that I actually use. As Executive Editor for MacTech, I send out a 'nag' message each month to authors that due dates are coming up. (Yes, I'm looking to automate this, but honestly like the personal touch that sending it out manually provides). I keep a group in AddressBook with the authors that have requested that I send them a reminder. Sometimes I use Mail.app, but sometimes I'm using a web-based mail interface that does not contain my contacts. Thanks to the magic of MobileMe, I tend to have my AddressBook no matter which machine I'm logged into. So then, what I need each month is a list of each address in the group I call "MacTech Editorial".

Like last month, I marvel at how little code we need to accomplish this. Here's the entire listing:

Listing 1 – MTDumpABGroup.py

#!/usr/bin/python2.5
import sys
from AddressBook import *
def GetAllABGroups(abref):
  groupdict = {}
  abgroups = abref.groups()
  for abgroup in abgroups:
    groupdict[abgroup.name()] = [abgroup.uniqueId()]
  return groupdict
def GetAllABListEmails(abref, abgroupid):
  address_dict = {}
  abgroup = abref.recordForUniqueId_(abgroupid)
  card = abgroup.members()
  for entity in card:
    emails = entity.valueForProperty_(kABEmailProperty)
    if emails is not None:
      address_dict[entity.uniqueId()] = emails.valueAtIndex_(0)
  return address_dict
def main():
  ab = ABAddressBook.sharedAddressBook()
  groups = GetAllABGroups(ab)
  groupid = None
  for group in groups:
    if group == "MacTech Editorial":
      groupid = groups[group][0]
      break
  if groupid is None:
    print "Group not found"
    sys.exit(1)
  addresses = GetAllABListEmails(ab, groupid)
  for i in addresses:
    print addresses[i] + ",",
if __name__ == '__main__':
  main()

Analyzing the code

Despite the brevity of the code involved, there's still some explaining to do. I'll follow the code as it executes, rather than go line-by-line from the top to the bottom. The only exceptions to that is the import statement at the top of the file (which does execute first). We need to import the AddressBook library for any of this to work, which is what make our job easy: Apple has already done the grunt work and we just need to exploit it.

The first statement to execute is the second to last: "if __name__..." This is the standard Python-ism that we've discussed in the past. This allows another Python app to import our program without running it. If we are running stand-alone, though, main() gets called.

First, in main(), we need a reference to the system's shared AddressBook. We instantiate a new copy of the ABAddressBook class and assign it to ab. Next, that reference gets passed into our GetGroups() function.

GetGroups() is more of a convenience function than anything, as we're really only going to use it once, but it's a decent illustration on pulling out all groups listed in the current user's address book. How do we obtain the list of groups in the address book? We ask! The groups() method returns an array of each group. In turn, each group has properties that can be obtained. In our case, we only care about the name, because as humans, that how we tend to identify things, and the group's unique ID, as we'll need to use that to request the members of the group. This function simply defines a dictionary that we fill with the requisite information. Once filled, we return that value from the function.

Back in main(), we simply loop though the groups that were returned, by name, and look for the one we're interested in. In our case, as mentioned, we're after the group named "MacTech Editorial". Once we find what we're looking for, we break out of the loop.

You'll notice that we set groupid to None prior to entering the loop. This just makes it easier for us to test if groupid has a value or not. Since it only gets set if we found the group we're looking for we use that in an if conditional:

if groupid is None:
    print "Group not found"
    sys.exit(1)

If groupid is still None when we exit the loop, we haven't found the group we're looking for and print a message and then exit with an exit code. It's useful to set a proper exit code so you can test for this in a shell script.

As an aside, another way to accomplish this would be to use a try block, but I found that a little more cumbersome for this program. Using a try block would eliminate the need to set groupid to None prior to entering the loop:

try:
  groupid
except NameError:
  print "Group not found"
  sys.exit(1)

For this particular endeavor, either method will suffice, however, I've gone with the "define as None" method above.

Once we've found the unique ID for the group we want to dump, we pass that off to GetAllListEmails(). First, we define a dictionary, addressdict, that will hold the addresses. Next, retrieve the address book group record that matches the given unique ID with recordForUniqueId. From there, we can gather all of the members of the group. How? We ask! The AddressBook Group class reference documentation lists the member method. The remainder of this function relies on the results returned from this call. A simple Python for loop allows us access to each person retrieved. Now, an AddressBook card may contain an entry that does not have an e-mail address, which is all we're really interested in. So, we retrieve all e-mail addresses associated with the card with the line:

emails = entity.valueForProperty_(kABEmailProperty)

This returns a multi-value of e-mail addresses attached to the card. For the purposes here, I'm only interested in one, and I'll take the first that's returned. But first, we need to see if any addresses were returned at all. The if conditional checks for addresses, and if some were returned, we'll take the first and add it to our dictionary:

address_dict[entity.uniqueId()] = emails.valueAtIndex_(0)

Once we've looped through all people returned, we have the dictionary we need. Time to return that back to the calling function.

Delivering the Results

Now for the easy part: printing out the results. We've covered looping through a Python dictionary plenty of times before, and that's all that's happening here:

for i in addresses:
  print addresses[i] + ",",

So, time to run the application! Naturally, you'll need to substitute an appropriate group name on line 31 (if group == "MacTech Editorial":) for a group that you have in your address book. Don't forget to chmod it as executable (chmod 770 MTDumpABGroup.py), and then go for it:

./MTDumpABGroup.py

bob@example.com, scott@example.net, bruce@mactech.com, wendel@example.org, alice@example.co.uk,

Thanks to one of OS X's many integrations between the shell and GUI, we can make our lives easier by piping the output into pbcopy:

./MTDumpABGroup | pbcopy

...and then just paste it into the To: field in your e-mail application (if it does indeed accept the address-comma-address format. I'm hard pressed to think of an e-mail client that doesn't, but I won't say one doesn't exist). You may need to drop the trailing comma, but since I've been using Gmail which just ignores the trailing comma, I just past the whole thing in.

Conclusion

In just 43 lines, including the stylistic spacing, we have a script that will dump all of the e-mail addresses associated with a particular group in Address Book. This example should illustrate several things: first, it's not difficult to get Cocoa via Python. It's well documented. Second, you don't have to spend a lifetime trying to find a solution. My itch (getting a list of e-mail addresses from a particular group) was easily scratched.

Media of the month: My reading list has become incredibly long...so much to read! But I gravitated toward a particular book in my pile (by the way – I really do prefer books. As in the real, physical variety. Perhaps it's just tactile, but, no Kindle for me yet). "Brewing Up a Business: Adventures in Entrepreneurship" by Sam Calagione seemed to be beckoning. Now, this may be the first book that I'm recommending before I actually finish it. I'm about three-fifths of the way through. It's so far really enjoyable. It's targeted at people starting their own business, so, for the consultants and potential consultants out there, it seems like something that should be on your reading list.

Until next month, keep practicing Python!

References

Address Book Class Reference: http://developer.apple.com/documentation/userexperience/Reference/AddressBook/Classes/ABAddressBook_Class/Reference/Reference.html#//apple_ref/occ/instm/ABAddressBook/people

Address Book Group Reference: http://developer.apple.com/documentation/UserExperience/Reference/AddressBook/Classes/ABGroup_Class/Reference/Reference.html

Address Book Person Reference: http://developer.apple.com/documentation/UserExperience/Reference/AddressBook/C/ABPersonRef/Reference/reference.html


Ed Marczak is the Executive Editor of MacTech Magazine. He has written for MacTech since 2004.

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

iDefrag 5.0.0 - Disk defragmentation and...
iDefrag helps defragment and optimize your disk for improved performance. Features include: Supports HFS and HFS+ (Mac OS Extended). Supports case sensitive and journaled filesystems. Supports... Read more
PCalc 4.2 - Full-featured scientific cal...
PCalc is a full-featured, scriptable scientific calculator with support for hexadecimal, octal, and binary calculations, as well as an RPN mode, programmable functions, and an extensive set of unit... Read more
FileZilla 3.10.2 - Fast and reliable FTP...
FileZilla (ported from Windows) is a fast and reliable FTP client and server with lots of useful features and an intuitive interface. Version 3.10.2: Note: Now requires a 64-bit Intel processor.... Read more
The Hit List 1.1.11 - Advanced reminder...
The Hit List manages the daily chaos of your modern life. It's easy to learn - it's as easy as making lists. And it's powerful enough to let you plan, then forget, then act when the time is right.... Read more
Bartender 1.2.32 - Organize your menu ba...
Bartender lets you organize your menu bar apps. Features: Lets you tidy your menu bar apps how you want. See your menu bar apps when you want. Hide the apps you need to run, but do not need to... Read more
ClamXav 2.7.5 - Free virus checker, base...
ClamXav is a free virus checker for OS X. It uses the tried, tested, and very popular ClamAV open source antivirus engine as a back end. I hope you like and use ClamXav a lot and that it helps keep... Read more
xScope 4.1.2 - Onscreen graphic measurem...
xScope is powerful set of tools that are ideal for measuring, inspecting, and testing on-screen graphics and layouts. Its tools float above your desktop windows and can be accessed via a toolbar,... Read more
MacFamilyTree 7.3.3 - Create and explore...
MacFamilyTree gives genealogy a facelift: it's modern, interactive, incredibly fast, and easy to use. We're convinced that generations of chroniclers would have loved to trade in their genealogy... Read more
Skype 7.5.0.738 - Voice-over-internet ph...
Skype allows you to talk to friends, family and co-workers across the Internet without the inconvenience of long distance telephone charges. Using peer-to-peer data transmission technology, Skype... Read more
PushPal 3.0 - Mirror Android notificatio...
PushPal is a client for Pushbullet, which automatically shows you all of your phone's notifications right on your computer. This means you can see who's calling or read text messages even if your... Read more

Dungeon Hunter 5 Coming on March 12
Gameloft has excitedly announced that Dungeon Hunter 5 is on its way! Once again, you will adventure across the land of Valenthia exploring dungeons and fighting monsters. The game will have a new asynchronous multiplayer mode called Strongholds... | Read more »
It Came From Canada: Jurojin: Immortal N...
At this point it’s pretty safe to say that no MOBA is going to dethrone Dota 2 and League of Legends anytime soon. After all, if Batman can’t do it, nobody can. However, with a genre as popular and profitable as this one, there’s still room for... | Read more »
Tiny Farm – Animals, Tractors and Advent...
Tiny Farm – Animals, Tractors and Adventures! Review By Amy Solomon on March 3rd, 2015 Our Rating: :: LIVELY LANDSCAPESUniversal App - Designed for iPhone and iPad Tiny Farm – Animals, Tractors and Adventures! includes farm-related... | Read more »
This Week at 148Apps: February 23-27, 20...
Final February Fun at 148Apps   How do you know what apps are worth your time and money? Just look to the review team at 148Apps. We sort through the chaos and find the apps you’re looking for. The ones we love become Editor’s Choice, standing out... | Read more »
GDC 2015 – Does Not Commute is Definitel...
GDC 2015 – Does Not Commute is Definitely a Game You Should Keep an Eye on Posted by Rob Rich on March 2nd, 2015 [ permalink ] We were teased about Mediocre Games’ (Smash Hit, | Read more »
F84 Games & POW! Announce Stan Lee V...
F84 Games has announced that it is working with legendary comic creator Stan Lee and POW! Entertainment to produce Stan Lee’s Hero Command. The game will be a action adventure of heroic proportions. | Read more »
Setlyst Keeps Your Set Straight So You C...
Setlyst Keeps Your Set Straight So You Can Focus On Rocking Out. Posted by Jessica Fisher on March 2nd, 2015 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
Space is Vast, So Space Agency Has a Vas...
Space is Vast, So Space Agency Has a Vast New Update! Posted by Jessica Fisher on March 2nd, 2015 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
Size DOES Matter Review
Size DOES Matter Review By Campbell Bird on March 2nd, 2015 Our Rating: :: HARD TO BEATUniversal App - Designed for iPhone and iPad This rhythm game has a unique control scheme and performance system that make it feel like a true... | Read more »
The first ever action 3D card battler Al...
On the other hand, you probably haven’t played an action 3D card battler – until now. Step forward, All Star Legion. All Star Legion is a 3D QTE-based action RPG card battler, but fear not – the game itself isn’t as convoluted as its description.... | Read more »

Price Scanner via MacPrices.net

Another Tranche Of IBM MobileFirst For iOS Ap...
IBM has announced the next expansion phase for  its IBM MobileFirst for iOS portfolio, with a troika of new apps to address key priorities for the Banking and Financial Services, Airline and Retail... Read more
Sale! 15-inch Retina MacBook Pros for up to $...
B&H Photo has the new 2014 15″ Retina MacBook Pros on sale for up to $250 off MSRP for a limited time. Shipping is free, and B&H charges NY sales tax only: - 15″ 2.2GHz Retina MacBook Pro: $... Read more
WaterField Designs Introduces the Minimalist...
With Apple Pay gaining popularity, Android Pay coming in May 2015, and loyalty cards and receipts that can be accessed from smartphones, San Francisco’s WaterField Designs observes that it may be... Read more
Sale! 15-inch 2.2GHz Retina MacBook Pro for $...
 Best Buy has the 15″ 2.2GHz Retina MacBook Pro on sale for $1774.99 $1799.99, or $225 off MSRP. Choose free home shipping or free local store pickup (if available). Price valid for online orders... Read more
13-inch 2.5GHz MacBook Pro (refurbished) avai...
The Apple Store has Apple Certified Refurbished 13″ 2.5GHz MacBook Pros available for $170 off the cost of new models. Apple’s one-year warranty is standard, and shipping is free: - 13″ 2.5GHz... Read more
13-inch 2.5GHz MacBook Pro on sale for $100 o...
B&H Photo has the 13″ 2.5GHz MacBook Pro on sale for $999.99 including free shipping plus NY sales tax only. Their price is $100 off MSRP. Read more
27-inch 3.5GHz 5K iMac in stock today and on...
 B&H Photo has the 27″ 3.5GHz 5K iMac in stock today and on sale for $2299 including free shipping plus NY sales tax only. Their price is $200 off MSRP, and it’s the lowest price available for... Read more
Apple Launches Free Web-Based Pages and Other...
Apple’s new Web-only access to iWork productivity apps is a free level of iCloud service available to anyone, including people who don’t own or use Apple devices. The service includes access to Apple... Read more
Survey Reveals Solid State Disk (SSD) Technol...
In a recent SSD technology use survey, Kroll Ontrack, a firm specializing in data recovery, found that while nearly 90 percent of respondents leverage the performance and reliability benefits of SSD... Read more
Save up to $600 with Apple refurbished Mac Pr...
The Apple Store is offering Apple Certified Refurbished Mac Pros for up to $600 off the cost of new models. An Apple one-year warranty is included with each Mac Pro, and shipping is free. The... Read more

Jobs Board

*Apple* Solutions Consultant - Retail Sales...
**Job Summary** As an Apple Solutions Consultant (ASC) you are the link between our customers and our products. Your role is to drive the Apple business in a retail Read more
*Apple* Pay Automation Engineer - iOS System...
**Job Summary** At Apple , great ideas have a way of becoming great products, services, and customer experiences very quickly. Bring passion and dedication to your job Read more
Sr. Technical Services Consultant, *Apple*...
**Job Summary** Apple Professional Services (APS) has an opening for a senior technical position that contributes to Apple 's efforts for strategic and transactional Read more
Event Director, *Apple* Retail Marketing -...
…This senior level position is responsible for leading and imagining the Apple Retail Team's global engagement strategy and team. Delivering an overarching brand Read more
*Apple* Pay - Site Reliability Engineer - Ap...
**Job Summary** Imagine what you could do here. At Apple , great ideas have a way of becoming great products, services, and customer experiences very quickly. Bring Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.