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

BBEdit 11.6.6 - Powerful text and HTML e...
BBEdit is the leading professional HTML and text editor for the Mac. Specifically crafted in response to the needs of Web authors and software developers, this award-winning product provides a... Read more
Brackets 1.9.0 - Open Source Web design...
Brackets is an Open-Source editor for Web design and development built on top of Web technologies such as HTML, CSS, and JavaScript. The project was created and is maintained by Adobe, and is... Read more
Audio Hijack 3.3.4 - Record and enhance...
Audio Hijack (was Audio Hijack Pro) drastically changes the way you use audio on your computer, giving you the freedom to listen to audio when you want and how you want. Record and enhance any audio... Read more
Tunnelblick 3.7.1a - GUI for OpenVPN.
Tunnelblick is a free, open source graphic user interface for OpenVPN on OS X. It provides easy control of OpenVPN client and/or server connections. It comes as a ready-to-use application with all... Read more
Amazon Chime 4.3.5721 - Amazon-based com...
Amazon Chime is a communications service that transforms online meetings with a secure, easy-to-use application that you can trust. Amazon Chime works seamlessly across your devices so that you can... Read more
Posterino 3.3.7 - Create posters, collag...
Posterino offers enhanced customization and flexibility including a variety of new, stylish templates featuring grids of identical or odd-sized image boxes. You can customize the size and shape of... Read more
Airmail 3.2.9 - Powerful, minimal email...
Airmail is an mail client with fast performance and intuitive interaction. Support for iCloud, MS Exchange, Gmail, Google Apps, IMAP, POP3, Yahoo!, AOL, Outlook.com, Live.com. Airmail was designed... Read more
Arq 5.8.4 - Online backup to Google Driv...
Arq is super-easy online backup for Mac and Windows computers. Back up to your own cloud account (Amazon Cloud Drive, Google Drive, Dropbox, OneDrive, Google Cloud Storage, any S3-compatible server... Read more
Microsoft Remote Desktop 8.0.39 - Connec...
With Microsoft Remote Desktop, you can connect to a remote PC and your work resources from almost anywhere. Experience the power of Windows with RemoteFX in a Remote Desktop client designed to help... Read more
Arq 5.8.4 - Online backup to Google Driv...
Arq is super-easy online backup for Mac and Windows computers. Back up to your own cloud account (Amazon Cloud Drive, Google Drive, Dropbox, OneDrive, Google Cloud Storage, any S3-compatible server... Read more

Latest Forum Discussions

See All

Pokémon GO might be getting legendaries...
The long-awaited legendary Pokémon may soon be coming to Pokémon GO at long last. Data miners have already discovered that the legendary birds, Articuno, Moltres, and Zapdos are already in the game, it’s just a matter of time. [Read more] | Read more »
The best deals on the App Store this wee...
If you’ve got the Monday blues we have just the thing to cheer you up. The week is shaping up to be a spectacular one for sales. We’ve got a bunch of well-loved indie games at discounted prices this week along with a few that are a little more... | Read more »
Honor 8 Pro, a great choice for gamers
Honor is making strides to bring its brand to the forefront of mobile gaming with its latest phone, the Honor 8 Pro. The Pro sets itself apart from its predecessor, the Honor 8, with a host of premium updates that boost the device’s graphical and... | Read more »
The 4 best outdoor adventure apps
Now that we're well into the pleasant, warmer months, it's time to start making the most of the great outdoors. Spring and summer are ideal times for a bit of trekking or exploration. You don't have to go it alone, though. There are plenty of... | Read more »
Things 3 (Productivity)
Things 3 3.0.1 Device: iOS iPhone Category: Productivity Price: $7.99, Version: 3.0.1 (iTunes) Description: Meet the all-new Things! A complete rethinking of the original, award-winning task manager – with a perfect balance between... | Read more »
Oddball mash-up Arkanoid vs Space Invade...
In a move no one was really expecting, Square Enix has put forth an Arkanoid/Space Invaders mash-up aptly titled Arkanoid vs Space Invaders. The game launched today on both iOS and Android and the reviews are actually quite good. [Read more] | Read more »
Arkanoid vs Space Invaders (Games)
Arkanoid vs Space Invaders 1.0 Device: iOS Universal Category: Games Price: $3.99, Version: 1.0 (iTunes) Description: LAUNCH SALE: GET THE GAME AT 20% OFF! Two of the most iconic classic games ever made meet in Arkanoid vs Space... | Read more »
The best new games we played this week
Things got off to a bit of a slow start this week, but as we steadily creep towards Friday a bunch of great games have started cropping up. If you're looking for a quality new release to play this weekend, we've got you covered. Here's a handy... | Read more »
No Stick Shooter (Games)
No Stick Shooter 1.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0 (iTunes) Description: Happy Robot presents a fresh take on the classic retro-arcade shooters we all know and love. Featuring 30 levels of non-stop... | Read more »
Chroma Squad (Games)
Chroma Squad 1.0.85 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0.85 (iTunes) Description: | Read more »

Price Scanner via MacPrices.net

touchbyte Releases PhotoSync 3.2 for iOS With...
Hamburg, Germany based touchbyte has announced the release of PhotoSync 3.2 for iOS, a major upgrade to the versatile and powerful app to transfer, backup and share photos and videos over the air.... Read more
Emerson Adds Touchscreen Display and Apple Ho...
Emerson has announced the next evolution of its nationally recognized smart thermostat. The new Sensi Touch Wi-Fi Thermostat combines proven smarthome technology with a color touchscreen display and... Read more
SurfPro VPN for Mac Protects Data While Offer...
XwaveSoft has announced announce the release and immediate availability of SurfPro VPN 1.0, their secure VPN client for macOS. SurfPro VPN allows Mac users to protect their internet traffic from... Read more
13-inch Touch Bar MacBook Pros on sale for $1...
B&H Photo has 13″ MacBook Pros in stock today for up to $150 off MSRP. Shipping is free, and B&H charges NY & NJ sales tax only: - 13″ 2.9GHz/512GB Touch Bar MacBook Pro Space Gray (... Read more
Tuesday deal: $200 off 27-inch Apple iMacs
Amazon has select 27″ iMacs on sale for $200 off MSRP, each including free shipping: - 27″ 3.3GHz iMac 5K: $2099 $200 off MSRP - 27″ 3.2GHz/1TB Fusion iMac 5K: $1799 $200 off MSRP Keep an eye on our... Read more
Five To Six Million 10.5-inch iPad Pro Tablet...
Digitimes’ Siu Han and Joseph Tsai report that upstream supply chain shipments for Apple’s new 10.5-inch iPad Pro have been increasing, with monthly shipment volume expected to hit 600,000 units by... Read more
Georgia Tech Students Win Toyota and Net Impa...
Earlier this year, a team of students at Georgia Tech realized that there was a critical gap in transportation services for people who use wheelchairs, and wondered if the solution could be in the... Read more
13-inch 2.0GHz Space Gray MacBook Pro on sale...
Amazon has the 13″ 2.0GHz Space Gray non-Touch Bar MacBook Pro (MLL42LL/A) on sale for $1299.99 including free shipping. Their price is $200 off MSRP, and it’s currently the lowest price available... Read more
Roundup of 15-inch MacBook Pro sale prices, m...
B&H Photo has the new 2016 15″ Apple Touch Bar MacBook Pros in stock today and on sale for up to $200 off MSRP. Shipping is free, and B&H charges NY & NJ sales tax only: - 15″ 2.7GHz... Read more
15-inch 2.2GHz Retina MacBook Pro on sale for...
B&H Photo has the 2015 15″ 2.2GHz Retina MacBook Pro (MJLQ2LL/A) on sale for $1849 including free shipping plus NY & NJ sales tax only. Their price is $150 off MSRP. Read more

Jobs Board

*Apple* Media Products - Commerce Engineerin...
Apple Media Products - Commerce Engineering Manager Job Number: 57037480 Santa Clara Valley, California, United States Posted: Apr. 18, 2017 Weekly Hours: 40.00 Job Read more
Director *Apple* Platform, IS Data Manageme...
…a real difference. Come, shine with us! Astellas is announcing a Director Apple Platform, IS Data Management Lead opportunity in Northbrook, IL. Purpose & Scope: Read more
Director *Apple* ERP Integration Lead - Ast...
…make a real difference. Come, shine with us! Astellas is announcing a Director Apple ERP Integration Lead opportunity in Northbrook, IL. Purpose & Scope: This role Read more
Associate Director *Apple* Platform -- SAP...
…real difference. Come, shine with us! Astellas is announcing a Associate Director Apple Platform -- SAP Security, Risks and Controls Lead opportunity in Northbrook, Read more
Geek Squad *Apple* Master Consultation Agen...
**508241BR** **Job Title:** Geek Squad Apple Master Consultation Agent **Location Number:** 000149-Towson-Store **Job Description:** **What does a Geek Squad Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.