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

Pro Tools 2022.5 - Professional audio ed...
Pro Tools offers audio professionals superb quality and efficiency through one intuitive, integrated production environment. This high-definition system embodies the latest Digidesign innovations,... Read more
Evernote 10.38.1 - Create searchable not...
Evernote allows you to easily capture information in any environment using whatever device or platform you find most convenient, and makes this information accessible and searchable at anytime, from... Read more
calibre 5.43.0 - Complete e-book library...
Calibre is a complete e-book library manager. Organize your collection, convert your books to multiple formats, and sync with all of your devices. Let Calibre be your multi-tasking digital librarian... Read more
Mellel 5.1.2 - The word processor for sc...
Mellel is the leading word processor for OS X and has been widely considered the industry standard for long form documents since its inception. Mellel focuses on writers and scholars for technical... Read more
FileZilla 3.60.0 - 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. The FileZilla Client not only supports FTP, but also FTP over TLS... Read more
Parallels Desktop 17.1.3 - Run Windows a...
Parallels allows you to run Windows and Mac applications side by side. Choose your view to make Windows invisible while still using its applications, or keep the familiar Windows background and... Read more
iMazing 2.15.0 - Complete iOS device man...
iMazing is the world’s favourite iOS device manager for Mac and PC. Millions of users every year leverage its powerful capabilities to make the most of their personal or business iPhone and iPad.... Read more
Nitro PDF Pro 13.2.1 - Advanced PDF tool...
Nitro PDF Pro allows users to edit PDF's easily. Add text, images and signatures. Fill out PDF forms. Merge or split PDF documents. Reorder and delete pages. Create fillable forms and tables of... Read more
Nitro PDF Pro Essentials 13.2.1 - Edit a...
Nitro PDF Pro Essentials allows users to easily edit PDF's. Add text, images and signatures. Fill out PDF forms. Merge or split PDF documents. Reorder and delete pages. Even correct text and edit... Read more
Adobe InDesign 17.3 - Professional print...
InDesign is available as part of Adobe Creative Cloud for as little as $20.99/month (or $9.99/month if you're a previous InDesign customer). Adobe InDesign is part of Creative Cloud. That means you... Read more

Latest Forum Discussions

See All

Help TikTok Pool Guy, I Need You – The T...
It’s official! The video podcast is back for all you Patreon supporters. Turns out the answer was right in front of us all along: Zoom. Yes, Zoom! Duh! I don’t know why we didn’t think to try that before. Anyhoo, this week’s show is stuffed to the... | Read more »
TouchArcade Game of the Week: ‘Streets o...
It was a stacked week of great new mobile game releases, and it was a really hard week to pick just one for the Game of the Week. It seems like that’s been the case a lot lately, which just means that us mobile gamers are eating quite well as of... | Read more »
SwitchArcade Round-Up: ‘Pac-Man Museum+’...
Hello gentle readers, and welcome to the SwitchArcade Round-Up for May 27th, 2022. In today’s article, we’ve got even more new releases than yesterday to look at. Pac-Man Museum+, Kao the Kangaroo, Remote Life, and Arcade Spirits: The New... | Read more »
Steam Deck Update Reduces Fan Noise, Add...
Today, Valve pushed out another major update for SteamOS on Steam Deck. This update focuses on reducing fan noise with some useful features finally implemented. If you missed our review, see what Jared thought of it at launch here. | Read more »
Pro Darts 2022+ Is Out Now on Apple Arca...
As revealed before, Pro Darts 2022+ () from iWare Designs has gone live on Apple Arcade today as the final May 2022 addition on the service. Pro Darts 2022+ is from the developers who brought us Pro Snooker & Pool 2022+. The App Store version... | Read more »
Strategy Game ‘SD Gundam G Generation Et...
Bandai Namco Entertainment just announced a brand new Gundam strategy game titled SD Gundam G Generation Eternal. SD Gundam G Generation Eternal is a free to play game for iOS and Android that lets you collect your favorite Mobile Suits from the... | Read more »
‘Genshin Impact’ Version 2.7 Pre-Install...
Genshin Impact (Free) version 2.7 update finally releases next week across all platforms following a bit of a delay. Developer HoYoverse previously showcased Yelan in a new character trailer with details for the update being revealed a little while... | Read more »
‘Delete After Reading’ is a New Genre-Mi...
Back in October of 2020, developer Patrones & Escondites released a very unique titled called Unmemory. It’s one part interactive fiction, one part puzzle game, and multiple parts escape room or alternate reality game. Its back-of-the-box pitch... | Read more »
‘Jurassic World Primal Ops’ is a Hero Co...
Did you know that there’s a new Jurassic World movie coming out in just a couple of weeks? Chances are that the movie’s marketing machine has beaten you over the head with that information already, but did you know there’s also a Jurassic World... | Read more »
SwitchArcade Round-Up: ‘Biomotor Unitron...
Hello gentle readers, and welcome to the SwitchArcade Round-Up for May 26th, 2022. The day is Thursday, and that means we’ve got a bunch of new releases to check out. Jumping into the past, we’ve got Biomotor Unitron and Arcade Archives Flipull,... | Read more »

Price Scanner via MacPrices.net

Memorial Day Apple iPad Sale: $30 off 9th-gen...
Apple reseller Expercom is offering a $30 discount on all 9th-generation 10.2″ iPads and a $75 discount on all 11″ M1 iPad Pros through June 6th as part of their Memorial Day Sale. Prices start at $... Read more
Memorial Day Weekend Savings: MagSafe accesso...
Amazon has Apple MagSafe Chargers and Apple’s MagSafe Battery on sale for up to $20 off MSRP as part of their Memorial Day Weekend Sale sale. Shipping is free. Amazon’s sale prices are among the... Read more
Best Memorial Day Weekend MacBook Deal: Get t...
Other World Computing has Apple refurbished, factory-sealed, current-generation 13″ Space Gray M1 MacBook Pros on sale for $420-$500 off Apple’s MSRP, starting at only $879. Their prices are the... Read more
Memorial Day Weekend iPhone Sale: $250 off iP...
As part of their Memorial Day Weekend sale, Xfinity Mobile is offering any new Apple iPhone 13, or the 64GB iPhone 12, for $250 off MSRP for customers switching to Xfinity Mobile and opening a new... Read more
Memorial Day Weekend iPhone Sale: Free $300 g...
Memorial Day Weekend iPhone sales are now live at Verizon’s low-cost wireless cell service, Visible. They will include a free $300 gift card with the purchase of a new 2022 iPhone 13 Pro Max, 13 Pro... Read more
In stock today: 13″ M1 MacBook Air for $899,...
B&H has Apple’s base 13″ M1 MacBook Air (Space Gray) in stock and on sale today for $100 off MSRP, only $899. Free 1-2 day shipping is available to most addresses in the US: 8-Core M1 Apple... Read more
In stock today: Open-box 16″ MacBook Pro with...
Having trouble finding a 16″ M1 Pro MacBook Pro to buy? QuickShip Electronics has open-box return 16″ M1 Pro MacBook Pros in stock and on sale for $500 off MSRP on their eBay store right now, each... Read more
16″ MacBook Pro with Apple M1 Pro CPU in stoc...
Stock of Apple’s 16″ MacBook Pro can be hard to find at resellers today. However, Apple reseller Expercom is reporting stock of the Silver 16″ MacBook Pro with a 10-Core M1 Pro CPU and 512GB SSD... Read more
Amazon has select 13″ M1 MacBook Airs on sale...
Amazon has select Apple 13″ M1 MacBook Airs on sale for $100 off MSRP today, only $899. Amazon does not have stock of these MacBooks, but they are available for order at the discounted price. The... Read more
Deal Alert! 14″ 10-Core M1 Pro MacBook Pros a...
Amazon has 14″ MacBook Pros with a 10-Core M1 Pro CPUs on sale today for $2249.99 shipped. That’s $250 off Apple’s MSRP. Amazon’s prices are the lowest currently available for 10-Core 14″ MacBook... Read more

Jobs Board

Sr. Strategic Marketing Programs Manager - *...
The Sr. Strategic Marketing Programs Manager - Apple will be focused on helping SHI tell a compelling and exciting story around its partnership with Apple Read more
*Apple* Engineering Specialist - General Dyn...
…IT Service Delivery solutions to SEC. Currently, we are seeking an Apple Engineering Specialist in Washington, DC The responsibilities for candidates in this Read more
*Apple* Engineering Specialist - General Dyn...
…IT Service Delivery solutions to SEC. Currently, we are seeking an Apple Engineering Specialist in Washington, DC The responsibilities for candidates in this Read more
Sephora Beauty Advisor - *Apple* Blossom Ma...
Sephora Beauty Advisor - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Read more
Omnichannel Associate - *Apple* Blossom Mal...
Omnichannel Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.